import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; import { mkdtemp, rm, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import os from 'node:os'; const exec = promisify(execFile); const SCRIPT = 'scripts/validate-assets.mjs'; describe('PIPE-03 / AEST-09: asset provenance gate', () => { it('exits 0 against the real /assets/ tree (refused sample excluded)', async () => { const result = await exec('node', [SCRIPT]); expect(result.stdout).toMatch(/all \d+ assets carry valid provenance/); }); describe('with an isolated tmpdir fixture missing provenance', () => { let tmpDir: string; let fixtureFile: string; beforeAll(async () => { // Per-test-run unique tmpdir under os.tmpdir() — isolated from /assets/, // no risk of polluting the real tree even if the runner is killed mid-test. tmpDir = await mkdtemp(join(os.tmpdir(), 'tlg-provenance-test-')); fixtureFile = join(tmpDir, 'orphan.png'); // Tiny 1x1 PNG with no sidecar const png = Buffer.from( '89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000d49444154789c63600100000005000146cd9c5d0000000049454e44ae426082', 'hex', ); await writeFile(fixtureFile, png); }); afterAll(async () => { await rm(tmpDir, { recursive: true, force: true }); }); it('exits non-zero with a clear error message when ASSETS_DIR points at the fixture', async () => { // Run the validator against the isolated tmpdir; the script reads ASSETS_DIR // from process.env, so the orphan.png is the only file under inspection. let exitCode = 0; let combinedOutput = ''; try { await exec('node', [SCRIPT], { env: { ...process.env, ASSETS_DIR: tmpDir } }); } catch (err: any) { exitCode = err.code ?? -1; combinedOutput = (err.stdout ?? '') + (err.stderr ?? ''); } expect(exitCode).toBe(1); expect(combinedOutput).toMatch(/validation failed/); expect(combinedOutput).toMatch(/orphan\.png/); expect(combinedOutput).toMatch(/missing.*provenance sidecar/i); // Sanity check: silence the unused-var lint by referencing fixtureFile. expect(fixtureFile).toContain('orphan.png'); }); }); });