import { createHash, generateKeyPairSync, sign } from "node:crypto"; import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { providerEvidenceSignaturePayload } from "./lib/provider-evidence.ts"; import { verifyPromotionInputs } from "./lib/promotion-verifier.ts"; import { createReleaseCandidateManifest, RELEASE_CANDIDATE_EVIDENCE_PATHS, RELEASE_CANDIDATE_MANIFEST_PATH, releaseCandidateManifestSchema, } from "./lib/release-candidate.ts"; const fixtureRoot = await mkdtemp( path.join(tmpdir(), "supply-chain-provider-fixture-"), ); try { const repositoryRoot = process.cwd(); const actualCandidate = releaseCandidateManifestSchema.parse( JSON.parse( await readFile( path.join(repositoryRoot, RELEASE_CANDIDATE_MANIFEST_PATH), "utf8", ), ) as unknown, ); const actualProviderEnvironment = absoluteProviderEnvironment( fixtureRoot, await writeProviderEnvironment( fixtureRoot, "actual", actualCandidate.distSha256, actualCandidate.lockfileSha256, ), ); const actualDefaultVerifier = await verifyPromotionInputs({ artifactType: "provider-verification", environment: actualProviderEnvironment, }); const rawLockfile = "lockfileVersion: '9.0'\n"; const lockfileSha256 = createHash("sha256") .update(rawLockfile) .digest("hex"); await mkdir(path.join(fixtureRoot, "dist"), { recursive: true }); await writeFile(path.join(fixtureRoot, "dist/app.js"), "immutable\n"); await writeFile(path.join(fixtureRoot, "pnpm-lock.yaml"), rawLockfile); for (const file of RELEASE_CANDIDATE_EVIDENCE_PATHS) { if (file === "pnpm-lock.yaml") continue; await mkdir(path.dirname(path.join(fixtureRoot, file)), { recursive: true, }); const value = file === "artifacts/release/dependency-inventory.json" ? { lockfileSha256 } : { fixture: file }; await writeFile( path.join(fixtureRoot, file), `${JSON.stringify(value)}\n`, ); } const candidate = await createReleaseCandidateManifest(fixtureRoot); await writeFile( path.join(fixtureRoot, RELEASE_CANDIDATE_MANIFEST_PATH), `${JSON.stringify(candidate)}\n`, ); const validEnvironment = await writeProviderEnvironment( fixtureRoot, "valid", candidate.distSha256, candidate.lockfileSha256, ); const wrongEnvironment = await writeProviderEnvironment( fixtureRoot, "wrong", "3".repeat(64), candidate.lockfileSha256, ); const acceptLocalEvidence = async () => ({ status: "PASS" as const, failures: [] as const, }); const fixtures = { absent: await verifyPromotionInputs({ artifactType: "provider-verification", repositoryRoot: fixtureRoot, environment: {}, verifyLocalEvidence: acceptLocalEvidence, }), validImmutable: await verifyPromotionInputs({ artifactType: "provider-verification", repositoryRoot: fixtureRoot, environment: validEnvironment, verifyLocalEvidence: acceptLocalEvidence, }), wrongDigest: await verifyPromotionInputs({ artifactType: "provider-verification", repositoryRoot: fixtureRoot, environment: wrongEnvironment, verifyLocalEvidence: acceptLocalEvidence, }), postAttestationMutation: null as Awaited< ReturnType > | null, }; await writeFile(path.join(fixtureRoot, "dist/app.js"), "mutated\n"); fixtures.postAttestationMutation = await verifyPromotionInputs({ artifactType: "provider-verification", repositoryRoot: fixtureRoot, environment: validEnvironment, verifyLocalEvidence: acceptLocalEvidence, }); const passed = actualDefaultVerifier.status === "PASS" && fixtures.validImmutable.status === "PASS" && fixtures.absent.status === "FAIL_UNVERIFIED" && fixtures.wrongDigest.status === "FAIL_UNVERIFIED" && fixtures.postAttestationMutation.status === "FAIL_UNVERIFIED"; await mkdir("artifacts/security", { recursive: true }); await writeFile( "artifacts/security/supply-chain-provider-fixtures.json", `${JSON.stringify( { schemaVersion: 1, actualDefaultVerifier: { status: actualDefaultVerifier.status, failures: actualDefaultVerifier.failures, }, fixtures: Object.fromEntries( Object.entries(fixtures).map(([name, result]) => [ name, { status: result?.status, failures: result?.failures }, ]), ), passingFixtureCount: Object.values(fixtures).filter( (result) => result?.status === "PASS", ).length, status: passed ? "PASS" : "FAIL", }, null, 2, )}\n`, ); if (!passed) { process.stderr.write( "Supply-chain provider fixtures failed closed incorrectly\n", ); process.exitCode = 1; } else { process.stdout.write( "Supply-chain provider fixtures: actual default verifier and valid immutable fixture PASS\n", ); } } finally { await rm(fixtureRoot, { recursive: true, force: true }); } function absoluteProviderEnvironment( repositoryRoot: string, environment: NodeJS.ProcessEnv, ): NodeJS.ProcessEnv { const absolute = { ...environment }; for (const key of [ "CANDIDATE_ARCHIVE_PATH", "VULNERABILITY_REPORT_PATH", "PROVENANCE_ATTESTATION_PATH", "VULNERABILITY_PUBLIC_KEY_PATH", "PROVENANCE_PUBLIC_KEY_PATH", ] as const) { const value = absolute[key]; if (value) absolute[key] = path.join(repositoryRoot, value); } return absolute; } async function writeProviderEnvironment( repositoryRoot: string, name: string, distDigest: string, lockfileSha256: string, ): Promise { const vulnerabilityKeys = generateKeyPairSync("ed25519"); const provenanceKeys = generateKeyPairSync("ed25519"); const directory = `provider/${name}`; await mkdir(path.join(repositoryRoot, directory), { recursive: true }); const vulnerability = signedEvidence( { schemaVersion: 1, provider: "fixture-vulnerability-provider", generatedAt: "2026-08-01T00:00:00.000Z", scannedLockfileSha256: lockfileSha256, scannedDistSha256: distDigest, findings: [], }, "fixture-vulnerability-key", vulnerabilityKeys.privateKey, ); const provenance = signedEvidence( { schemaVersion: 1, provider: "fixture-provenance-provider", signer: "fixture-workload-identity", generatedAt: "2026-08-01T00:00:00.000Z", subject: { name: "dist", digest: { sha256: distDigest } }, }, "fixture-provenance-key", provenanceKeys.privateKey, ); await Promise.all([ writeFile( path.join(repositoryRoot, directory, "candidate.tar.gz"), "fixture archive\n", ), writeFile( path.join(repositoryRoot, directory, "vulnerability.json"), `${JSON.stringify(vulnerability)}\n`, ), writeFile( path.join(repositoryRoot, directory, "provenance.json"), `${JSON.stringify(provenance)}\n`, ), writeFile( path.join(repositoryRoot, directory, "vulnerability.pem"), vulnerabilityKeys.publicKey .export({ type: "spki", format: "pem" }) .toString(), ), writeFile( path.join(repositoryRoot, directory, "provenance.pem"), provenanceKeys.publicKey .export({ type: "spki", format: "pem" }) .toString(), ), ]); return { CANDIDATE_ARCHIVE_PATH: `${directory}/candidate.tar.gz`, CANDIDATE_ARCHIVE_SHA256: createHash("sha256") .update("fixture archive\n") .digest("hex"), VULNERABILITY_REPORT_PATH: `${directory}/vulnerability.json`, PROVENANCE_ATTESTATION_PATH: `${directory}/provenance.json`, VULNERABILITY_PUBLIC_KEY_PATH: `${directory}/vulnerability.pem`, VULNERABILITY_KEY_ID: "fixture-vulnerability-key", PROVENANCE_PUBLIC_KEY_PATH: `${directory}/provenance.pem`, PROVENANCE_KEY_ID: "fixture-provenance-key", }; } function signedEvidence( value: Record, keyId: string, privateKey: ReturnType["privateKey"], ) { return { ...value, signature: { algorithm: "Ed25519", keyId, value: sign( null, providerEvidenceSignaturePayload(value), privateKey, ).toString("base64"), }, }; }