import { dependencyDiffArtifactSchema, dependencyInventoryArtifactSchema, licenseReportArtifactSchema, } from "../contracts/release-artifacts.ts"; import type { DistOutput } from "./release-candidate.ts"; import { diffDependencyInventories, supplyChainDigest, validateDependencyReview, validateLicensePolicy, } from "./supply-chain.ts"; type Document = Record; export function recomputeDependencyEvidence(input: Readonly<{ inventory: unknown; baseline: unknown; baselineApproval: unknown; dependencyChangeEvidence: unknown; skipBaseline?: boolean; }>) { const inventory = dependencyInventoryArtifactSchema.parse(input.inventory); const baseline = asDocument(input.baseline); const approval = asDocument(input.baselineApproval); const dependencyChangeEvidence = asDocument(input.dependencyChangeEvidence); const failures: string[] = []; const skipBaseline = input.skipBaseline === true; let diff: ReturnType = Object.freeze({ added: Object.freeze([]), removed: Object.freeze([]), changed: Object.freeze([]), upgrades: Object.freeze([]), }); let review: ReturnType = Object.freeze({ passed: skipBaseline, highRisk: Object.freeze([]), failures: Object.freeze( skipBaseline ? [] : ["dependency baseline unavailable"], ), }); const baselineDigest = baseline ? supplyChainDigest(baseline) : null; if (baseline && approval) { diff = diffDependencyInventories(baseline, inventory); review = validateDependencyReview( diff, inventory, dependencyChangeEvidence ?? {}, ); if ( approval.schemaVersion !== 1 || approval.snapshotDigest !== baselineDigest || typeof approval.owner !== "string" || approval.owner.trim().length === 0 ) { failures.push("dependency baseline approval digest mismatch"); } } else if (!skipBaseline) { failures.push("dependency baseline and approval are required"); } failures.push(...review.failures); const report = dependencyDiffArtifactSchema.parse({ schemaVersion: 2, baselineDigest, currentDigest: supplyChainDigest(inventory), ...diff, highRisk: review.highRisk, reviewFailures: review.failures, }); return Object.freeze({ report, dependencyDiff: diff, highRisk: review.highRisk, failures: Object.freeze(failures), }); } export function compareStoredDependencyEvidence( recomputed: ReturnType, stored: unknown, ): string[] { const parsed = dependencyDiffArtifactSchema.safeParse(stored); if ( !parsed.success || supplyChainDigest(parsed.data) !== supplyChainDigest(recomputed.report) ) { return ["stored dependency diff does not match recomputed policy evidence"]; } return [...recomputed.failures]; } export function recomputeLicenseEvidence(input: Readonly<{ inventory: unknown; policy: unknown; }>) { const inventory = dependencyInventoryArtifactSchema.parse(input.inventory); const policy = asDocument(input.policy) ?? {}; const result = validateLicensePolicy(inventory, policy); const report = licenseReportArtifactSchema.parse({ schemaVersion: 1, status: result.passed ? "PASS" : "FAIL", dependencyCount: inventory.dependencyCount, results: result.results, failures: result.failures, }); return Object.freeze({ report, failures: result.failures, }); } export function compareStoredLicenseEvidence( recomputed: ReturnType, stored: unknown, ): string[] { const parsed = licenseReportArtifactSchema.safeParse(stored); if ( !parsed.success || supplyChainDigest(parsed.data) !== supplyChainDigest(recomputed.report) ) { return ["stored license report does not match recomputed policy evidence"]; } return [...recomputed.failures]; } export function distChecksumsText(outputs: readonly DistOutput[]): string { return `${[...outputs] .sort((left, right) => left.path.localeCompare(right.path)) .map((output) => `${output.sha256} ${output.path}`) .join("\n")}\n`; } export function verifyStoredDistChecksums( outputs: readonly DistOutput[], stored: string, ): string[] { return stored === distChecksumsText(outputs) ? [] : ["stored dist checksums do not match current outputs"]; } function asDocument(value: unknown): Document | null { return value !== null && typeof value === "object" && !Array.isArray(value) ? (value as Document) : null; }