import { createHash } from "node:crypto"; import { mkdir, readFile, writeFile } from "node:fs/promises"; import { verifyCompatibilityTuple } from "../src/application/policies/compatibility.js"; import { compareReleaseToRuntime, RELEASE_TOKEN_REGISTRY, } from "../src/contracts/release-tokens.js"; const fixturesDocument = /** @type {{ * fixtures: Array<{ * name: string, * expectedCompatible: boolean, * frontend: { * buildId: string, * configSchemaVersion: string, * apiContractVersion: string, * assetManifestHash: string, * releaseId: string * }, * runtime: { * buildId: string, * configSchemaVersion: string, * apiContractVersion: string, * assetManifestHash: string, * releaseId: string * } * }> * }} */ ( JSON.parse( await readFile("config/release/coherence-fixtures.json", "utf8"), ) ); const release = JSON.parse(await readFile("dist/release-manifest.json", "utf8")); const runtimeConfig = JSON.parse(await readFile("dist/config.json", "utf8")); const viteManifest = await readFile("dist/.vite/manifest.json"); const actualAssetManifestHash = createHash("sha256") .update(viteManifest) .digest("hex"); const artifactComparison = compareReleaseToRuntime(release, runtimeConfig); const artifactMismatches = [...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 (!Number.isFinite(Date.parse(release.builtAt))) { artifactMismatches.push("releaseToken:builtAtFormat"); } if (release.assetManifestHash !== actualAssetManifestHash) { artifactMismatches.push("assetManifestContent"); } 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`, );