#!/usr/bin/env node const assert = require("assert"); const cp = require("child_process"); const crypto = require("crypto"); const fs = require("fs"); const os = require("os"); const path = require("path"); const repo = path.resolve(__dirname, ".."); const manifestPath = path.resolve( process.env.CLUSTERFLUX_PUBLIC_RELEASE_MANIFEST || path.join( process.env.CLUSTERFLUX_PUBLIC_RELEASE_DIR || path.join(repo, "target/release-candidate"), "public-release-manifest.json" ) ); const evidencePath = path.resolve( process.env.CLUSTERFLUX_QUALITY_GATE_EVIDENCE_PATH || path.join(repo, "target/acceptance/quality-gates.json") ); const transcriptPath = path.resolve( process.env.CLUSTERFLUX_QUALITY_GATE_TRANSCRIPT_PATH || path.join(repo, "target/acceptance/quality-gates-transcript.txt") ); function readJson(file) { return JSON.parse(fs.readFileSync(file, "utf8")); } function sha256(file) { return crypto .createHash("sha256") .update(fs.readFileSync(file)) .digest("hex"); } function commandText(command, args) { return [command, ...args] .map((value) => /^[A-Za-z0-9_./:=+-]+$/.test(value) ? value : JSON.stringify(value) ) .join(" "); } function main() { assert(fs.existsSync(manifestPath), `missing release manifest ${manifestPath}`); const manifest = readJson(manifestPath); fs.mkdirSync(path.dirname(evidencePath), { recursive: true }); fs.mkdirSync(path.dirname(transcriptPath), { recursive: true }); const transcript = fs.openSync(transcriptPath, "w"); const evidence = { kind: "clusterflux-release-quality-gates", source_commit: manifest.source_commit, source_tree_digest: manifest.source_tree_digest, public_tree_identity: manifest.public_tree_identity, checks: {}, }; const runGroup = (id, commands, extra = {}) => { const startedAt = Date.now(); const commandEvidence = []; let status = "passed"; for (const command of commands) { const args = command.args || []; const cwd = command.cwd || repo; const text = commandText(command.command, args); fs.writeSync(transcript, `\n[${id}] ${text}\n`); const commandStartedAt = Date.now(); const result = cp.spawnSync(command.command, args, { cwd, env: { ...process.env, ...(command.env || {}) }, stdio: ["ignore", transcript, transcript], }); const durationMs = Math.max(1, Date.now() - commandStartedAt); commandEvidence.push({ command: text, cwd, exit_status: result.status, duration_ms: durationMs, }); if (result.error || result.status !== 0) { status = "failed"; evidence.checks[id] = { status, duration_ms: Math.max(1, Date.now() - startedAt), commands: commandEvidence, error: result.error?.message || `command exited ${result.status}`, ...extra, }; fs.writeFileSync(evidencePath, `${JSON.stringify(evidence, null, 2)}\n`); throw new Error(`${id} failed: ${text}`); } } evidence.checks[id] = { status, duration_ms: Math.max(1, Date.now() - startedAt), commands: commandEvidence, ...extra, }; }; try { runGroup("repository_structure", [ { command: path.join(repo, "scripts/check-old-name.sh") }, { command: "node", args: [path.join(repo, "scripts/check-docs.js")] }, { command: path.join(repo, "scripts/check-code-size.sh") }, ]); runGroup("formatting", [ { command: "cargo", args: ["fmt", "--all", "--check"] }, { command: "cargo", args: [ "fmt", "--all", "--manifest-path", "private/hosted-policy/Cargo.toml", "--check", ], }, ]); runGroup("clippy_warnings_denied", [ { command: "cargo", args: ["clippy", "--workspace", "--all-targets", "--", "-D", "warnings"], }, { command: "cargo", args: [ "clippy", "--manifest-path", "private/hosted-policy/Cargo.toml", "--all-targets", "--", "-D", "warnings", ], }, ]); runGroup("public_workspace_tests", [ { command: "cargo", args: ["test", "--workspace", "--all-targets"], }, { command: "cargo", args: ["build", "--workspace", "--all-targets"], }, ]); runGroup("private_hosted_policy_locked_tests", [ { command: "cargo", args: [ "test", "--locked", "--manifest-path", "private/hosted-policy/Cargo.toml", "--all-targets", ], }, ]); runGroup("process_lifecycle_regressions", [ { command: "cargo", args: [ "test", "-p", "clusterflux-coordinator", "completed_main_waits_for_final_child_then_preserves_history_and_releases_the_slot", ], }, { command: "cargo", args: [ "test", "-p", "clusterflux-coordinator", "failed_main_aborts_unfinished_children_and_clears_process_debug_state", ], }, { command: "cargo", args: [ "test", "-p", "clusterflux-coordinator", "service_cancels_whole_process_and_blocks_new_task_launches", ], }, ]); runGroup("wasm_example_builds", [ { command: "cargo", args: [ "build", "-p", "hello-build", "--target", "wasm32-unknown-unknown", ], }, { command: "cargo", args: [ "build", "-p", "recovery-build", "--target", "wasm32-unknown-unknown", ], }, { command: "cargo", args: [ "build", "-p", "runtime-conformance", "--target", "wasm32-unknown-unknown", ], }, ]); runGroup("filtered_public_tree_build_and_tests", [ { command: path.join(repo, "scripts/verify-public-split.sh") }, ]); const extensionAsset = manifest.assets.find((asset) => asset.name.endsWith(".vsix") ); assert(extensionAsset, "candidate manifest omitted its VSIX"); const extensionFile = path.resolve( path.dirname(manifestPath), extensionAsset.file ); assert(fs.existsSync(extensionFile), `missing candidate VSIX ${extensionFile}`); const extensionDigest = sha256(extensionFile); assert.strictEqual(extensionDigest, extensionAsset.sha256); assert.strictEqual( extensionDigest, manifest.release_candidate.extension_sha256 ); const extractedVsix = fs.mkdtempSync( path.join(os.tmpdir(), "clusterflux-tested-vsix-") ); try { runGroup( "vscode_extension_candidate", [ { command: "npm", args: ["ci", "--ignore-scripts"], cwd: path.join(repo, "vscode-extension"), }, { command: "unzip", args: ["-q", extensionFile, "-d", extractedVsix], }, { command: "node", args: [path.join(repo, "scripts/vscode-extension-smoke.js")], env: { CLUSTERFLUX_VSCODE_EXTENSION_ROOT: path.join( extractedVsix, "extension" ), }, }, ], { candidate_vsix: { file: extensionFile, sha256: extensionDigest, }, } ); } finally { fs.rmSync(extractedVsix, { recursive: true, force: true }); } const publicCheckIds = [ "repository_structure", "formatting", "clippy_warnings_denied", "public_workspace_tests", "process_lifecycle_regressions", "wasm_example_builds", "filtered_public_tree_build_and_tests", "vscode_extension_candidate", ]; evidence.public = { status: "passed", duration_ms: publicCheckIds.reduce( (total, id) => total + evidence.checks[id].duration_ms, 0 ), independent_filtered_tree: true, }; evidence.private = { status: "passed", duration_ms: evidence.checks.formatting.duration_ms + evidence.checks.clippy_warnings_denied.duration_ms + evidence.checks.private_hosted_policy_locked_tests.duration_ms, }; evidence.status = "passed"; evidence.transcript = transcriptPath; fs.writeFileSync(evidencePath, `${JSON.stringify(evidence, null, 2)}\n`); } finally { fs.closeSync(transcript); } console.log(`Release quality gates passed: ${evidencePath}`); } try { main(); } catch (error) { console.error(error.stack || error.message); process.exit(1); }