import { z } from "zod"; export * from "../../src/contracts/release-artifacts.ts"; const nonEmptyString = z.string().min(1); const timestamp = z.iso.datetime(); const sha256 = z.string().regex(/^[a-f0-9]{64}$/u); const jsonObject = z.record(z.string(), z.json()); export const moduleInventoryArtifactSchema = z .object({ schemaVersion: z.literal(1), chunks: z.array( z .object({ fileName: nonEmptyString, modules: z.array(nonEmptyString), }) .strict(), ), }) .strict(); export const jsonSchemaDocumentArtifactSchema = z .object({ $schema: z.literal("https://json-schema.org/draft/2020-12/schema"), }) .catchall(z.json()); const dependencyInventoryRowSchema = z .object({ name: nonEmptyString, version: nonEmptyString, direct: z.boolean(), scope: z.enum(["production", "development"]), optional: z.boolean(), license: nonEmptyString, integrity: z.string().regex(/^sha512-/u), dependencies: z.array(nonEmptyString), }) .strict(); export const dependencyInventoryArtifactSchema = z .object({ schemaVersion: z.literal(2), packageManager: nonEmptyString, lockfileSha256: sha256, dependencyCount: z.int().positive(), directDependencyCount: z.int().positive(), dependencies: z.array(dependencyInventoryRowSchema).min(1), }) .strict() .superRefine((inventory, context) => { if (inventory.dependencyCount !== inventory.dependencies.length) { context.addIssue({ code: "custom", path: ["dependencyCount"], message: "must equal dependencies.length", }); } const actualDirect = inventory.dependencies.filter( (dependency) => dependency.direct, ).length; if (inventory.directDependencyCount !== actualDirect) { context.addIssue({ code: "custom", path: ["directDependencyCount"], message: "must equal the number of direct dependencies", }); } }); const dependencyUpgradeSchema = z .object({ name: nonEmptyString, from: nonEmptyString, to: nonEmptyString, }) .strict(); export const dependencyDiffSchema = z .object({ added: z.array(nonEmptyString), removed: z.array(nonEmptyString), changed: z.array(nonEmptyString), upgrades: z.array(dependencyUpgradeSchema), }) .strict(); export const supplyChainVerificationArtifactSchema = z .object({ schemaVersion: z.literal(1), localStatus: z.enum(["PASS", "FAIL"]), promotionStatus: z.enum(["PASS", "FAIL_UNVERIFIED"]), lockfileSha256: sha256, sourceSetSha256: sha256, distSha256: sha256, sbomSha256: sha256, dependencyDiff: dependencyDiffSchema, highRiskReview: z.array(nonEmptyString), vulnerabilityStatus: z.enum(["PASS", "FAIL", "FAIL_UNVERIFIED"]), provenanceAttestationStatus: z.enum(["PASS", "FAIL_UNVERIFIED"]), failures: z.array(z.string()), }) .strict(); const registryChangeSchema = z .object({ changeId: nonEmptyString, registryId: nonEmptyString, rowName: nonEmptyString, field: nonEmptyString, kind: nonEmptyString, impact: z.enum(["none", "additive", "behavior-change", "breaking"]), before: z.json().optional(), after: z.json().optional(), }) .strict(); const registryArtifactRowSchema = z .object({ registryId: nonEmptyString, owner: nonEmptyString, source: nonEmptyString, rowCount: z.int().nonnegative(), contract: jsonObject, rows: jsonObject, }) .strict(); const registrySnapshotBaseArtifactSchema = z .object({ schemaVersion: z.literal(2), generatedAt: timestamp, baselineDigest: sha256.nullable(), currentDigest: sha256, compatibility: z .object({ impact: z.enum([ "not-evaluated", "none", "additive", "behavior-change", "breaking", ]), changes: z.array(registryChangeSchema), }) .strict(), }) .strict(); const successfulRegistrySnapshotArtifactSchema = registrySnapshotBaseArtifactSchema.extend({ failures: z.array(z.string()).max(0), registries: z.array(registryArtifactRowSchema).length(11), }); const failedRegistrySnapshotArtifactSchema = registrySnapshotBaseArtifactSchema.extend({ failures: z.array(z.string()).min(1), registries: z.array(registryArtifactRowSchema), }); export const registrySnapshotArtifactSchema = z.union([ successfulRegistrySnapshotArtifactSchema, failedRegistrySnapshotArtifactSchema, ]); export const registryGovernanceRunArtifactSchema = z.union([ registrySnapshotBaseArtifactSchema.extend({ failures: z.array(z.string()).max(0), registries: z.array(registryArtifactRowSchema).min(1), }), failedRegistrySnapshotArtifactSchema, ]); const outputDigestSchema = z .object({ path: nonEmptyString, bytes: z.int().nonnegative(), gzipBytes: z.int().nonnegative(), sha256, }) .strict(); export const bundlePerformanceArtifactSchema = z .object({ schemaVersion: z.literal(1), generatedAt: timestamp, context: z .object({ nodeVersion: nonEmptyString, packageManager: nonEmptyString, runnerImage: nonEmptyString, }) .strict(), outputs: z.array(outputDigestSchema).min(1), }) .strict(); const cyclonedxComponentSchema = z .object({ type: z.literal("library"), "bom-ref": nonEmptyString, name: nonEmptyString, version: nonEmptyString, scope: z.enum(["optional", "required"]), hashes: z.array( z.object({ alg: z.literal("SHA-512"), content: nonEmptyString }).strict(), ), licenses: z.array( z.object({ expression: nonEmptyString }).strict(), ), properties: z.array( z.object({ name: nonEmptyString, value: nonEmptyString }).strict(), ), }) .strict(); export const sbomArtifactSchema = z .object({ bomFormat: z.literal("CycloneDX"), specVersion: z.literal("1.6"), serialNumber: nonEmptyString, version: z.literal(1), metadata: z .object({ component: z .object({ type: z.literal("application"), name: nonEmptyString, version: nonEmptyString, }) .strict(), properties: z.array( z.object({ name: nonEmptyString, value: nonEmptyString }).strict(), ), }) .strict(), components: z.array(cyclonedxComponentSchema), dependencies: z.array( z .object({ ref: nonEmptyString, dependsOn: z.array(nonEmptyString) }) .strict(), ), }) .strict(); export const provenanceArtifactSchema = z .object({ _type: z.literal("https://in-toto.io/Statement/v1"), subject: z .array( z .object({ name: z.literal("dist"), digest: z.object({ sha256 }).strict(), }) .strict(), ) .length(1), predicateType: z.literal("https://slsa.dev/provenance/v1"), predicate: z .object({ buildDefinition: z .object({ buildType: nonEmptyString, externalParameters: jsonObject, internalParameters: jsonObject, resolvedDependencies: z.array( z .object({ uri: nonEmptyString, digest: z.object({ sha256 }).strict() }) .strict(), ), }) .strict(), runDetails: z .object({ builder: z.object({ id: nonEmptyString }).strict(), metadata: z.object({ invocationId: nonEmptyString }).strict(), }) .strict(), materials: z .object({ lockfileSha256: sha256, sourceSetSha256: sha256, sbomSha256: sha256 }) .strict(), }) .strict(), }) .strict(); export const dependencyDiffArtifactSchema = z .object({ schemaVersion: z.literal(2), baselineDigest: sha256.nullable(), currentDigest: sha256, ...dependencyDiffSchema.shape, highRisk: z.array(nonEmptyString), reviewFailures: z.array(z.string()), }) .strict(); export const licenseReportArtifactSchema = z .object({ schemaVersion: z.literal(1), status: z.enum(["PASS", "FAIL"]), dependencyCount: z.int().nonnegative(), results: z.array( z .object({ package: nonEmptyString, license: nonEmptyString, passed: z.boolean(), reason: z.string().nullable(), }) .strict(), ), failures: z.array(z.string()), }) .strict(); export const vulnerabilityReportArtifactSchema = z .object({ schemaVersion: z.literal(1), provider: nonEmptyString, scannedLockfileSha256: sha256, status: z.enum(["PASS", "FAIL", "FAIL_UNVERIFIED"]), findings: z.array(jsonObject), exceptionsApplied: z.array(jsonObject), failures: z.array(z.string()), blocking: z.array(z.string()), }) .strict(); export const fieldWebVitalsArtifactSchema = z .object({ schemaVersion: z.literal(1), generatedAt: timestamp, window: z .object({ days: z.literal(28), start: timestamp, end: timestamp }) .strict(), context: z .object({ source: nonEmptyString, sourceSystem: z.string().nullable(), exportId: z.string().nullable(), network: z.literal("production-real-user"), routeAggregation: z.literal("route-id-only"), releaseId: z.string().nullable(), privacyApprovalRef: z.string().nullable(), thresholdDecisionRef: z.string().nullable(), validationFailures: z.array(z.string()), }) .strict(), metrics: z .object({ p75LcpMs: z.number().finite().nonnegative().nullable(), p75Cls: z.number().finite().nonnegative().nullable(), p75InpMs: z.number().finite().nonnegative().nullable(), }) .strict(), thresholds: z .object({ p75LcpMs: z.number().finite().nonnegative(), p75Cls: z.number().finite().nonnegative(), p75InpMs: z.number().finite().nonnegative(), minimumEligibleSamples: z.int().positive().nullable(), }) .strict(), eligibility: z .object({ consentRequired: z.literal(true), totalSamples: z.int().nonnegative(), eligibleSamples: z.int().nonnegative(), minimumEligibleSamples: z.int().positive().nullable(), routeSamples: z.record(z.string(), z.int().nonnegative()), }) .strict(), status: z.enum(["PASS", "FAIL_THRESHOLD", "FAIL_UNVERIFIED"]), passed: z.boolean(), }) .strict(); export const labPerformanceArtifactSchema = z .object({ schemaVersion: z.literal(1), generatedAt: timestamp, context: jsonObject, metrics: jsonObject, thresholds: jsonObject, fixtures: z.array( z.object({ name: nonEmptyString, passed: z.boolean() }).strict(), ), passed: z.boolean(), }) .strict(); export const releaseVerificationArtifactSchema = z .object({ schemaVersion: z.literal(1), generatedAt: timestamp, artifact: z .object({ checked: z.boolean(), compatible: z.boolean(), mismatches: z.array(z.string()), releaseId: nonEmptyString, }) .strict(), fixtures: z.array( z .object({ name: nonEmptyString, expectedCompatible: z.boolean(), actualCompatible: z.boolean(), mismatches: z.array(z.string()), passed: z.boolean(), }) .strict(), ), passed: z.boolean(), }) .strict(); export const runbookRecordArtifactSchema = z .object({ schemaVersion: z.literal(1), runbookId: z.string().regex(/^FE-RB-00[1-5]$/u), releaseId: nonEmptyString, drillTimestamp: timestamp, triggerInjected: nonEmptyString, triggerAsserted: z.boolean(), containmentAsserted: z.boolean(), escalationPathAsserted: z.boolean(), recoveryAssertions: z.array( z .object({ assertion: nonEmptyString, evidence: nonEmptyString, passed: z.boolean(), }) .strict(), ), negativeFixtureFailedAsExpected: z.boolean(), windowObservedBucket: nonEmptyString, providerVerificationRequired: z.boolean(), passed: z.boolean(), }) .strict();