import { createHash } from "node:crypto"; import { mkdir, readFile, writeFile } from "node:fs/promises"; import { verifyCompatibilityTuple, type CompatibilityTuple, } from "../src/application/policies/compatibility.ts"; import { compareReleaseToRuntime, RELEASE_TOKEN_REGISTRY, } from "../src/contracts/release-tokens.ts"; import { ROUTE_REGISTRY, ROUTE_RUNTIME_CONTRACT, } from "../src/features/installed-feature-contracts.ts"; type CoherenceFixture = Readonly<{ name: string; expectedCompatible: boolean; frontend: CompatibilityTuple; runtime: CompatibilityTuple; }>; type ReleaseDocument = CompatibilityTuple & Record & Readonly<{ releaseId: string; routeChunks: Readonly> }>; type RuntimeConfigDocument = Readonly<{ BUILD_ID: string; CONFIG_SCHEMA_VERSION: string; API_CONTRACT_VERSION: string; RELEASE_ID: string; }>; type BuildManifestDocument = Readonly< Record & { outputs?: Readonly<{ runtimeConfigSchema?: unknown; routeChunks?: Readonly>; }>; } >; type ViteManifestEntry = Readonly<{ file: string; name?: string; isDynamicEntry?: boolean; }>; const fixturesDocument = parseFixturesDocument( JSON.parse( await readFile("config/release/coherence-fixtures.json", "utf8"), ), ); const release = parseReleaseDocument( JSON.parse(await readFile("dist/release-manifest.json", "utf8")), ); const runtimeConfig = parseRuntimeConfigDocument( JSON.parse(await readFile("dist/config.json", "utf8")), ); const buildManifest = parseBuildManifestDocument( JSON.parse(await readFile("artifacts/release/build-manifest.json", "utf8")), ); const runtimeConfigJsonSchema = requireRecord( JSON.parse(await readFile("dist/runtime-config.schema.json", "utf8")), "runtime config JSON schema", ); const viteManifest = await readFile("dist/.vite/manifest.json", "utf8"); const viteManifestObject = parseViteManifest(JSON.parse(viteManifest)); const actualAssetManifestHash = createHash("sha256") .update(viteManifest) .digest("hex"); const artifactComparison = compareReleaseToRuntime(release, runtimeConfig); const artifactMismatches: string[] = [...artifactComparison.mismatches]; for (const token of Object.keys(RELEASE_TOKEN_REGISTRY)) { if (typeof release[token] !== "string" || release[token].length === 0) { artifactMismatches.push(`releaseToken:${token}`); } } if ( typeof release.builtAt !== "string" || !Number.isFinite(Date.parse(release.builtAt)) ) { artifactMismatches.push("releaseToken:builtAtFormat"); } if (release.assetManifestHash !== actualAssetManifestHash) { artifactMismatches.push("assetManifestContent"); } if ( runtimeConfigJsonSchema.$schema !== "https://json-schema.org/draft/2020-12/schema" || runtimeConfigJsonSchema.type !== "object" || !runtimeConfigJsonSchema.properties ) { artifactMismatches.push("runtimeConfigSchema"); } if ( buildManifest.outputs?.runtimeConfigSchema !== "dist/runtime-config.schema.json" ) { artifactMismatches.push("buildManifest:runtimeConfigSchema"); } for (const [buildToken, releaseToken] of [ ["buildId", "buildId"], ["commitSha", "commitSha"], ["releaseId", "releaseId"], ["generatedAt", "builtAt"], ]) { if (buildManifest[buildToken] !== release[releaseToken]) { artifactMismatches.push(`buildManifest:${buildToken}`); } } const expectedChunkIds = new Set( Object.values(ROUTE_REGISTRY).map((definition) => definition.chunkId), ); const actualChunkIds = new Set(Object.keys(release.routeChunks)); for (const chunkId of expectedChunkIds) { if (!actualChunkIds.has(chunkId)) { artifactMismatches.push(`routeChunk:missing:${chunkId}`); } } for (const chunkId of actualChunkIds) { if (!expectedChunkIds.has(chunkId)) { artifactMismatches.push(`routeChunk:orphan:${chunkId}`); } } const runtimeContracts: Readonly> = ROUTE_RUNTIME_CONTRACT; for (const definition of Object.values(ROUTE_REGISTRY)) { const runtime = runtimeContracts[definition.routeId]; const viteEntry = Object.values(viteManifestObject).find( (entry) => entry.name === runtime?.moduleId && entry.isDynamicEntry, ); const routeAsset = release.routeChunks[definition.chunkId]; if (!runtime || !viteEntry || routeAsset !== viteEntry.file) { artifactMismatches.push(`routeChunk:mismatch:${definition.chunkId}`); continue; } if ( buildManifest.outputs?.routeChunks?.[definition.chunkId] !== routeAsset ) { artifactMismatches.push(`buildManifest:routeChunk:${definition.chunkId}`); } try { await readFile(`dist/${routeAsset}`); } catch { artifactMismatches.push(`routeChunk:file:${definition.chunkId}`); } } const fixtures = fixturesDocument.fixtures.map((fixture) => { const result = verifyCompatibilityTuple({ frontend: fixture.frontend, runtime: fixture.runtime, }); return { name: fixture.name, expectedCompatible: fixture.expectedCompatible, actualCompatible: result.compatible, mismatches: result.mismatches, passed: result.compatible === fixture.expectedCompatible, }; }); const artifact = { checked: true, compatible: artifactComparison.compatible && artifactMismatches.length === 0, mismatches: artifactMismatches, releaseId: release.releaseId, }; const passed = artifact.compatible && fixtures.every((fixture) => fixture.passed); const report = { schemaVersion: 1, generatedAt: new Date().toISOString(), artifact, fixtures, passed, }; await mkdir("artifacts/release", { recursive: true }); await writeFile( "artifacts/release/verification.json", `${JSON.stringify(report, null, 2)}\n`, ); if (!passed) { process.stderr.write( `Release coherence failed: ${artifactMismatches.join(", ") || "fixture"}\n`, ); process.exit(1); } process.stdout.write( `Release coherence: PASS (${fixtures.length - 1} mixed fixtures rejected)\n`, ); function parseFixturesDocument(value: unknown): Readonly<{ fixtures: readonly CoherenceFixture[]; }> { const document = requireRecord(value, "release coherence fixtures"); if (!Array.isArray(document.fixtures)) { throw new TypeError("release coherence fixtures must be an array"); } return { fixtures: document.fixtures.map((candidate, index) => { const fixture = requireRecord(candidate, `release fixture ${index}`); if ( typeof fixture.name !== "string" || typeof fixture.expectedCompatible !== "boolean" ) { throw new TypeError(`Invalid release fixture metadata: ${index}`); } return { name: fixture.name, expectedCompatible: fixture.expectedCompatible, frontend: parseCompatibilityTuple( fixture.frontend, `release fixture ${index}.frontend`, ), runtime: parseCompatibilityTuple( fixture.runtime, `release fixture ${index}.runtime`, ), }; }), }; } function parseReleaseDocument(value: unknown): ReleaseDocument { const document = requireRecord(value, "release manifest"); const tuple = parseCompatibilityTuple(document, "release manifest"); const routeChunks = isRecord(document.routeChunks) ? document.routeChunks : {}; return { ...document, ...tuple, routeChunks }; } function parseRuntimeConfigDocument(value: unknown): RuntimeConfigDocument { const document = requireRecord(value, "runtime config"); return { BUILD_ID: requireString(document.BUILD_ID, "runtime config BUILD_ID"), CONFIG_SCHEMA_VERSION: requireString( document.CONFIG_SCHEMA_VERSION, "runtime config CONFIG_SCHEMA_VERSION", ), API_CONTRACT_VERSION: requireString( document.API_CONTRACT_VERSION, "runtime config API_CONTRACT_VERSION", ), RELEASE_ID: requireString( document.RELEASE_ID, "runtime config RELEASE_ID", ), }; } function parseBuildManifestDocument(value: unknown): BuildManifestDocument { const document = requireRecord(value, "build manifest"); const outputs = isRecord(document.outputs) ? { runtimeConfigSchema: document.outputs.runtimeConfigSchema, routeChunks: isRecord(document.outputs.routeChunks) ? document.outputs.routeChunks : undefined, } : undefined; return { ...document, ...(outputs ? { outputs } : {}) }; } function parseCompatibilityTuple(value: unknown, label: string): CompatibilityTuple { const document = requireRecord(value, label); return { buildId: requireString(document.buildId, `${label}.buildId`), configSchemaVersion: requireString( document.configSchemaVersion, `${label}.configSchemaVersion`, ), apiContractVersion: requireString( document.apiContractVersion, `${label}.apiContractVersion`, ), assetManifestHash: requireString( document.assetManifestHash, `${label}.assetManifestHash`, ), releaseId: requireString(document.releaseId, `${label}.releaseId`), }; } function parseViteManifest( value: unknown, ): Readonly> { const document = requireRecord(value, "Vite manifest"); const entries: Record = {}; for (const [key, candidate] of Object.entries(document)) { const entry = requireRecord(candidate, `Vite manifest entry ${key}`); entries[key] = { file: requireString(entry.file, `Vite manifest entry ${key}.file`), ...(typeof entry.name === "string" ? { name: entry.name } : {}), ...(typeof entry.isDynamicEntry === "boolean" ? { isDynamicEntry: entry.isDynamicEntry } : {}), }; } return entries; } function requireString(value: unknown, label: string): string { if (typeof value !== "string" || value.length === 0) { throw new TypeError(`${label} must be a non-empty string`); } return value; } function requireRecord( value: unknown, label: string, ): Record { if (!isRecord(value)) throw new TypeError(`${label} must be an object`); return value; } function isRecord(value: unknown): value is Record { return Boolean(value && typeof value === "object" && !Array.isArray(value)); }