From c1a227d1843d76ffa87d42a42c5ae2221d059125 Mon Sep 17 00:00:00 2001 From: HWLAB Code Queue Date: Thu, 21 May 2026 16:54:27 +0000 Subject: [PATCH] chore: refresh dev gate preflight evidence --- docs/dev-gate-preflight.md | 2 + reports/dev-gate/dev-preflight-report.json | 59 +++++++++++++++++++--- scripts/src/dev-gate-preflight.mjs | 46 ++++++++++++++++- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/docs/dev-gate-preflight.md b/docs/dev-gate-preflight.md index 0e09ab64..2f151f73 100644 --- a/docs/dev-gate-preflight.md +++ b/docs/dev-gate-preflight.md @@ -48,6 +48,8 @@ The preflight checks: - `deploy/frp` and `deploy/master-edge` describe the D601-to-master DEV route on port `6667`. - The runner can perform read-only `kubectl` probes against `hwlab-dev`. +- `reports/dev-gate/dev-edge-health.json`, when present, records read-only + public edge, frps, tunnel-health, and k3s observability evidence. - `http://74.48.78.17:6667/health/live` responds. - GHCR manifests are visible without reading credentials. - Deploy images do not point at UniDesk, provider-gateway, or microservice-proxy diff --git a/reports/dev-gate/dev-preflight-report.json b/reports/dev-gate/dev-preflight-report.json index 222c41dd..c1069fb4 100644 --- a/reports/dev-gate/dev-preflight-report.json +++ b/reports/dev-gate/dev-preflight-report.json @@ -15,10 +15,10 @@ ], "target": { "ref": "origin/main", - "commitId": "eddfe3ba70db5725682cba2008b10a7a786bef92", - "shortCommitId": "eddfe3b" + "commitId": "6da6ab40bc356ddf6f2ebea11af935f4399e4945", + "shortCommitId": "6da6ab4" }, - "generatedAt": "2026-05-21T16:48:18.417Z", + "generatedAt": "2026-05-21T16:53:29.568Z", "mode": "read-only", "devOnly": true, "prodDisabled": true, @@ -51,7 +51,7 @@ "id": "target-commit-pinning", "category": "contract", "status": "blocked", - "summary": "deploy/catalog commitId 24eb3bf does not match origin/main eddfe3b.", + "summary": "deploy/catalog commitId 24eb3bf does not match origin/main 6da6ab4.", "evidence": [] }, { @@ -75,6 +75,46 @@ "summary": "DEV artifact publish report status is blocked with 9/13 published for source 1e8d009e9531d71cef0762998663b4e3731032c6.", "evidence": [] }, + { + "id": "dev-edge-health-report", + "category": "edge", + "status": "blocked", + "summary": "Committed DEV edge health report is blocked with classification frp_blocker.", + "evidence": [ + { + "report": "reports/dev-gate/dev-edge-health.json", + "status": "blocked", + "classification": "frp_blocker", + "publicTcp": [ + { + "host": "74.48.78.17", + "port": 6667, + "status": "error", + "code": "ECONNREFUSED", + "message": "connect ECONNREFUSED 74.48.78.17:6667", + "durationMs": 221 + }, + { + "host": "74.48.78.17", + "port": 7000, + "status": "error", + "code": "ECONNREFUSED", + "message": "connect ECONNREFUSED 74.48.78.17:7000", + "durationMs": 218 + }, + { + "host": "74.48.78.17", + "port": 7402, + "status": "error", + "code": "ECONNREFUSED", + "message": "connect ECONNREFUSED 74.48.78.17:7402", + "durationMs": 207 + } + ], + "kubernetesObservable": false + } + ] + }, { "id": "frp-master-edge-static", "category": "edge", @@ -254,7 +294,7 @@ "status": "open", "type": "contract_blocker", "scope": "deploy-target", - "summary": "deploy/deploy.json and deploy/artifact-catalog.dev.json still target 24eb3bf, not origin/main eddfe3b.", + "summary": "deploy/deploy.json and deploy/artifact-catalog.dev.json still target 24eb3bf, not origin/main 6da6ab4.", "nextTask": "Publish or select a DEV artifact set for the current origin/main commit and update deploy/deploy.json plus deploy/artifact-catalog.dev.json to that immutable commit/tag." }, { @@ -268,9 +308,16 @@ "status": "open", "type": "runtime_blocker", "scope": "dev-artifact-publish", - "summary": "reports/dev-gate/dev-artifacts.json does not prove all HWLAB service artifacts for origin/main eddfe3b; current status is blocked with 9/13 published.", + "summary": "reports/dev-gate/dev-artifacts.json does not prove all HWLAB service artifacts for origin/main 6da6ab4; current status is blocked with 9/13 published.", "nextTask": "Complete DEV artifact publishing for every frozen HWLAB service at the current origin/main commit and record immutable registry digests." }, + { + "status": "open", + "type": "network_blocker", + "scope": "dev-edge-health", + "summary": "public 6667 and frps control 7000 both refuse TCP connections; frps is not reachable on the master edge", + "nextTask": "Repair the master frps/public DEV edge route and rerun the read-only DEV edge health smoke before real deployment." + }, { "status": "open", "type": "environment_blocker", diff --git a/scripts/src/dev-gate-preflight.mjs b/scripts/src/dev-gate-preflight.mjs index 87791cdc..a3e7dfaf 100644 --- a/scripts/src/dev-gate-preflight.mjs +++ b/scripts/src/dev-gate-preflight.mjs @@ -247,7 +247,7 @@ function assertFrpStatic(frpc, frps, masterEdge) { assert.equal(frpc.serverAddr, "74.48.78.17"); assert.equal(frpc.serverPort, 7000); assert.equal(frps.bindPort, 7000); - assert.equal(frps.vhostHTTPPort, 6667); + assert.equal(Object.hasOwn(frps, "vhostHTTPPort"), false, "frps must not bind vhostHTTPPort because 6667 is reserved for the TCP proxy"); assert.ok(frpc.proxies.some((proxy) => proxy.name === "hwlab-dev-edge-proxy" && proxy.remotePort === 6667)); assert.ok(frps.allowPorts.some((port) => port.start === 6667 && port.end === 6667)); assert.equal(masterEdge.environment, ENVIRONMENT_DEV); @@ -272,7 +272,8 @@ async function loadContracts() { async function loadOptionalReports() { return { - artifactPublish: await readOptionalJson("reports/dev-gate/dev-artifacts.json") + artifactPublish: await readOptionalJson("reports/dev-gate/dev-artifacts.json"), + edgeHealth: await readOptionalJson("reports/dev-gate/dev-edge-health.json") }; } @@ -396,6 +397,46 @@ function validateArtifactPublishReport(reporter, artifactReport, targetShortComm }); } +function validateEdgeHealthReport(reporter, edgeReport) { + if (!edgeReport) { + reporter.check("dev-edge-health-report", "edge", "blocked", "No DEV edge health report is present."); + reporter.block({ + type: "network_blocker", + scope: "dev-edge-health-report", + summary: "reports/dev-gate/dev-edge-health.json is missing, so the preflight has no committed edge/frp health evidence.", + nextTask: "Run the read-only DEV edge health smoke and commit reports/dev-gate/dev-edge-health.json before real deployment." + }); + return; + } + + const edgeHealth = edgeReport.edgeHealth; + const pass = edgeReport.status === "pass" && edgeHealth?.status === "pass"; + const evidence = [ + { + report: "reports/dev-gate/dev-edge-health.json", + status: edgeReport.status, + classification: edgeHealth?.classification ?? "unknown", + publicTcp: edgeHealth?.publicTcp ?? [], + kubernetesObservable: edgeHealth?.kubernetes?.observable ?? false + } + ]; + + if (pass) { + reporter.check("dev-edge-health-report", "edge", "pass", "Committed DEV edge health report shows public edge health passing.", evidence); + return; + } + + const classification = edgeHealth?.classification ?? "unknown"; + const summary = edgeHealth?.blocker ?? edgeReport.devPreconditions?.summary ?? "DEV edge health report is not passing."; + reporter.check("dev-edge-health-report", "edge", "blocked", `Committed DEV edge health report is ${edgeReport.status} with classification ${classification}.`, evidence); + reporter.block({ + type: "network_blocker", + scope: "dev-edge-health", + summary, + nextTask: "Repair the master frps/public DEV edge route and rerun the read-only DEV edge health smoke before real deployment." + }); +} + async function validateEdgeContracts(reporter, masterEdge) { try { const [frpc, frps] = await Promise.all([ @@ -594,6 +635,7 @@ export async function runPreflight(argv) { ); validateArtifactPublishReport(reporter, optionalReports.artifactPublish, targetShortCommit, targetCommit, args.targetRef); + validateEdgeHealthReport(reporter, optionalReports.edgeHealth); await validateEdgeContracts(reporter, masterEdge); validateRuntimeBoundary(reporter, deploy); await validateLiveProbes(reporter, catalog, args.timeoutMs);