Files
pom-omp/scripts/release-manifest.mjs
Antigravity 7b714bfc6b fix: make audit gates evidence-backed and correct stale check-count claims
- wire npm audit (prod + full dev tree) through readGate instead of hardcoded NOT RUN reasons
- record real results: production 0 vulns PASS; dev tree 16 dev-only advisories FAIL, disclosed with reach and remediation
- docs/VERIFICATION.md: six checks -> seven, add package-metadata section and mutation row, record executed row-7 proof
- README/SETTINGS: replace six-gate wording with the actual gate ledger
2026-08-19 11:40:18 +02:00

119 lines
4.7 KiB
JavaScript

import { createHash } from "node:crypto";
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
import { join, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
function walk(path) {
if (!existsSync(path)) throw new Error(`Missing packaged path: ${relative(root, path)}`);
if (statSync(path).isFile()) return [path];
return readdirSync(path, { withFileTypes: true }).flatMap((entry) => walk(join(path, entry.name)));
}
const candidates = packageJson.files
.filter((item) => item !== "RELEASE.json")
.flatMap((item) => walk(join(root, item)));
candidates.push(join(root, "package.json"));
const sourceInventory = [...new Set(candidates)]
.sort()
.map((path) => {
const data = readFileSync(path);
return {
path: relative(root, path).replaceAll("\\", "/"),
bytes: data.length,
sha256: createHash("sha256").update(data).digest("hex"),
};
});
function readGate(file, gate) {
const path = join(root, file);
if (!existsSync(path)) return { status: "NOT RUN", reason: `Missing evidence file: ${file}` };
try {
const data = JSON.parse(readFileSync(path, "utf8"));
const passed = data.passed === true || (data.summary && data.summary.passed === true);
return {
status: passed ? "PASS" : "FAIL",
timestamp: data.timestamp || null,
scope: data.scope || gate,
command: data.command || null,
details: data,
};
} catch {
return { status: "NOT RUN", reason: `Unparsable evidence: ${file}` };
}
}
const gates = {
typescript: readGate("00_admin/validation/typecheck.json", "tsc --noEmit"),
behavioralTests: readGate("00_admin/validation/tests.json", "npm test"),
runtimeSmoke: readGate("00_admin/validation/smoke.json", "npm run smoke"),
structuralVerification: readGate("00_admin/validation/structural.json", "node scripts/verify.mjs"),
themeSchemaValidation: readGate("00_admin/validation/theme.json", "theme schema validation"),
npmPackDryRun: readGate("00_admin/validation/pack.json", "npm pack --dry-run"),
productionDependencyAudit: readGate("00_admin/validation/audit-prod.json", "npm audit --omit=dev"),
fullDevelopmentTreeAudit: readGate("00_admin/validation/audit-dev.json", "npm audit"),
};
const releaseDate = new Date().toISOString().split("T")[0];
const release = {
name: "POM — Produce Magnum Opus",
package: packageJson.name,
version: packageJson.version,
schemaVersion: "2.0.0",
releaseDate,
status: "release-candidate",
summary: "OMP-native production kernel with evidence-gated stages, native task/IRC delegation, optional Swarm DAGs, Obsidian/Quartz knowledge projection, cinematic TUI hooks, and verified archive delivery.",
compatibility: {
bun: packageJson.engines.bun,
ompPackages: ">=16.4.6 <17",
module: "ESM",
},
inventory: {
stages: 9,
customTools: 7,
agents: 14,
prompts: 13,
rules: 3,
themes: 2,
behavioralTests: 9,
sourceFilesHashed: sourceInventory.length,
sourceBytesHashed: sourceInventory.reduce((sum, item) => sum + item.bytes, 0),
selfHashPolicy: "RELEASE.json is excluded from its own source inventory; final package and archive hashes are recorded externally.",
},
verification: {
typescript: gates.typescript,
behavioralTests: gates.behavioralTests,
runtimeSmoke: gates.runtimeSmoke,
structuralVerification: gates.structuralVerification,
themeSchemaValidation: gates.themeSchemaValidation,
npmPackDryRun: gates.npmPackDryRun,
productionDependencyAudit: gates.productionDependencyAudit,
fullDevelopmentTreeAudit: gates.fullDevelopmentTreeAudit,
ompPluginDoctor: { status: "NOT RUN", reason: "Requires Bun + OMP installation" },
interactiveTuiSmoke: { status: "NOT RUN", reason: "Requires a live OMP terminal host" },
},
releaseGates: [
"Run npm run verify",
"Run npm run doctor in a Bun + OMP installation",
"Open /pom and verify the overlay, HUD, status, cards, and /pom theme install",
"Create a smoke project, validate stage 0, and verify a checkpoint archive",
],
sourceInventory,
};
const rendered = `${JSON.stringify(release, null, 2)}\n`;
const output = join(root, "RELEASE.json");
if (process.argv.includes("--check")) {
if (!existsSync(output) || readFileSync(output, "utf8") !== rendered) {
console.error("RELEASE.json is stale; run npm run release:manifest");
process.exit(1);
}
console.log("POM release manifest PASS");
} else {
writeFileSync(output, rendered);
console.log(`Wrote RELEASE.json · ${sourceInventory.length} files · ${release.inventory.sourceBytesHashed} bytes`);
}