#!/usr/bin/env node import { createHash } from "node:crypto"; import { lstat, readFile, realpath } from "node:fs/promises"; import { isAbsolute, relative, resolve, sep } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { isMap, isScalar, parseAllDocuments } from "yaml"; import { extractBashDocuments } from "./bash-heredoc.mjs"; import { validatePythonRevisionStates, validateRevisionState } from "./revision-state-policy.mjs"; import { parseWorkspaceYaml } from "../dist/workspaces/schema.js"; const scriptPath = fileURLToPath(import.meta.url); const allowedKinds = new Set(["policy_text", "workspace_descriptor", "deployment_script"]); // Exact-content trust exceptions. Each digest covers the raw UTF-8 bytes from the // opener line through the closer line (including physical line endings). These // blocks are reviewed non-workspace runtime/config generation, not semantic proof. const reviewedExpandableBlocks = new Map([ ["scripts/preprocess-smoke.sh", [ { sha256: "fc530dc721c946644ab6552bbd46b7918d6c5f11f06f3495b6ea1fcda819b38d", rationale: "Generates the reviewed preprocess Compose override." }, ]], ["scripts/test-dwh-auth-nginx-integration.sh", [ { sha256: "ead57234ad3520b5c7d4262b772957cbc7b9589da4f35fb17b160f948eb2ac7b", rationale: "Generates the reviewed isolated Nginx integration configuration." }, ]], ["scripts/test-install-tht.sh", [ { sha256: "37f18ce7ce93cb8b84f3b3708462cc16d50fdc7bab22836c382dbacf8382f05f", rationale: "Generates the reviewed synthetic tht installer artifact." }, ]], ["scripts/test-server-pi-state-topology.sh", [ { sha256: "a9ab86c9408b22afb87f10f615570bc7ec09bc3e7eb8131f6d835afba9a6b1d8", rationale: "Generates the isolated server topology test environment, including its authentication configuration root." }, ]], ["scripts/test-vector-backup-restore-safety.sh", [ { sha256: "40b8a10a3c06aaa98e324fbf688b7d1f5cead330d7ba7eef98e06256d412a85a", rationale: "Generates the reviewed restore safety manifest." }, ]], ["scripts/test-windows-clone-contract.ps1", [ { sha256: "3204f772d33cad42bcac99191507051aefb2c91d2935bec6698b956e44f9bf45", rationale: "Generates reviewed Windows clone test configuration with its authentication configuration root." }, { sha256: "f4814d842a7502b7ef30fd6b224d5cb17b0ffd6fb2367c41c49ac16587536d93", rationale: "Same reviewed block in the repository-required CRLF checkout representation." }, { sha256: "6f25ce3b58cea47b74fe9319ed917d8089a2fb334bc0d469daa7e1f10865d870", rationale: "Generates the reviewed Windows Compose override for the canonical service topology." }, { sha256: "45a3cf19f7ce697b858b63d27a4edc7fefa2414d0408e7b6d72a65c86d314f5b", rationale: "Same reviewed Compose override in the repository-required CRLF checkout representation." }, { sha256: "5d0d1a3fc45e99b3aacaf4ee5dd09a6bee1937784375dfe4bcfaa4ae32cfb9de", rationale: "Generates reviewed Windows clone test configuration." }, { sha256: "b903e5dae953ae1372f1a5276f12a92ed3dd632b897f3afe5e00c646d90a1b42", rationale: "Same reviewed block in the repository-required CRLF checkout representation." }, ]], ["scripts/unified-deployment-smoke.sh", [ { sha256: "1d60bf140165a8fabfa0c3729e776136904717e67becf3e0ab68c70d8e37847e", rationale: "Generates reviewed Task 13 runtime configuration." }, { sha256: "36d3d8a2362dbdc4fad90948d6c227586d749f56b9a4bc5b6b5a91bcbec6407b", rationale: "Generates the reviewed local Task 13 Compose override." }, { sha256: "c556f7d910d0788e219b042957e6b307cb9925b43920c680535d0d3a6dcbdb25", rationale: "Generates the reviewed local Task 13 installation descriptor." }, { sha256: "526006fa6d48a8080b3834723630c64de5005a67243e944ebf1da15212b4d654", rationale: "Generates the reviewed server Task 13 Compose override." }, { sha256: "c57ae2205c21ead0c2015a353aaabb948fa4ddd9b78a2cdcdb71f48cf2db742d", rationale: "Generates the reviewed projected-auth server Task 13 installation descriptor." }, ]], ["scripts/vector-backup.sh", [ { sha256: "571899db49dfdcec8107fbe1e0a86a61e7581979d3c4c248c20546843e275bcf", rationale: "Generates the reviewed backup manifest inside the helper command." }, ]], ["scripts/vector-restore.sh", [ { sha256: "f04d872e556a7323583c6e620b25814fb6a8e2568a9a555623978185b473a49d", rationale: "Feeds reviewed parsed manifest values to read loops." }, { sha256: "c6053ed44abae71ae4821b68f9a513f8070947350e30d89ae0f65bf4a48f66fd", rationale: "Feeds reviewed parsed manifest values to read loops." }, ]], ]); function blockDigest(rawBlock) { return createHash("sha256").update(rawBlock, "utf8").digest("hex"); } function reviewedExpandableBlock(path, rawBlock) { const digest = blockDigest(rawBlock); return (reviewedExpandableBlocks.get(path) ?? []).some((review) => review.sha256 === digest); } function hasAmbiguousExpansion(source, path) { const powershell = path.endsWith(".ps1"); for (let index = 0; index < source.length; index += 1) { const character = source[index]; if (powershell && character === "`") { index += 1; continue; } if (!powershell && character === "\\") { index += 1; continue; } if (character === "$" || (!powershell && character === "`")) return true; } return false; } function physicalLines(source) { const rawLines = source.match(/[^\n]*\n|[^\n]+$/gu) ?? []; if (rawLines.length === 0) rawLines.push(""); return rawLines.map((raw) => ({ raw, text: raw.replace(/\n$/u, "").replace(/\r$/u, "") })); } const prescribedSymbols = [ "WorkspaceV1", "WorkspaceV2", "DeprecatedV2Descriptor", "LegacyMigrationResult", "LegacyMigrationOptions", "WorkspaceV2MigrationInput", "migrateLegacyWorkspace", "writeMigratedWorkspace", "migrateWorkspaceV1ToV2", "migrateWorkspaceV2ToV3", ]; const migrationMarkers = ["migration_required", "deprecated-v2-descriptor", "migrate-legacy", "migrate-v2-qdrant"]; function isPolicyImplementationException(label, category) { const implementations = new Set([ "scripts/verify-schema-v3-only.sh", "scripts/test-verify-schema-v3-only.sh", "backend/scripts/verify-workspace-descriptor-files.mjs", "backend/scripts/verify-workspace-descriptor-files.test.mjs", "backend/scripts/revision-state-policy.mjs", "backend/scripts/revision-state-policy.test.mjs", "backend/scripts/bash-heredoc.mjs", "backend/scripts/revision_state_policy.py", "backend/scripts/test_revision_state_policy.py", ]); if (implementations.has(label)) return true; if (category === "migration-marker" && new Set([ "scripts/workspace_descriptor_doc_contract.py", "scripts/test_workspace_descriptor_doc_contract.py", "backend/scripts/clean-dist.test.mjs", ]).has(label)) return true; return false; } function validatePolicySource(source, label) { if (!isPolicyImplementationException(label, "prescribed-symbol")) { for (const symbol of prescribedSymbols) { if (source.toLowerCase().includes(symbol.toLowerCase())) throw new Error(`${label}: forbidden prescribed-symbol substring: ${symbol}`); } } if (!isPolicyImplementationException(label, "migration-marker")) { for (const marker of migrationMarkers) { if (source.toLowerCase().includes(marker.toLowerCase())) throw new Error(`${label}: forbidden migration-marker substring: ${marker}`); } } if (!isPolicyImplementationException(label, "legacy-workspace")) { for (const match of source.matchAll(/legacyworkspace/giu)) { if (match[0] !== "legacyWorkspace") throw new Error(`${label}: forbidden legacy-workspace spelling: ${match[0]}`); } } if (!/\.pyw?$/iu.test(label) && !isPolicyImplementationException(label, "revision-state")) validateRevisionState(source, label); } function documentShape(document) { const shape = { workspacePresent: false, workspaceMapping: false }; if (!isMap(document.contents)) return shape; for (const pair of document.contents.items) { if (!isScalar(pair.key)) continue; if (pair.key.value === "workspace") { shape.workspacePresent = true; if (isMap(pair.value)) shape.workspaceMapping = true; } } return shape; } function documents(source) { try { return parseAllDocuments(source, { uniqueKeys: true }); } catch (error) { throw new Error(`YAML parser failed: ${error instanceof Error ? error.message : String(error)}`); } } function validateWorkspaceSource(source, label, { requireWorkspace, expandable = false, path, rawBlock }) { const parsed = documents(source); const shapes = parsed.map(documentShape); if (requireWorkspace) { if (!shapes.some((shape) => shape.workspacePresent)) { throw new Error(`${label}: expected a top-level workspace mapping`); } if (!shapes.some((shape) => shape.workspaceMapping)) { throw new Error(`${label}: top-level workspace must be a mapping`); } } else { if (expandable && hasAmbiguousExpansion(source, path) && !reviewedExpandableBlock(path, rawBlock)) { throw new Error(`${label}: expandable block interpolation is not in the exact-content reviewed allowlist`); } if (shapes.some((shape) => shape.workspaceMapping)) { throw new Error(`${label}: embedded workspace descriptor is forbidden; use a tracked workspace fixture`); } return false; } try { parseWorkspaceYaml(source); } catch (error) { throw new Error(`${label}: workspace descriptor is not valid schema v3: ${error instanceof Error ? error.message : String(error)}`); } return true; } function deploymentScriptDialect(path) { if (path.endsWith(".sh")) return "bash"; if (path.endsWith(".ps1")) return "powershell"; throw new Error(`${path}: unknown deployment script dialect`); } function powerShellHereStringOpener(line, state) { let quote = null; for (let index = 0; index < line.length; index += 1) { if (state.blockComment) { const close = line.indexOf("#>", index); if (close < 0) return null; state.blockComment = false; index = close + 1; continue; } const character = line[index]; if (quote === null && character === "`") { index += 1; continue; } if (quote === "'") { if (character === "'" && line[index + 1] === "'") index += 1; else if (character === "'") quote = null; continue; } if (quote === '"') { if (character === "`") index += 1; else if (character === '"') quote = null; continue; } if (character === "#") return null; if (character === "<" && line[index + 1] === "#") { state.blockComment = true; index += 1; continue; } if (character === "@" && (line[index + 1] === "'" || line[index + 1] === '"') && /^[ \t]*$/u.test(line.slice(index + 2))) return line[index + 1]; if (character === "'" || character === '"') quote = character; } return null; } function extractPowerShellDocuments(source, label) { const records = physicalLines(source); const lines = records.map((record) => record.text); const extracted = []; const state = { blockComment: false }; for (let index = 0; index < lines.length; index += 1) { const quote = powerShellHereStringOpener(lines[index], state); if (quote === null) continue; const delimiter = `${quote}@`; const opener = index; const body = []; const start = index + 2; let closed = false; for (index += 1; index < lines.length; index += 1) { if (lines[index].trimEnd() === delimiter) { closed = true; break; } body.push(lines[index]); } extracted.push({ source: `${body.join("\n")}\n`, label: `${label}:${start} PowerShell here-string${closed ? "" : " (unclosed)"}`, expandable: quote === '"', path: label, rawBlock: records.slice(opener, Math.min(index + 1, records.length)).map((record) => record.raw).join(""), }); } return extracted; } export function extractScriptDocuments(source, label = "deployment script") { const dialect = deploymentScriptDialect(label); if (dialect === "bash") return extractBashDocuments(source, label); return extractPowerShellDocuments(source, label); } async function safeFile(root, path) { if (typeof path !== "string" || path.length === 0 || isAbsolute(path) || path.includes("\\")) { throw new Error(`unsafe verifier path: ${JSON.stringify(path)}`); } const segments = path.split("/"); if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) { throw new Error(`unsafe verifier path: ${JSON.stringify(path)}`); } const absolute = resolve(root, ...segments); const fromRoot = relative(root, absolute); if (fromRoot.startsWith(`..${sep}`) || fromRoot === ".." || isAbsolute(fromRoot)) { throw new Error(`verifier path escapes root: ${JSON.stringify(path)}`); } const entry = await lstat(absolute); if (!entry.isFile() || entry.isSymbolicLink()) { throw new Error(`verifier input is not a regular file: ${path}`); } const canonical = await realpath(absolute); const canonicalRelative = relative(root, canonical); if (canonicalRelative.startsWith(`..${sep}`) || canonicalRelative === ".." || isAbsolute(canonicalRelative)) { throw new Error(`verifier input resolves outside root: ${path}`); } return absolute; } export async function verifyEntries({ root, entries }) { const canonicalRoot = await realpath(root); const seen = new Set(); const pythonPolicies = []; for (const entry of entries) { if (!entry || !allowedKinds.has(entry.kind) || typeof entry.path !== "string") { throw new Error("workspace verifier manifest contains an invalid entry"); } const identity = `${entry.kind}\0${entry.path}`; if (seen.has(identity)) throw new Error(`workspace verifier manifest duplicates: ${entry.path}`); seen.add(identity); const absolute = await safeFile(canonicalRoot, entry.path); const bytes = await readFile(absolute); let source; try { source = new TextDecoder("utf-8", { fatal: true }).decode(bytes); } catch { throw new Error(`${entry.path}: input is not valid UTF-8`); } if (source.includes("\0")) throw new Error(`${entry.path}: NUL byte is forbidden`); if (entry.kind === "policy_text") { validatePolicySource(source, entry.path); if (/\.pyw?$/iu.test(entry.path) && !isPolicyImplementationException(entry.path, "revision-state")) { pythonPolicies.push({ label: entry.path, source }); } continue; } if (entry.kind === "workspace_descriptor") { validateWorkspaceSource(source, entry.path, { requireWorkspace: true }); continue; } for (const candidate of extractScriptDocuments(source, entry.path)) { validateWorkspaceSource(candidate.source, candidate.label, { requireWorkspace: false, expandable: candidate.expandable, path: entry.path, rawBlock: candidate.rawBlock, }); } } validatePythonRevisionStates(pythonPolicies); } export function decodeManifest(bytes) { const fields = bytes.toString("utf8").split("\0"); if (fields.at(-1) !== "") throw new Error("workspace verifier manifest is not NUL-terminated"); fields.pop(); if (fields.length % 2 !== 0) throw new Error("workspace verifier manifest has an incomplete record"); const entries = []; for (let index = 0; index < fields.length; index += 2) { entries.push({ kind: fields[index], path: fields[index + 1] }); } return entries; } function cliArguments(argv) { let root; let manifest; for (let index = 0; index < argv.length; index += 1) { const option = argv[index]; const value = argv[index + 1]; if ((option === "--root" || option === "--manifest") && value !== undefined) { if (option === "--root" && root === undefined) root = value; else if (option === "--manifest" && manifest === undefined) manifest = value; else throw new Error(`duplicate or invalid option: ${option}`); index += 1; } else { throw new Error(`unknown or incomplete option: ${option}`); } } if (root === undefined || manifest === undefined) { throw new Error("usage: verify-workspace-descriptor-files.mjs --root ROOT --manifest NUL_FILE"); } return { root, manifest }; } async function main(argv) { const { root, manifest } = cliArguments(argv); const manifestEntry = await lstat(manifest); if (!manifestEntry.isFile() || manifestEntry.isSymbolicLink()) { throw new Error("workspace verifier manifest is not a regular file"); } const entries = decodeManifest(await readFile(manifest)); await verifyEntries({ root, entries }); } if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { main(process.argv.slice(2)).catch((error) => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; }); }