import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { M3_TRUSTED_CHAIN, createHardwareEvidencePanelModel, defaultHardwareEvidencePanelData, hardwareEvidencePanelSourceLegend, renderHardwareEvidencePanel } from "../workbench-hardware-panel.mjs"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const panelPath = path.resolve(rootDir, "workbench-hardware-panel.mjs"); const panelSource = fs.readFileSync(panelPath, "utf8"); const REQUIRED_SOURCE_KINDS = Object.freeze(["SOURCE", "DRY-RUN", "DEV-LIVE", "BLOCKED"]); const FORBIDDEN_MUTATION_PATTERNS = Object.freeze([ /hardware\.operation\.request/u, /callRpc\(\s*["']hardware\./u, /hardware\.invoke\.shell/u, /audit\.event\.write/u, /evidence\.record\.write/u, /\/wiring\/apply/u, /\/wiring\/reload/u, /fetch\(/u, /XMLHttpRequest/u, /sendBeacon/u ]); export function runWorkbenchHardwarePanelContract() { assert.equal(typeof renderHardwareEvidencePanel, "function", "renderer export must exist"); assert.equal(typeof createHardwareEvidencePanelModel, "function", "model export must exist"); assert.deepEqual(M3_TRUSTED_CHAIN, { fromResourceId: "res_boxsimu_1", fromPort: "DO1", patchPanelServiceId: "hwlab-patch-panel", toResourceId: "res_boxsimu_2", toPort: "DI1" }); const sourceKinds = hardwareEvidencePanelSourceLegend.map((item) => item.sourceKind); assert.deepEqual(sourceKinds, REQUIRED_SOURCE_KINDS, "panel must expose SOURCE/DRY-RUN/DEV-LIVE/BLOCKED tags"); for (const sourceKind of REQUIRED_SOURCE_KINDS) { assert.match(panelSource, new RegExp(`["']${sourceKind}["']`, "u"), `${sourceKind} label must be rendered by source`); } const blockedModel = createHardwareEvidencePanelModel(defaultHardwareEvidencePanelData); assert.equal(blockedModel.trustedLoop.status, "blocked", "default model must stay blocked without DEV-LIVE evidence"); assert.equal(blockedModel.trustedLoop.tone, "degraded", "default model must render degraded, not green"); assert.equal(blockedModel.sourceKind, "BLOCKED", "missing DEV-LIVE evidence must force BLOCKED source kind"); assert.equal(blockedModel.chain.fromResourceId, "res_boxsimu_1"); assert.equal(blockedModel.chain.fromPort, "DO1"); assert.equal(blockedModel.chain.patchPanelServiceId, "hwlab-patch-panel"); assert.equal(blockedModel.chain.toResourceId, "res_boxsimu_2"); assert.equal(blockedModel.chain.toPort, "DI1"); assert.match(blockedModel.chain.detail, /BLOCKED/u); assert.match(blockedModel.chain.detail, /runtime\.durable=false/u); assert.equal(blockedModel.trustedLoop.runtimeDurability.ready, false); assert.ok( blockedModel.statuses.some((item) => item.kind === "BOX-SIMU" && item.id === "res_boxsimu_1"), "BOX-SIMU source status must be present" ); assert.ok( blockedModel.statuses.some((item) => item.kind === "Gateway-SIMU"), "Gateway-SIMU status must be present" ); assert.ok( blockedModel.statuses.some((item) => item.kind === "Patch Panel" && item.id === "hwlab-patch-panel"), "Patch Panel status must be present" ); assert.ok(blockedModel.records.operations.length >= 1, "operation summary must render"); assert.ok(blockedModel.records.audit.length >= 1, "audit summary must render"); assert.ok(blockedModel.records.evidence.length >= 1, "evidence summary must render"); assert.ok( blockedModel.records.evidence.some((record) => record.sourceKind === "DRY-RUN"), "fixture evidence must stay DRY-RUN labeled" ); assert.ok(blockedModel.controls.length >= 1, "placeholder controls must exist"); for (const control of blockedModel.controls) { assert.equal(control.disabled, true, `${control.id} must be disabled`); assert.match(control.reason, /not wired \/ readonly \/ waiting for DEV-LIVE M3 loop/u); } const misleadingGreenModel = createHardwareEvidencePanelModel({ statuses: [ { id: "res_boxsimu_1", label: "BOX-SIMU 1", kind: "BOX-SIMU", status: "healthy", sourceKind: "SOURCE" } ], chain: { ...M3_TRUSTED_CHAIN, status: "healthy", sourceKind: "SOURCE" }, records: { operations: [], audit: [], evidence: [] }, controls: [] }); assert.equal(misleadingGreenModel.trustedLoop.status, "blocked", "green-looking source data cannot promote M3"); assert.equal(misleadingGreenModel.chain.status, "blocked", "chain must be blocked without DEV-LIVE evidence"); assert.notEqual(misleadingGreenModel.statuses[0].status, "healthy", "healthy source-only status must be downgraded"); const devLiveEvidenceWithMemoryRuntime = { chain: { ...M3_TRUSTED_CHAIN, status: "verified", sourceKind: "DEV-LIVE", detail: "DEV-LIVE M3 loop observed and attached." }, records: { operations: [ { id: "op_m3_dev_live_readonly_summary", status: "succeeded", sourceKind: "DEV-LIVE", summary: "Existing trusted operation summary only." } ], audit: [ { id: "aud_m3_dev_live_readonly_summary", status: "recorded", sourceKind: "DEV-LIVE", summary: "Existing trusted audit summary only." } ], evidence: [ { id: "evi_m3_dev_live_loop", status: "verified", sourceKind: "DEV-LIVE", summary: "Trusted M3 loop evidence is already recorded." } ] } }; const nonDurableModel = createHardwareEvidencePanelModel(devLiveEvidenceWithMemoryRuntime); assert.equal(nonDurableModel.trustedLoop.status, "blocked", "DEV-LIVE-looking records cannot promote without durable runtime"); assert.equal(nonDurableModel.sourceKind, "BLOCKED"); assert.match(nonDurableModel.trustedLoop.reason, /runtime\.durable=false/u); const trustedModel = createHardwareEvidencePanelModel({ ...devLiveEvidenceWithMemoryRuntime, runtime: { adapter: "postgres", durable: true, ready: true, status: "ready", liveRuntimeEvidence: true }, controls: [ { id: "dev-live-safe-placeholder", label: "Readonly", disabled: false, reason: "" } ] }); assert.equal(trustedModel.trustedLoop.status, "verified", "DEV-LIVE evidence plus exact chain can promote M3"); assert.equal(trustedModel.sourceKind, "DEV-LIVE"); assert.equal(trustedModel.controls[0].disabled, true, "controls must remain disabled even with DEV-LIVE evidence"); assert.match(trustedModel.controls[0].reason, /not wired \/ readonly \/ waiting for DEV-LIVE M3 loop/u); const dom = createFakeDom(); const rendered = renderHardwareEvidencePanel(dom.container, defaultHardwareEvidencePanelData); assert.equal(rendered.model.sourceKind, "BLOCKED", "renderer must use guarded model"); assert.equal(dom.container.children.length, 1, "renderer must replace the container with one panel root"); assert.equal(dom.container.children[0].dataset.sourceKind, "BLOCKED", "rendered panel must expose sourceKind"); const buttons = dom.container.querySelectorAll("button"); assert.equal(buttons.length, blockedModel.controls.length, "renderer must include all placeholder controls"); for (const button of buttons) { assert.equal(button.disabled, true, "rendered placeholder controls must be disabled"); } for (const pattern of FORBIDDEN_MUTATION_PATTERNS) { assert.doesNotMatch(panelSource, pattern, `panel must not include mutation or network path ${pattern}`); } } function createFakeDom() { const document = { createElement(tagName) { return new FakeElement(tagName, document); } }; return { document, container: new FakeElement("div", document) }; } class FakeElement { constructor(tagName, ownerDocument) { this.tagName = tagName.toUpperCase(); this.ownerDocument = ownerDocument; this.children = []; this.dataset = {}; this.attributes = {}; this.className = ""; this.disabled = false; this.textContent = ""; this.type = ""; } append(...children) { this.children.push(...children); } replaceChildren(...children) { this.children = children; } setAttribute(name, value) { this.attributes[name] = String(value); } querySelectorAll(tagName) { const normalizedTagName = tagName.toUpperCase(); const matches = []; for (const child of this.children) { if (child.tagName === normalizedTagName) { matches.push(child); } matches.push(...child.querySelectorAll(tagName)); } return matches; } } if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) { runWorkbenchHardwarePanelContract(); console.log("Workbench hardware evidence panel contract passed"); }