import { spawnSync } from "node:child_process"; import { createHash, generateKeyPairSync, sign, type KeyObject, } from "node:crypto"; import { cp, mkdir, mkdtemp, readFile, readdir, rm, writeFile, } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { localEvidenceAssessmentArtifactSchema, supplyChainProviderFixturesArtifactSchema, } from "./contracts/release-artifacts.ts"; import { PROMOTED_FILE_NAMES } from "./contracts/promotion-artifacts.ts"; import { captureCiCandidateArchive, } from "./lib/ci-candidate-archive.ts"; import { cleanupFinalizedPromotion, finalizeVerifiedPromotion, } from "./lib/promotion-stager.ts"; import { verifyExactPromotionBundle } from "./lib/exact-promotion-bundle.ts"; import { providerEvidenceSignaturePayload, providerPublicKeyFingerprint, } from "./lib/provider-evidence.ts"; import { LOCAL_EVIDENCE_ASSESSMENT_PATH, RELEASE_CANDIDATE_EVIDENCE_PATHS, RELEASE_CANDIDATE_MANIFEST_PATH, releaseCandidateManifestSchema, } from "./lib/release-candidate.ts"; import { writeValidatedJsonArtifact } from "./lib/validated-json-artifact.ts"; import { linkFixtureNodeModules } from "./lib/fixture-node-modules.ts"; const repositoryRoot = process.cwd(); const fixtureRoot = await mkdtemp(path.join(tmpdir(), "provider-exact-five-fixture-")); try { await cp(repositoryRoot, fixtureRoot, { recursive: true, filter: (source) => { const relative = path.relative(repositoryRoot, source); if (!relative) return true; const first = relative.split(path.sep)[0]; return ![".release", "artifacts", "dist", "node_modules"].includes(first ?? ""); }, }); await cp(path.join(repositoryRoot, "artifacts"), path.join(fixtureRoot, "artifacts"), { recursive: true, }); await rm(path.join(fixtureRoot, "artifacts/release"), { recursive: true, force: true }); await linkFixtureNodeModules(fixtureRoot, repositoryRoot); const git = spawnSync("git", ["show", "-s", "--format=%H%n%ct", "HEAD"], { cwd: repositoryRoot, encoding: "utf8", }); if (git.status !== 0) throw new Error(`provider fixture git identity failed: ${git.stderr}`); const [revision, sourceDateEpoch] = git.stdout.trim().split(/\r?\n/u); if (!revision || !sourceDateEpoch) throw new Error("provider fixture git identity is incomplete"); const build = spawnSync("corepack", ["pnpm", "build:release-candidate"], { cwd: fixtureRoot, encoding: "utf8", timeout: 120_000, maxBuffer: 32 * 1024 * 1024, env: { ...process.env, CI: "true", VITE_BUILD_ID: "provider-exact-five-fixture", VITE_COMMIT_SHA: revision, RELEASE_ID: "provider-exact-five-fixture", SOURCE_DATE_EPOCH: sourceDateEpoch, CI_RUNNER_IMAGE: `fixture@sha256:${"a".repeat(64)}`, }, }); if (build.status !== 0) throw new Error(`${build.stdout}\n${build.stderr}`); const manifest = releaseCandidateManifestSchema.parse( JSON.parse( await readFile(path.join(fixtureRoot, RELEASE_CANDIDATE_MANIFEST_PATH), "utf8"), ) as unknown, ); const assessment = localEvidenceAssessmentArtifactSchema.parse( JSON.parse( await readFile(path.join(fixtureRoot, LOCAL_EVIDENCE_ASSESSMENT_PATH), "utf8"), ) as unknown, ); const archivePath = path.join(fixtureRoot, "candidate.tar.gz"); const tar = spawnSync( "/usr/bin/tar", [ "--sort=name", "--mtime=@0", "--owner=0", "--group=0", "--numeric-owner", "-czf", archivePath, "dist", ...RELEASE_CANDIDATE_EVIDENCE_PATHS, RELEASE_CANDIDATE_MANIFEST_PATH, ], { cwd: fixtureRoot, encoding: "utf8" }, ); if (tar.status !== 0) throw new Error(`provider fixture real tar failed: ${tar.stderr}`); const archiveBytes = await readFile(archivePath); const archiveSha256 = sha256(archiveBytes); const now = Date.parse("2026-08-02T01:00:00.000Z"); const vulnerabilityKeys = generateKeyPairSync("ed25519"); const provenanceKeys = generateKeyPairSync("ed25519"); const vulnerabilityKeyId = "fixture-vulnerability-key"; const provenanceKeyId = "fixture-provenance-key"; const vulnerabilityNonce = "1".repeat(64); const provenanceNonce = "2".repeat(64); const context = { run: { id: "fixture-run", attempt: 1 }, source: { revision: assessment.source.revision, sourceSetSha256: assessment.source.sourceSetSha256, }, candidate: { archiveSha256, bundleSha256: manifest.bundleSha256, distSha256: manifest.distSha256, lockfileSha256: manifest.lockfileSha256, }, } as const; const vulnerability = signedEvidence( { schemaVersion: 2, evidenceType: "vulnerability-report", provider: "fixture-vulnerability-provider", issuedAt: new Date(now).toISOString(), expiresAt: new Date(now + 60 * 60 * 1_000).toISOString(), run: { ...context.run, invocationNonce: vulnerabilityNonce }, source: context.source, candidate: context.candidate, secretScanAttestation: { status: "PASS", localEvidenceAssessmentSha256: sha256( await readFile(path.join(fixtureRoot, LOCAL_EVIDENCE_ASSESSMENT_PATH)), ), sourceSetSha256: assessment.source.sourceSetSha256, policySha256: assessment.secretScan.policySha256, sarifSha256: assessment.secretScan.sarifSha256, scanInputSha256: assessment.secretScan.scanInputSha256, }, findings: [], }, vulnerabilityKeyId, vulnerabilityKeys.publicKey, vulnerabilityKeys.privateKey, ); const provenance = signedEvidence( { schemaVersion: 2, evidenceType: "provenance-attestation", provider: "fixture-provenance-provider", signer: "fixture-workload-identity", issuedAt: new Date(now).toISOString(), expiresAt: new Date(now + 60 * 60 * 1_000).toISOString(), run: { ...context.run, invocationNonce: provenanceNonce }, source: context.source, candidate: context.candidate, subject: { name: "dist", digest: { sha256: manifest.distSha256 } }, }, provenanceKeyId, provenanceKeys.publicKey, provenanceKeys.privateKey, ); await Promise.all([ write(fixtureRoot, "provider/vulnerability.json", `${JSON.stringify(vulnerability)}\n`), write(fixtureRoot, "provider/provenance.json", `${JSON.stringify(provenance)}\n`), write( fixtureRoot, "provider/vulnerability.pem", vulnerabilityKeys.publicKey.export({ type: "spki", format: "pem" }), ), write( fixtureRoot, "provider/provenance.pem", provenanceKeys.publicKey.export({ type: "spki", format: "pem" }), ), ]); const runnerTempRoot = path.join(fixtureRoot, "runner-temp"); await mkdir(runnerTempRoot, { mode: 0o700 }); const finalized = await finalizeVerifiedPromotion( { repositoryRoot: fixtureRoot, archivePath, expectedArchiveSha256: archiveSha256, vulnerabilityReportPath: "provider/vulnerability.json", provenanceAttestationPath: "provider/provenance.json", vulnerabilityPublicKeyPath: "provider/vulnerability.pem", vulnerabilityKeyId, provenancePublicKeyPath: "provider/provenance.pem", provenanceKeyId, expectedRun: { id: context.run.id, attempt: 1, sourceRevision: revision }, vulnerabilityInvocationNonce: vulnerabilityNonce, provenanceInvocationNonce: provenanceNonce, runnerTempRoot, }, { nowEpochMs: () => now, randomBytes: (bytes) => Buffer.alloc(bytes, 0x4a), afterCapture: async () => { await writeFile(path.join(fixtureRoot, "dist/index.html"), "contradictory external tree\n"); }, }, ); const validImmutable = finalized.files.length === 5 && (await readdir(finalized.stagingRoot)).length === 5; const exactFiles = Object.fromEntries( await Promise.all( PROMOTED_FILE_NAMES.map(async (name) => [ name, await readFile(path.join(finalized.stagingRoot, name)), ] as const), ), ); const bundleTrust = { vulnerabilityTrust: { keyId: vulnerabilityKeyId, publicKey: vulnerabilityKeys.publicKey, publicKeyFingerprint: providerPublicKeyFingerprint(vulnerabilityKeys.publicKey), }, provenanceTrust: { keyId: provenanceKeyId, publicKey: provenanceKeys.publicKey, publicKeyFingerprint: providerPublicKeyFingerprint(provenanceKeys.publicKey), }, expected: { run: context.run, sourceRevision: context.source.revision, sourceSetSha256: context.source.sourceSetSha256, archiveSha256: context.candidate.archiveSha256, bundleSha256: context.candidate.bundleSha256, distSha256: context.candidate.distSha256, lockfileSha256: context.candidate.lockfileSha256, }, nowEpochMs: () => now, } as const; const absentFiles = { ...exactFiles } as Partial; delete absentFiles["provider-verification.json"]; const absent = await captureRejection(async () => { await verifyExactPromotionBundle(absentFiles, bundleTrust); }); const invalidPath = path.join(fixtureRoot, "invalid.tar.gz"); const invalidBytes = Buffer.from("arbitrary non-tar bytes\n"); await writeFile(invalidPath, invalidBytes); const invalidTar = await captureRejection(async () => { await finalizeVerifiedPromotion( { repositoryRoot: fixtureRoot, archivePath: invalidPath, expectedArchiveSha256: sha256(invalidBytes), vulnerabilityReportPath: "provider/vulnerability.json", provenanceAttestationPath: "provider/provenance.json", vulnerabilityPublicKeyPath: "provider/vulnerability.pem", vulnerabilityKeyId, provenancePublicKeyPath: "provider/provenance.pem", provenanceKeyId, expectedRun: { id: context.run.id, attempt: 1, sourceRevision: revision }, vulnerabilityInvocationNonce: vulnerabilityNonce, provenanceInvocationNonce: provenanceNonce, runnerTempRoot, }, { nowEpochMs: () => now }, ); }); const wrongDigest = await captureRejection(async () => { await captureCiCandidateArchive({ archivePath, expectedSha256: "0".repeat(64) }); }); const passed = validImmutable && absent.rejected && invalidTar.rejected && wrongDigest.rejected; await cleanupFinalizedPromotion({ runnerTempRoot, stagingRoot: finalized.stagingRoot, cleanupToken: finalized.cleanupToken, runnerTempIdentity: finalized.runnerTempIdentity, stagingIdentity: finalized.stagingIdentity, }); await mkdir(path.join(repositoryRoot, "artifacts/security"), { recursive: true }); await writeValidatedJsonArtifact({ path: path.join(repositoryRoot, "artifacts/security/supply-chain-provider-fixtures.json"), schema: supplyChainProviderFixturesArtifactSchema, value: { schemaVersion: 1, actualDefaultVerifier: { status: validImmutable ? "PASS" : "FAIL_UNVERIFIED", failures: validImmutable ? [] : ["canonical exact-five finalizer failed"], }, fixtures: { absent: { status: absent.rejected ? "FAIL_UNVERIFIED" : "PASS", failures: [absent.failure], }, validImmutable: { status: validImmutable ? "PASS" : "FAIL_UNVERIFIED", failures: [] }, wrongDigest: { status: wrongDigest.rejected ? "FAIL_UNVERIFIED" : "PASS", failures: [wrongDigest.failure], }, invalidTar: { status: invalidTar.rejected ? "FAIL_UNVERIFIED" : "PASS", failures: [invalidTar.failure], }, }, externalTreeCanary: { status: validImmutable ? "PASS" : "FAIL_UNVERIFIED", failures: validImmutable ? [] : ["external tree canary influenced captured archive"], }, passingFixtureCount: validImmutable ? 1 : 0, status: passed ? "PASS" : "FAIL", }, }); if (!passed) throw new Error("canonical exact-five provider fixtures failed closed incorrectly"); process.stdout.write("Supply-chain provider real-tar signed exact-five fixtures: PASS\n"); } finally { await rm(fixtureRoot, { recursive: true, force: true }); } function signedEvidence( value: Record, keyId: string, publicKey: KeyObject, privateKey: KeyObject, ) { return { ...value, signature: { algorithm: "Ed25519", keyId, publicKeyFingerprint: providerPublicKeyFingerprint(publicKey), value: sign( null, providerEvidenceSignaturePayload(value), privateKey, ).toString("base64"), }, }; } async function write(root: string, relative: string, value: string | Buffer): Promise { const absolute = path.join(root, relative); await mkdir(path.dirname(absolute), { recursive: true }); await writeFile(absolute, value); } async function captureRejection( operation: () => Promise, ): Promise> { try { await operation(); return Object.freeze({ rejected: false, failure: "fixture unexpectedly passed" }); } catch (error) { return Object.freeze({ rejected: true, failure: error instanceof Error ? error.message : String(error), }); } } function sha256(bytes: Buffer): string { return createHash("sha256").update(bytes).digest("hex"); }