import { verify, type KeyObject } from "node:crypto"; import { z } from "zod"; import { canonicalizeSupplyChainValue } from "./supply-chain.ts"; const sha256 = z.string().regex(/^[a-f0-9]{64}$/u); const nonEmptyString = z.string().trim().min(1); const signatureSchema = z .object({ algorithm: z.literal("Ed25519"), keyId: nonEmptyString, value: z.string().regex(/^[A-Za-z0-9+/]+={0,2}$/u), }) .strict(); export const vulnerabilityProviderReportSchema = z .object({ schemaVersion: z.literal(1), provider: nonEmptyString, generatedAt: z.iso.datetime(), scannedLockfileSha256: sha256, scannedDistSha256: sha256, findings: z.array(z.record(z.string(), z.json())), signature: signatureSchema, }) .strict(); export const provenanceProviderAttestationSchema = z .object({ schemaVersion: z.literal(1), provider: nonEmptyString, signer: nonEmptyString, generatedAt: z.iso.datetime(), subject: z .object({ name: z.literal("dist"), digest: z.object({ sha256 }).strict(), }) .strict(), signature: signatureSchema, }) .strict(); export const providerVerificationArtifactSchema = z .object({ schemaVersion: z.literal(2), artifactType: z.enum(["provider-verification", "promotion-verification"]), status: z.enum(["PASS", "FAIL_UNVERIFIED"]), vulnerabilityStatus: z.enum(["PASS", "FAIL_UNVERIFIED"]), provenanceAttestationStatus: z.enum(["PASS", "FAIL_UNVERIFIED"]), lockfileSha256: sha256, distSha256: sha256, candidateArchiveSha256: sha256.nullable(), vulnerabilityReportSha256: sha256.nullable(), provenanceAttestationSha256: sha256.nullable(), failures: z.array(z.string()), }) .strict() .superRefine((artifact, context) => { const passing = artifact.status === "PASS" && artifact.vulnerabilityStatus === "PASS" && artifact.provenanceAttestationStatus === "PASS" && artifact.failures.length === 0; if ((artifact.status === "PASS") !== passing) { context.addIssue({ code: "custom", path: ["status"], message: "verification PASS must agree with provider statuses and failures", }); } if ( artifact.status === "PASS" && [ artifact.candidateArchiveSha256, artifact.vulnerabilityReportSha256, artifact.provenanceAttestationSha256, ].some((digest) => digest === null) ) { context.addIssue({ code: "custom", path: ["candidateArchiveSha256"], message: "passing verification requires every exact input digest", }); } if (artifact.status === "FAIL_UNVERIFIED" && artifact.failures.length === 0) { context.addIssue({ code: "custom", path: ["failures"], message: "failed verification requires a failure diagnostic", }); } }); export type ProviderVerificationArtifactType = z.infer< typeof providerVerificationArtifactSchema >["artifactType"]; export type ProviderTrust = Readonly<{ keyId: string; publicKey: KeyObject; }>; export type PromotionEvidenceResult = Readonly<{ status: "PASS" | "FAIL_UNVERIFIED"; vulnerabilityStatus: "PASS" | "FAIL_UNVERIFIED"; provenanceAttestationStatus: "PASS" | "FAIL_UNVERIFIED"; failures: readonly string[]; }>; export function providerEvidenceSignaturePayload(value: unknown): Buffer { if (!isRecord(value)) return Buffer.from("null", "utf8"); const { signature: _signature, ...payload } = value; return Buffer.from( JSON.stringify(canonicalizeSupplyChainValue(payload)), "utf8", ); } export function evaluatePromotionEvidence(input: Readonly<{ candidate: Readonly<{ distSha256: string; lockfileSha256: string }>; currentDistSha256: string; localStatus: unknown; vulnerabilityReport: unknown; provenanceAttestation: unknown; vulnerabilityTrust: ProviderTrust | null; provenanceTrust: ProviderTrust | null; }>): PromotionEvidenceResult { const failures: string[] = []; let vulnerabilityStatus: "PASS" | "FAIL_UNVERIFIED" = "FAIL_UNVERIFIED"; let provenanceAttestationStatus: "PASS" | "FAIL_UNVERIFIED" = "FAIL_UNVERIFIED"; if (input.localStatus !== "PASS") { failures.push("local supply-chain evidence is not PASS"); } if (input.currentDistSha256 !== input.candidate.distSha256) { failures.push("candidate dist bytes changed after immutable build"); } const vulnerability = vulnerabilityProviderReportSchema.safeParse( input.vulnerabilityReport, ); if (!vulnerability.success) { failures.push("external vulnerability provider report is missing or invalid"); } else { if ( vulnerability.data.scannedLockfileSha256 !== input.candidate.lockfileSha256 ) { failures.push("vulnerability report lockfile digest mismatch"); } if ( vulnerability.data.scannedDistSha256 !== input.candidate.distSha256 ) { failures.push("vulnerability report dist digest mismatch"); } if (vulnerability.data.findings.length > 0) { failures.push("vulnerability report contains findings"); } const signaturePassed = signatureMatches( vulnerability.data, input.vulnerabilityTrust, ); if (!signaturePassed) { failures.push("vulnerability report signature verification failed"); } if ( vulnerability.data.scannedLockfileSha256 === input.candidate.lockfileSha256 && vulnerability.data.scannedDistSha256 === input.candidate.distSha256 && vulnerability.data.findings.length === 0 && input.currentDistSha256 === input.candidate.distSha256 && input.localStatus === "PASS" && signaturePassed ) { vulnerabilityStatus = "PASS"; } } const provenance = provenanceProviderAttestationSchema.safeParse( input.provenanceAttestation, ); if (!provenance.success) { failures.push("external signed provenance attestation is missing or invalid"); } else { if (provenance.data.subject.digest.sha256 !== input.candidate.distSha256) { failures.push("provenance attestation dist digest mismatch"); } const signaturePassed = signatureMatches( provenance.data, input.provenanceTrust, ); if (!signaturePassed) { failures.push("provenance attestation signature verification failed"); } if ( provenance.data.subject.digest.sha256 === input.candidate.distSha256 && input.currentDistSha256 === input.candidate.distSha256 && input.localStatus === "PASS" && signaturePassed ) { provenanceAttestationStatus = "PASS"; } } return Object.freeze({ status: failures.length === 0 && vulnerabilityStatus === "PASS" && provenanceAttestationStatus === "PASS" ? "PASS" : "FAIL_UNVERIFIED", vulnerabilityStatus, provenanceAttestationStatus, failures: Object.freeze(failures), }); } function signatureMatches( evidence: z.infer< | typeof vulnerabilityProviderReportSchema | typeof provenanceProviderAttestationSchema >, trust: ProviderTrust | null, ): boolean { if ( !trust || evidence.signature.keyId !== trust.keyId || trust.publicKey.asymmetricKeyType !== "ed25519" ) { return false; } try { return verify( null, providerEvidenceSignaturePayload(evidence), trust.publicKey, Buffer.from(evidence.signature.value, "base64"), ); } catch { return false; } } function isRecord(value: unknown): value is Record { return Boolean(value) && typeof value === "object" && !Array.isArray(value); }