assets: add approved portfolio evidence media

This commit is contained in:
2026-09-04 23:07:00 +03:00
parent 5bdeeaa433
commit c60477a475
11 changed files with 235 additions and 54 deletions

View File

@@ -1,49 +1,13 @@
{ {
"assets": [ "assets": [
{ {
"id": "soundtrack-intro-opus", "id": "soundtrack-afterglow-mp3",
"fileName": "nightdrive-intro.opus", "fileName": "nightdrive-afterglow.mp3",
"sha256": "561c05cea71d0920ec323375644039007b91b0a4c346dc663e233ad42d6ab490", "sha256": "685687ad131d61c34e42bcee29af16a4c8180d788c67d75f2331fa9082a3a44e",
"mediaType": "audio/ogg",
"width": null,
"height": null,
"durationMs": 56064,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "soundtrack-intro-mp3",
"fileName": "nightdrive-intro.mp3",
"sha256": "008794ebd7f545c32f19aab4ada6aba40d9fc3341830a66e77f21d87a41c009b",
"mediaType": "audio/mpeg", "mediaType": "audio/mpeg",
"width": null, "width": null,
"height": null, "height": null,
"durationMs": 56064, "durationMs": 25116,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "soundtrack-main-opus",
"fileName": "nightdrive-main.opus",
"sha256": "81933fc8e589428ef07fb265572a79975f183848b6a23616cb289e33fe3fb88c",
"mediaType": "audio/ogg",
"width": null,
"height": null,
"durationMs": 178605,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "soundtrack-main-mp3",
"fileName": "nightdrive-main.mp3",
"sha256": "796de8247c4cb8012d7c6883b534112ac09a40255a2c33cd68acf0f87c066659",
"mediaType": "audio/mpeg",
"width": null,
"height": null,
"durationMs": 178605,
"rightsHolder": "Luca Pîslaru", "rightsHolder": "Luca Pîslaru",
"license": "All rights reserved", "license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5" "attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
@@ -61,13 +25,13 @@
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5" "attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
}, },
{ {
"id": "soundtrack-afterglow-mp3", "id": "soundtrack-drive-lift-mp3",
"fileName": "nightdrive-afterglow.mp3", "fileName": "nightdrive-drive-lift.mp3",
"sha256": "685687ad131d61c34e42bcee29af16a4c8180d788c67d75f2331fa9082a3a44e", "sha256": "edcb802938d3d1e53392f9ccd2e153f72a24b494c205ce6f556d73de5fe709ec",
"mediaType": "audio/mpeg", "mediaType": "audio/mpeg",
"width": null, "width": null,
"height": null, "height": null,
"durationMs": 25116, "durationMs": 11163,
"rightsHolder": "Luca Pîslaru", "rightsHolder": "Luca Pîslaru",
"license": "All rights reserved", "license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5" "attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
@@ -85,16 +49,136 @@
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5" "attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
}, },
{ {
"id": "soundtrack-drive-lift-mp3", "id": "soundtrack-intro-mp3",
"fileName": "nightdrive-drive-lift.mp3", "fileName": "nightdrive-intro.mp3",
"sha256": "edcb802938d3d1e53392f9ccd2e153f72a24b494c205ce6f556d73de5fe709ec", "sha256": "008794ebd7f545c32f19aab4ada6aba40d9fc3341830a66e77f21d87a41c009b",
"mediaType": "audio/mpeg", "mediaType": "audio/mpeg",
"width": null, "width": null,
"height": null, "height": null,
"durationMs": 11163, "durationMs": 56064,
"rightsHolder": "Luca Pîslaru", "rightsHolder": "Luca Pîslaru",
"license": "All rights reserved", "license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5" "attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "soundtrack-intro-opus",
"fileName": "nightdrive-intro.opus",
"sha256": "561c05cea71d0920ec323375644039007b91b0a4c346dc663e233ad42d6ab490",
"mediaType": "audio/ogg",
"width": null,
"height": null,
"durationMs": 56064,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "soundtrack-main-mp3",
"fileName": "nightdrive-main.mp3",
"sha256": "796de8247c4cb8012d7c6883b534112ac09a40255a2c33cd68acf0f87c066659",
"mediaType": "audio/mpeg",
"width": null,
"height": null,
"durationMs": 178605,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "soundtrack-main-opus",
"fileName": "nightdrive-main.opus",
"sha256": "81933fc8e589428ef07fb265572a79975f183848b6a23616cb289e33fe3fb88c",
"mediaType": "audio/ogg",
"width": null,
"height": null,
"durationMs": 178605,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Original AI-assisted soundtrack produced by Luca Pîslaru with ACE-Step 1.5"
},
{
"id": "currency-converter-interface",
"fileName": "project-currency-converter.webp",
"sha256": "57159ae72a075ba5317217233c3c0eb210a485c51b5f2c37b5ed156d5ea37efb",
"mediaType": "image/webp",
"width": 1440,
"height": 820,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
},
{
"id": "medication-mobile-data-settings",
"fileName": "project-medication-data-settings.webp",
"sha256": "d951dd723047b737ab6a7da46b82f3f3f3aca7ec8853314f74ac57e1950ce1ba",
"mediaType": "image/webp",
"width": 720,
"height": 1280,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
},
{
"id": "medication-mobile-logs",
"fileName": "project-medication-logs.webp",
"sha256": "d34b2d41855e6dca4762fb9fc7728b64a94fef60de36149e465ce50821bc1dc7",
"mediaType": "image/webp",
"width": 720,
"height": 1280,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
},
{
"id": "medication-mobile-notification-settings",
"fileName": "project-medication-notification-settings.webp",
"sha256": "d2fe0076d6581e76c361cb656350c58f6685f6fe91c5b6c5871e60977e8d5be7",
"mediaType": "image/webp",
"width": 720,
"height": 1280,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
},
{
"id": "opinion-final-distribution-chart",
"fileName": "project-opinion-final-distribution.webp",
"sha256": "2f2f6d64b8bb4f79ecbce1a8bc486cf7bbdf4087eb4f10062a6fe889246dbdf1",
"mediaType": "image/webp",
"width": 571,
"height": 455,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
},
{
"id": "opinion-polarization-chart",
"fileName": "project-opinion-polarization.webp",
"sha256": "77f0d5076769e6e45b566c5f322d8f535686f9e9f928e18fe4c16b3dac989c43",
"mediaType": "image/webp",
"width": 584,
"height": 455,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
},
{
"id": "social-preview-nightdrive",
"fileName": "project-social-preview.webp",
"sha256": "ed470760643ef3d413b6ca4a0e1434771fcc9b61b6ac34011feae77a13f2daca",
"mediaType": "image/webp",
"width": 1200,
"height": 630,
"durationMs": null,
"rightsHolder": "Luca Pîslaru",
"license": "All rights reserved",
"attribution": "Luca Pîslaru"
} }
] ]
} }

View File

@@ -4,13 +4,9 @@
{ "id": "medication-mobile-logs", "kind": "image", "output": "project-medication-logs.webp", "maxWidth": 720, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" }, { "id": "medication-mobile-logs", "kind": "image", "output": "project-medication-logs.webp", "maxWidth": 720, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "medication-mobile-data-settings", "kind": "image", "output": "project-medication-data-settings.webp", "maxWidth": 720, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" }, { "id": "medication-mobile-data-settings", "kind": "image", "output": "project-medication-data-settings.webp", "maxWidth": 720, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "medication-mobile-notification-settings", "kind": "image", "output": "project-medication-notification-settings.webp", "maxWidth": 720, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" }, { "id": "medication-mobile-notification-settings", "kind": "image", "output": "project-medication-notification-settings.webp", "maxWidth": 720, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "footy-detection-frame", "kind": "image", "output": "project-footy-detection.webp", "maxWidth": 1600, "rightsHolder": "Third-party footage and Luca Pîslaru", "license": "Publication requires confirmation", "attribution": "Detection overlay by Luca Pîslaru" },
{ "id": "opinion-polarization-chart", "kind": "image", "output": "project-opinion-polarization.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" }, { "id": "opinion-polarization-chart", "kind": "image", "output": "project-opinion-polarization.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "opinion-cascade-thresholds-chart", "kind": "image", "output": "project-opinion-cascade-thresholds.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "opinion-average-degree-chart", "kind": "image", "output": "project-opinion-average-degree.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "opinion-revolt-frequency-chart", "kind": "image", "output": "project-opinion-revolt-frequency.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "opinion-final-distribution-chart", "kind": "image", "output": "project-opinion-final-distribution.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" }, { "id": "opinion-final-distribution-chart", "kind": "image", "output": "project-opinion-final-distribution.webp", "maxWidth": 1000, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "private-game-loop", "kind": "video", "output": "project-private-game-loop.webm", "maxWidth": 1280, "startSeconds": 3, "durationSeconds": 5, "rightsHolder": "Rights holder confirmation pending", "license": "Publication requires confirmation", "attribution": "Prototype contribution by Luca Pîslaru" }, { "id": "currency-converter-interface", "kind": "image", "output": "project-currency-converter.webp", "maxWidth": 1440, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" },
{ "id": "currency-converter-interface", "kind": "image", "output": "project-currency-converter.webp", "maxWidth": 1440, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" } { "id": "social-preview-nightdrive", "kind": "image", "output": "project-social-preview.webp", "maxWidth": 1200, "rightsHolder": "Luca Pîslaru", "license": "All rights reserved", "attribution": "Luca Pîslaru" }
] ]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env node
import { mkdir, realpath } from 'node:fs/promises';
import { dirname, resolve, sep } from 'node:path';
import { fileURLToPath } from 'node:url';
import sharp from 'sharp';
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const permittedPrivateRoot = resolve(repositoryRoot, 'content/private');
const fail = () => {
throw new Error('SOCIAL-PREVIEW-PATH-001');
};
const canonicalizeForWrite = async (path) => {
const absolute = resolve(path);
let cursor = dirname(absolute);
const suffix = [];
while (true) {
try {
return resolve(await realpath(cursor), ...suffix, absolute.slice(dirname(absolute).length + 1));
} catch (error) {
if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT')) fail();
const parent = dirname(cursor);
if (parent === cursor) fail();
suffix.unshift(cursor.slice(parent.length + 1));
cursor = parent;
}
}
};
const isInside = (path, root) => path === root || path.startsWith(`${root}${sep}`);
export const generateSocialPreview = async (outputPath) => {
if (typeof outputPath !== 'string' || outputPath.trim() === '') fail();
const output = await canonicalizeForWrite(outputPath);
const privateRoot = await canonicalizeForWrite(permittedPrivateRoot);
if (!isInside(output, privateRoot) && !isInside(output, '/tmp')) fail();
const svg = Buffer.from(`
<svg width="1200" height="630" viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
<rect width="1200" height="630" fill="#070910"/>
<rect y="356" width="1200" height="274" fill="#0b1019"/>
<path d="M0 356H1200" stroke="#1b3246" stroke-width="2"/>
<circle cx="880" cy="174" r="78" fill="#152638"/>
<path d="M474 630L586 356H642L780 630Z" fill="#101b28"/>
<path d="M544 630L606 356" stroke="#35c8d0" stroke-width="7" opacity="0.9"/>
<path d="M701 630L623 356" stroke="#e3a44a" stroke-width="7" opacity="0.88"/>
<path d="M602 566L613 522M614 490L619 458M620 430L623 405" stroke="#dfe9ef" stroke-width="5" stroke-linecap="round" opacity="0.72"/>
<text x="92" y="183" font-family="DejaVu Sans, sans-serif" font-size="66" font-weight="700" fill="#f1f5f7">Luca Pîslaru</text>
<text x="96" y="245" font-family="DejaVu Sans, sans-serif" font-size="29" font-weight="500" letter-spacing="0.6" fill="#9fc8d1">System Administrator &amp; Full-Stack Developer</text>
<path d="M96 286H342" stroke="#35c8d0" stroke-width="4"/>
<path d="M350 286H430" stroke="#e3a44a" stroke-width="4"/>
</svg>
`);
await mkdir(dirname(output), { recursive: true });
await sharp(svg, { density: 72 })
.flatten({ background: '#070910' })
.png({ compressionLevel: 9, adaptiveFiltering: false, palette: false })
.toFile(output);
return output;
};
const parseOutput = (argv) => {
if (argv.length !== 2 || argv[0] !== '--output') fail();
return argv[1];
};
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
generateSocialPreview(parseOutput(process.argv.slice(2))).catch((error) => {
process.stderr.write(`${error instanceof Error ? error.message : 'SOCIAL-PREVIEW-001'}\n`);
process.exitCode = 1;
});
}

View File

@@ -16,6 +16,8 @@ import { scanImage, scanText } from '../../scripts/lib/privacy-scan.mjs';
import { mergeAssetRecords } from '../../scripts/lib/merge-assets.mjs'; import { mergeAssetRecords } from '../../scripts/lib/merge-assets.mjs';
// @ts-expect-error The production script is native ESM and intentionally has no TypeScript runtime wrapper. // @ts-expect-error The production script is native ESM and intentionally has no TypeScript runtime wrapper.
import { prepareAssets, publishPreparedAssets, verifyPreparedAssets } from '../../scripts/prepare-assets.mjs'; import { prepareAssets, publishPreparedAssets, verifyPreparedAssets } from '../../scripts/prepare-assets.mjs';
// @ts-expect-error The production script is native ESM and intentionally has no TypeScript runtime wrapper.
import { generateSocialPreview } from '../../scripts/generate-social-preview.mjs';
const execFileAsync = promisify(execFile); const execFileAsync = promisify(execFile);
interface Candidate { id: string; fileName: string; sha256: string; } interface Candidate { id: string; fileName: string; sha256: string; }
@@ -293,6 +295,31 @@ describe('prepared candidate publication', () => {
}); });
describe('deterministic asset preparation', () => { describe('deterministic asset preparation', () => {
it('renders the deterministic social preview at 1200×630 as opaque privacy-safe pixels', async () => {
const root = await createRoot();
const firstPath = join(root, 'social-preview-one.png');
const secondPath = join(root, 'social-preview-two.png');
await generateSocialPreview(firstPath);
await generateSocialPreview(secondPath);
const metadata = await sharp(firstPath).metadata();
const stats = await sharp(firstPath).stats();
expect(metadata.width).toBe(1200);
expect(metadata.height).toBe(630);
expect(stats.isOpaque).toBe(true);
expect(await hashFile(secondPath)).toBe(await hashFile(firstPath));
await expect(scanImage(firstPath, [
'private canary identity',
'private canary domain',
'private canary medication',
], { runOcr: true })).resolves.toMatchObject({ width: 1200, height: 630 });
}, 30_000);
it('rejects social-preview output paths outside private or temporary storage', async () => {
await expect(generateSocialPreview(join(process.cwd(), 'public', 'unsafe.png')))
.rejects.toThrow(/SOCIAL-PREVIEW-PATH-001/u);
});
it('re-encodes images without metadata under generated safe filenames, identically across runs', async () => { it('re-encodes images without metadata under generated safe filenames, identically across runs', async () => {
const root = await createRoot(); const root = await createRoot();
const inputs = await makeInputs(root, baseRecipe()); const inputs = await makeInputs(root, baseRecipe());