import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { loadMvpGateSummary } from "../../../internal/mvp-gate/summary.mjs"; import { gateSummary } from "../gate-summary.mjs"; import { runCloudWebM3ReadonlyContract } from "./m3-readonly-contract.mjs"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const repoRoot = path.resolve(rootDir, "../.."); const requiredFiles = ["index.html", "styles.css", "app.mjs", "gate-summary.mjs", "runtime.mjs"]; for (const file of requiredFiles) { const filePath = path.resolve(rootDir, file); if (!fs.existsSync(filePath)) { throw new Error(`missing web asset: ${file}`); } } const html = fs.readFileSync(path.resolve(rootDir, "index.html"), "utf8"); const app = fs.readFileSync(path.resolve(rootDir, "app.mjs"), "utf8"); const artifactPublisher = fs.readFileSync(path.resolve(repoRoot, "scripts/dev-artifact-publish.mjs"), "utf8"); const frontendSource = `${html}\n${app}\n${artifactPublisher}`; assert.match(html, /HWLAB DEV Console/); assert.match(html, /M3 Diagnostics Console/); assert.match(html, /Read-only runtime observation/); for (const moduleName of [ "Overview", "Topology / Patch Panel", "M3 Evidence", "Agent Sessions", "Evidence / Audit", "Gate / Diagnostics" ]) { assert.match(html, new RegExp(moduleName.replaceAll("/", "\\/"))); } for (const viewId of ["overview", "topology", "hardware", "agents", "evidence", "gate"]) { assert.match(html, new RegExp(`data-view="${viewId}"`)); } assert.match(html, /live-status/); assert.match(html, /method-grid/); assert.match(html, /runtime-metrics/); assert.match(html, /operation-body/); assert.match(html, /audit-body/); assert.match(html, /evidence-body/); assert.match(app, /fetchJson\("\/v1"\)/); assert.match(app, /callRpc\("system\.health"\)/); assert.match(app, /callRpc\("cloud\.adapter\.describe"\)/); assert.match(app, /callRpc\("audit\.event\.query"/); assert.match(app, /callRpc\("evidence\.record\.query"/); assert.match(artifactPublisher, /HWLAB_API_BASE_URL/); assert.match(artifactPublisher, /readOnlyRpcMethods/); assert.match(artifactPublisher, /"system\.health"/); assert.match(artifactPublisher, /"cloud\.adapter\.describe"/); assert.match(artifactPublisher, /"audit\.event\.query"/); assert.match(artifactPublisher, /"evidence\.record\.query"/); assert.match(artifactPublisher, /readonly_rpc_required/); assert.match(app, /degraded/); assert.match(app, /runtime\.serviceRoute\.join\(" -> "\)/); assert.doesNotMatch(app, /callRpc\("hardware\./); assert.doesNotMatch(app, /hardware\.operation\.request/); assert.doesNotMatch(app, /hardware\.invoke\.shell/); assert.doesNotMatch(app, /audit\.event\.write/); assert.doesNotMatch(app, /evidence\.record\.write/); assert.doesNotMatch(frontendSource, /--live --confirm-dev --confirmed-non-production/); assert.doesNotMatch(frontendSource, /74\.48\.78\.17:666[67]\b|:666[67]\b/); const sourceSummary = loadMvpGateSummary(repoRoot); assert.equal(gateSummary.endpoint, sourceSummary.endpoint); assert.equal(gateSummary.gateStatus, sourceSummary.gateStatus); assert.equal(gateSummary.milestones.length, 6); assert.deepEqual( gateSummary.milestones.map((item) => item.id), ["M0", "M1", "M2", "M3", "M4", "M5"] ); assert.equal(gateSummary.artifactCount, 13); assert.equal(gateSummary.healthCount, 14); assert.equal(gateSummary.gatewaySessionCount, 2); assert.equal(gateSummary.boxResourceCount, 2); assert.equal(gateSummary.topology.patchPanel.serviceId, "hwlab-patch-panel"); assert.equal(gateSummary.agent.agentServiceId, "hwlab-agent-mgr"); assert.equal(gateSummary.agent.workerServiceId, "hwlab-agent-worker"); assert.equal(gateSummary.evidenceRecords.length, 2); assert.equal(gateSummary.safety.allowNetwork, false); runCloudWebM3ReadonlyContract(); console.log("hwlab-cloud-web check ok: read-only M3 diagnostics contract is present");