46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
import { z } from "zod";
|
|
|
|
export const ciContractReportSchema = z
|
|
.object({
|
|
schemaVersion: z.literal(2),
|
|
nodeVersion: z.string().regex(/^\d+\.\d+\.\d+$/u),
|
|
gateCount: z.literal(26),
|
|
commandDefinitionCount: z.number().int().positive(),
|
|
commandReferenceCount: z.number().int().positive(),
|
|
artifactCount: z.number().int().positive(),
|
|
jobCount: z.literal(9),
|
|
workflowSha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
durationStatus: z.string().min(1),
|
|
negativeFixtures: z.array(
|
|
z
|
|
.object({
|
|
readiness: z.enum([
|
|
"MERGE_READY",
|
|
"RELEASE_READY",
|
|
"PROD_PROMOTION_READY",
|
|
"FIELD_SLO_READY",
|
|
"DOCUMENTATION_READY",
|
|
]),
|
|
failedGate: z.string().regex(/^FE-GATE-\d{3}$/u),
|
|
passed: z.boolean(),
|
|
})
|
|
.strict(),
|
|
),
|
|
failures: z.array(z.string()),
|
|
passed: z.boolean(),
|
|
})
|
|
.strict()
|
|
.superRefine((report, context) => {
|
|
const fail = (path: PropertyKey[], message: string) =>
|
|
context.addIssue({ code: "custom", path, message });
|
|
if ((report.passed === true) !== (report.failures.length === 0)) {
|
|
fail(["passed"], "passed must agree with failures");
|
|
}
|
|
if (
|
|
report.negativeFixtures.length !== 5 ||
|
|
report.negativeFixtures.some((fixture) => !fixture.passed)
|
|
) {
|
|
fail(["negativeFixtures"], "every readiness negative fixture must pass");
|
|
}
|
|
});
|