Files
pikasTech-HWLAB/web/hwlab-cloud-web/scripts/workbench-hardware-panel-contract.mjs
T
2026-05-22 23:38:18 +00:00

246 lines
8.7 KiB
JavaScript

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");
}