import * as fs from "node:fs"; import * as path from "node:path"; import { loadFactoryCapabilities, type FactoryCapabilityService } from "./factory-capabilities.js"; import type { CyberPreflightReceipt } from "./cyber-preflight.js"; export interface CyberReconcileFinding { capability: string; expected: string; evidence: string; status: "ok" | "missing"; } export interface CyberReconcileReceipt { created_at: string; preflight: string; capabilities: string; findings: CyberReconcileFinding[]; decision: "allow_read_only" | "fail_closed"; deploy_allowed: false; recommendation: string; } export function reconcileCyberPreflight(preflightFile: string, capabilitiesFile: string, now = new Date()): CyberReconcileReceipt { const preflight = JSON.parse(fs.readFileSync(preflightFile, "utf-8")) as CyberPreflightReceipt; const capabilities = loadFactoryCapabilities(capabilitiesFile); const findings = capabilities.flatMap((service) => findingsForService(service, preflight)); const allOk = findings.every((finding) => finding.status === "ok") && preflight.decision === "allow_read_only"; return { created_at: now.toISOString(), preflight: preflightFile, capabilities: capabilitiesFile, findings, decision: allOk ? "allow_read_only" : "fail_closed", deploy_allowed: false, recommendation: allOk ? "read-only posture verified; deploy still requires separate approval" : "hold position; restore telemetry routes or update capability registry", }; } export function writeCyberReconcileReceipt(file: string, receipt: CyberReconcileReceipt): void { fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`); } function findingsForService(service: FactoryCapabilityService, preflight: CyberPreflightReceipt): CyberReconcileFinding[] { return service.provides.map((capability) => { const check = matchingCheck(capability, preflight); return { capability, expected: service.url, evidence: check ? `${check.name}: ${check.ok ? "ok" : `failed status=${check.status} ${check.stderr.trim()}`}` : "no matching preflight check", status: check?.ok ? "ok" : "missing", }; }); } function matchingCheck(capability: string, preflight: CyberPreflightReceipt) { if (capability === "deploy") return preflight.checks.find((check) => check.name === "deploy_route_health"); if (capability === "factory-status") return preflight.checks.find((check) => check.name === "git_proxy_factory_status"); if (capability === "discovery") return preflight.checks.find((check) => check.name === "git_proxy_health"); return undefined; }