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

@@ -16,6 +16,8 @@ import { scanImage, scanText } from '../../scripts/lib/privacy-scan.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.
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);
interface Candidate { id: string; fileName: string; sha256: string; }
@@ -293,6 +295,31 @@ describe('prepared candidate publication', () => {
});
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 () => {
const root = await createRoot();
const inputs = await makeInputs(root, baseRecipe());