60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
import {
|
|
validateProviderEvidence,
|
|
type ExpectedPromotionContext,
|
|
type ProviderTrust,
|
|
} from "./provider-evidence.ts";
|
|
import {
|
|
verifyReleaseCandidate,
|
|
type ReleaseCandidateManifest,
|
|
} from "./release-candidate.ts";
|
|
|
|
export async function validateProviderUpload(input: Readonly<{
|
|
kind: "vulnerability" | "provenance";
|
|
verifiedManifest: ReleaseCandidateManifest;
|
|
archiveSha256: string;
|
|
candidateRoot: string;
|
|
capturedReport: Buffer;
|
|
expectedContext: ExpectedPromotionContext;
|
|
trust: ProviderTrust;
|
|
nowEpochMs?: () => number;
|
|
}>): Promise<unknown> {
|
|
if (
|
|
input.expectedContext.candidate.archiveSha256 !== input.archiveSha256 ||
|
|
input.expectedContext.candidate.bundleSha256 !== input.verifiedManifest.bundleSha256 ||
|
|
input.expectedContext.candidate.distSha256 !== input.verifiedManifest.distSha256 ||
|
|
input.expectedContext.candidate.lockfileSha256 !== input.verifiedManifest.lockfileSha256
|
|
) {
|
|
throw new Error("provider supervisor expected candidate context mismatch");
|
|
}
|
|
const verifiedCandidate = await verifyReleaseCandidate(
|
|
input.verifiedManifest,
|
|
input.candidateRoot,
|
|
);
|
|
if (verifiedCandidate.failures.length > 0) {
|
|
throw new Error(
|
|
`provider input candidate root changed: ${verifiedCandidate.failures.join("; ")}`,
|
|
);
|
|
}
|
|
let report: unknown;
|
|
try {
|
|
report = JSON.parse(
|
|
new TextDecoder("utf-8", { fatal: true }).decode(input.capturedReport),
|
|
) as unknown;
|
|
} catch {
|
|
throw new TypeError("provider output is not canonical UTF-8 JSON");
|
|
}
|
|
const evaluated = validateProviderEvidence({
|
|
kind: input.kind,
|
|
value: report,
|
|
expected: input.expectedContext,
|
|
trust: input.trust,
|
|
nowEpochMs: input.nowEpochMs,
|
|
});
|
|
if (evaluated.status !== "PASS" || !evaluated.evidence) {
|
|
throw new Error(
|
|
`provider evidence context validation failed: ${evaluated.failures.join("; ")}`,
|
|
);
|
|
}
|
|
return evaluated.evidence;
|
|
}
|