import { createHash } from "node:crypto"; import { readFile } from "node:fs/promises"; import path from "node:path"; import { z, type ZodType } from "zod"; import { EXPECTED_CONTRACT_SET_PACKAGES } from "../../src/features/installed-contract-contributions.ts"; import { ROUTE_REGISTRY, ROUTE_RUNTIME_CONTRACT, } from "../../src/features/installed-feature-contracts.ts"; import { buildManifestArtifactSchema, bundlePerformanceArtifactSchema, dependencyDiffArtifactSchema, dependencyInventoryArtifactSchema, licenseReportArtifactSchema, provenanceArtifactSchema, releaseManifestArtifactSchema, releaseVerificationArtifactSchema, runtimeConfigArtifactSchema, sbomArtifactSchema, supplyChainVerificationArtifactSchema, vulnerabilityReportArtifactSchema, } from "../contracts/release-artifacts.ts"; import { CANONICAL_VITE_MANIFEST_PATH, verifyBuildManifestOutputs, } from "./build-manifest-outputs.ts"; import { assertMatchesJsonSchema } from "./json-schema.ts"; import type { ReleaseCandidateManifest } from "./release-candidate.ts"; import { collectDistOutputs, distSha256 } from "./release-candidate.ts"; import { verifyReleaseRuntimeCoherence } from "./release-runtime-coherence.ts"; import { digestReleaseInputFiles } from "./release-input-evidence.ts"; import { buildRepositoryFileInventory, parseRepositoryFileInventoryPolicy, } from "./repository-file-inventory.ts"; import { isValidSha512Integrity, parsePnpmLockfilePackages, supplyChainDigest, verifySupplyChainCoherence, } from "./supply-chain.ts"; const sha256 = z.string().regex(/^[a-f0-9]{64}$/u); export const supplyChainCoherenceReportSchema = z .object({ schemaVersion: z.literal(1), status: z.enum(["PASS", "FAIL"]), dependencyCount: z.int().nonnegative(), lockfileSha256: sha256, distSha256: sha256, sbomSha256: sha256, failures: z.array(z.string()), }) .strict(); export type SupplyChainCoherenceReport = z.infer< typeof supplyChainCoherenceReportSchema >; export async function verifyLocalSupplyChainEvidence( repositoryRoot = process.cwd(), ): Promise { const failures: string[] = []; const inventory = await parseArtifact( repositoryRoot, "artifacts/release/dependency-inventory.json", dependencyInventoryArtifactSchema, "dependency inventory", failures, ); const sbom = await parseArtifact( repositoryRoot, "artifacts/release/sbom.cdx.json", sbomArtifactSchema, "SBOM", failures, ); const provenance = await parseArtifact( repositoryRoot, "artifacts/release/provenance.json", provenanceArtifactSchema, "local provenance", failures, ); const verification = await parseArtifact( repositoryRoot, "artifacts/security/supply-chain-verification.json", supplyChainVerificationArtifactSchema, "supply-chain verification", failures, ); for (const [schemaPath, artifact, label] of [ [ "schemas/artifacts/dependency-inventory.schema.json", inventory, "dependency inventory", ], [ "schemas/artifacts/supply-chain-verification.schema.json", verification, "supply-chain verification", ], ] as const) { if (!artifact) continue; try { assertMatchesJsonSchema( await readJson(repositoryRoot, schemaPath), artifact, label, ); } catch { failures.push(`${label} JSON Schema mismatch`); } } let lockfileText = ""; let lockfileSha256 = "0".repeat(64); try { const rawLockfile = await readFile( path.join(repositoryRoot, "pnpm-lock.yaml"), ); lockfileText = rawLockfile.toString("utf8"); lockfileSha256 = createHash("sha256").update(rawLockfile).digest("hex"); } catch { failures.push("raw pnpm-lock.yaml is missing or unreadable"); } let distDigest = "0".repeat(64); try { distDigest = distSha256(await collectDistOutputs(repositoryRoot)); } catch { failures.push("candidate dist is missing or unreadable"); } const sbomSha256 = sbom ? supplyChainDigest(sbom) : "0".repeat(64); if (inventory && sbom && provenance) { failures.push( ...verifySupplyChainCoherence( sbom, inventory, provenance, distDigest, ).failures, ); } if ( !inventory || !verification || inventory.lockfileSha256 !== lockfileSha256 || verification.lockfileSha256 !== lockfileSha256 ) { failures.push("inventory/verification lockfile digest mismatch"); } if ( !verification || verification.localStatus !== "PASS" || verification.failures.length > 0 || verification.distSha256 !== distDigest || verification.sbomSha256 !== sbomSha256 ) { failures.push("verification digest/status set is incoherent"); } if (inventory && sbom && provenance && verification) { try { const policy = parseRepositoryFileInventoryPolicy( await readJson( repositoryRoot, "config/security/secret-scan-policy.json", ), ); const repositoryInventory = await buildRepositoryFileInventory({ repositoryRoot, trackedRoots: policy.trackedRoots, generatedRoots: policy.generatedRoots, optionalRoots: policy.optionalRoots, }); const sourceSetSha256 = await digestReleaseInputFiles( repositoryInventory.trackedFiles, (file) => readFile(path.join(repositoryRoot, file)), ); if ( verification.sourceSetSha256 !== sourceSetSha256 || provenance.predicate.materials.sourceSetSha256 !== sourceSetSha256 || provenance.predicate.materials.sbomSha256 !== sbomSha256 ) { failures.push("source/SBOM provenance materials are incoherent"); } } catch { failures.push("release source inventory is unavailable or unreadable"); } } const lockRows = parsePnpmLockfilePackages(lockfileText); const inventoryRows = inventory?.dependencies ?? []; const inventoryByIdentity = new Map( inventoryRows.map( (entry) => [`${entry.name}@${entry.version}`, entry] as const, ), ); if (lockRows.length !== inventoryRows.length) { failures.push("transitive dependency count differs from lockfile"); } for (const lockRow of lockRows) { const identity = `${lockRow.name}@${lockRow.version}`; const dependency = inventoryByIdentity.get(identity); if ( !dependency || dependency.integrity !== lockRow.integrity || !isValidSha512Integrity(lockRow.integrity) ) { failures.push(`lockfile inventory integrity mismatch: ${identity}`); } } return supplyChainCoherenceReportSchema.parse({ schemaVersion: 1, status: failures.length === 0 ? "PASS" : "FAIL", dependencyCount: inventoryRows.length, lockfileSha256, distSha256: distDigest, sbomSha256, failures, }); } export async function verifyArchivedLocalEvidence(input: Readonly<{ repositoryRoot?: string; candidate: ReleaseCandidateManifest; }>): Promise> { const repositoryRoot = path.resolve(input.repositoryRoot ?? process.cwd()); const failures: string[] = []; const supplyReport = await verifyLocalSupplyChainEvidence(repositoryRoot); failures.push(...supplyReport.failures); if (supplyReport.lockfileSha256 !== input.candidate.lockfileSha256) { failures.push("candidate/raw lockfile digest mismatch"); } const buildManifest = await parseArtifact( repositoryRoot, "artifacts/release/build-manifest.json", buildManifestArtifactSchema, "build manifest", failures, ); const release = await parseArtifact( repositoryRoot, "dist/release-manifest.json", releaseManifestArtifactSchema, "release manifest", failures, ); const runtime = await parseArtifact( repositoryRoot, "dist/config.json", runtimeConfigArtifactSchema, "runtime config", failures, ); const storedRelease = await parseArtifact( repositoryRoot, "artifacts/release/verification.json", releaseVerificationArtifactSchema, "release verification", failures, ); const storedSupply = await parseArtifact( repositoryRoot, "artifacts/security/supply-chain-coherence.json", supplyChainCoherenceReportSchema, "supply-chain coherence", failures, ); await validateSupportingArtifacts(repositoryRoot, failures); if (buildManifest) { try { assertMatchesJsonSchema( await readJson( repositoryRoot, "schemas/artifacts/build-manifest.schema.json", ), buildManifest, "build manifest", ); } catch { failures.push("build manifest JSON Schema mismatch"); } failures.push( ...(await verifyBuildManifestOutputs(buildManifest, { repositoryRoot })), ); } if (release && runtime) { if (!runtime.BUILD_ID || !runtime.RELEASE_ID) { failures.push("runtime release identity is missing"); } else { const apiContractVersion = release.schemaVersion === 1 && "API_CONTRACT_VERSION" in runtime ? runtime.API_CONTRACT_VERSION : undefined; if (release.schemaVersion === 1 && apiContractVersion === undefined) { failures.push("runtime API contract identity is missing"); } const coherence = await verifyReleaseRuntimeCoherence({ release, runtime: { BUILD_ID: runtime.BUILD_ID, RELEASE_ID: runtime.RELEASE_ID, CONFIG_SCHEMA_VERSION: runtime.CONFIG_SCHEMA_VERSION, ...(apiContractVersion === undefined ? {} : { API_CONTRACT_VERSION: apiContractVersion }), }, contractPackages: EXPECTED_CONTRACT_SET_PACKAGES, }); failures.push(...coherence.mismatches.map((item) => `release:${item}`)); } await verifyReleaseOutputs( repositoryRoot, release, buildManifest, failures, ); } if ( !storedRelease || !storedRelease.passed || !storedRelease.artifact.checked || !storedRelease.artifact.compatible || storedRelease.artifact.mismatches.length > 0 || storedRelease.fixtures.length === 0 || storedRelease.fixtures.some((fixture) => !fixture.passed) || storedRelease.artifact.releaseId !== release?.releaseId || storedRelease.generatedAt !== release?.builtAt ) { failures.push("stored release verification is not a coherent PASS"); } if ( !storedSupply || storedSupply.status !== "PASS" || storedSupply.failures.length > 0 || storedSupply.dependencyCount !== supplyReport.dependencyCount || storedSupply.lockfileSha256 !== supplyReport.lockfileSha256 || storedSupply.distSha256 !== supplyReport.distSha256 || storedSupply.sbomSha256 !== supplyReport.sbomSha256 ) { failures.push("stored supply-chain coherence is not a recomputed PASS"); } await verifySecretScan(repositoryRoot, failures); return Object.freeze({ status: failures.length === 0 ? "PASS" : "FAIL", failures: Object.freeze([...new Set(failures)]), }); } async function validateSupportingArtifacts( repositoryRoot: string, failures: string[], ): Promise { const bundle = await parseArtifact( repositoryRoot, "artifacts/performance/bundle.json", bundlePerformanceArtifactSchema, "bundle report", failures, ); if (bundle) { try { const actual = await collectDistOutputs(repositoryRoot); if (JSON.stringify(bundle.outputs) !== JSON.stringify(actual)) { failures.push("bundle report does not describe current dist bytes"); } } catch { failures.push("bundle report dist inputs are unreadable"); } } const dependencyDiff = await parseArtifact( repositoryRoot, "artifacts/security/dependency-diff.json", dependencyDiffArtifactSchema, "dependency diff", failures, ); if (dependencyDiff && dependencyDiff.reviewFailures.length > 0) { failures.push("dependency review evidence is not PASS"); } const license = await parseArtifact( repositoryRoot, "artifacts/security/license-report.json", licenseReportArtifactSchema, "license report", failures, ); if (license && (license.status !== "PASS" || license.failures.length > 0)) { failures.push("license report is not PASS"); } const vulnerability = await parseArtifact( repositoryRoot, "artifacts/security/vulnerability-report.json", vulnerabilityReportArtifactSchema, "local vulnerability report", failures, ); if ( vulnerability && (vulnerability.status !== "FAIL_UNVERIFIED" || vulnerability.provider !== "UNCONFIGURED") ) { failures.push("local vulnerability report may not satisfy promotion"); } const provenance = await parseArtifact( repositoryRoot, "artifacts/release/provenance.json", provenanceArtifactSchema, "local provenance", failures, ); if ( provenance?.predicate.runDetails.metadata.invocationId !== "LOCAL_UNSIGNED" ) { failures.push("local provenance must remain LOCAL_UNSIGNED"); } } async function verifyReleaseOutputs( repositoryRoot: string, release: z.infer, buildManifest: z.infer | null, failures: string[], ): Promise { let viteManifest: Record = {}; try { const raw = await readFile( path.join(repositoryRoot, CANONICAL_VITE_MANIFEST_PATH), "utf8", ); viteManifest = asRecord(JSON.parse(raw), "Vite manifest"); if (createHash("sha256").update(raw).digest("hex") !== release.assetManifestHash) { failures.push("release asset manifest hash mismatch"); } } catch { failures.push("Vite manifest is missing or invalid"); } if ( buildManifest && (buildManifest.buildId !== release.buildId || buildManifest.commitSha !== release.commitSha || buildManifest.releaseId !== release.releaseId || buildManifest.generatedAt !== release.builtAt) ) { failures.push("build/release identity mismatch"); } const runtimeContracts: Readonly> = ROUTE_RUNTIME_CONTRACT; for (const definition of Object.values(ROUTE_REGISTRY)) { const runtime = runtimeContracts[definition.routeId]; const viteEntry = Object.values(viteManifest).find( (entry) => isRecord(entry) && entry.name === runtime?.moduleId && entry.isDynamicEntry === true, ); const file = isRecord(viteEntry) ? viteEntry.file : null; if ( typeof file !== "string" || release.routeChunks[definition.chunkId] !== file || buildManifest?.outputs.routeChunks[definition.chunkId] !== file ) { failures.push(`release route chunk mismatch: ${definition.chunkId}`); } } } async function verifySecretScan( repositoryRoot: string, failures: string[], ): Promise { try { const sarif = asRecord( await readJson(repositoryRoot, "artifacts/security/scan.sarif"), "secret scan SARIF", ); const runs = Array.isArray(sarif.runs) ? sarif.runs : []; if ( sarif.version !== "2.1.0" || runs.length !== 1 || !isRecord(runs[0]) || !Array.isArray(runs[0].results) || runs[0].results.length !== 0 ) { failures.push("secret scan SARIF is not an empty PASS"); } } catch { failures.push("secret scan SARIF is missing or invalid"); } } async function parseArtifact( repositoryRoot: string, file: string, schema: ZodType, label: string, failures: string[], ): Promise { try { return schema.parse(await readJson(repositoryRoot, file)); } catch { failures.push(`${label} executable schema mismatch`); return null; } } async function readJson(repositoryRoot: string, file: string): Promise { return JSON.parse(await readFile(path.join(repositoryRoot, file), "utf8")); } function asRecord(value: unknown, label: string): Record { if (!isRecord(value)) throw new TypeError(`${label} must be a JSON object`); return value; } function isRecord(value: unknown): value is Record { return Boolean(value) && typeof value === "object" && !Array.isArray(value); }