From e422317cce1f3f4675be42006ce661ee1c0edaa3 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Mon, 10 Aug 2026 13:42:48 +0800 Subject: [PATCH] fix(qa): record blocked SSH evidence (#121011) Extracted from #120588 at 2d0fdeb61fa06f9fa97b9626bb5a2f9016e45202. --- qa/scenarios/runtime/gateway-ssh-tunnels.yaml | 1 + .../runtime/gateway-ssh-tunnels.test.ts | 29 +++++++++---------- .../e2e/qa-lab/runtime/gateway-ssh-tunnels.ts | 18 +++++++----- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/qa/scenarios/runtime/gateway-ssh-tunnels.yaml b/qa/scenarios/runtime/gateway-ssh-tunnels.yaml index 0394042eeca7..c3a87ec72ae1 100644 --- a/qa/scenarios/runtime/gateway-ssh-tunnels.yaml +++ b/qa/scenarios/runtime/gateway-ssh-tunnels.yaml @@ -24,6 +24,7 @@ scenario: - src/commands/gateway-status/probe-run.ts - test/e2e/qa-lab/runtime/gateway-ssh-tunnels.ts execution: + allowBlockedEvidence: true kind: script parallelSafe: true path: test/e2e/qa-lab/runtime/gateway-ssh-tunnels.ts diff --git a/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.test.ts b/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.test.ts index 649f0b7eb4c6..c92cc8687346 100644 --- a/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.test.ts +++ b/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.test.ts @@ -46,6 +46,20 @@ const evidence = await runGatewaySshTunnels({ process.exitCode = evidence.entries[0]?.result.status === "pass" ? 0 : 1; `; +describe("Gateway SSH tunnel QA preflight", () => { + it("records blocked evidence outside Testbox without privileged setup", async () => { + const artifactBase = tempDirs.make("openclaw-gateway-ssh-guard-"); + const evidence = await withEnvAsync({ OPENCLAW_TESTBOX: undefined }, async () => + runGatewaySshTunnels({ artifactBase, repoRoot: process.cwd() }), + ); + + expect(evidence.entries[0]?.result).toMatchObject({ status: "blocked" }); + await expect(fs.access(path.join(artifactBase, ".ssh-namespace"))).rejects.toMatchObject({ + code: "ENOENT", + }); + }); +}); + async function terminateChild(child: ChildProcessWithoutNullStreams) { if (child.exitCode !== null || child.signalCode !== null) { return; @@ -155,21 +169,6 @@ async function readOptionalFile(filePath: string) { } describeOnTestbox("Gateway SSH tunnel QA producer", () => { - it("rejects privileged setup outside Testbox", async () => { - const artifactBase = tempDirs.make("openclaw-gateway-ssh-guard-"); - await withEnvAsync({ OPENCLAW_TESTBOX: undefined }, async () => { - await expect( - runGatewaySshTunnels({ - artifactBase, - repoRoot: process.cwd(), - }), - ).rejects.toThrow("requires OPENCLAW_TESTBOX=1 before privileged setup"); - }); - await expect(fs.access(path.join(artifactBase, ".ssh-namespace"))).rejects.toMatchObject({ - code: "ENOENT", - }); - }); - it("proves real forwarding, cleanup, and operator diagnostics", async () => { const artifactBase = tempDirs.make("openclaw-gateway-ssh-evidence-"); const gatewayStartupEnv = snapshotGatewayStartupEnv(); diff --git a/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.ts b/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.ts index bcfce2ed4665..b377b1a25c66 100644 --- a/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.ts +++ b/test/e2e/qa-lab/runtime/gateway-ssh-tunnels.ts @@ -514,12 +514,6 @@ function sanitizeDiagnostic(text: string, roots: readonly string[]) { export async function runGatewaySshTunnels( options: ProducerOptions, ): Promise { - if (process.env.OPENCLAW_TESTBOX !== "1") { - throw new Error("Gateway SSH tunnel QA requires OPENCLAW_TESTBOX=1 before privileged setup"); - } - if (process.env[SSH_NAMESPACE_MARKER] !== "1") { - return await runInSshNamespace(options); - } await fs.mkdir(options.artifactBase, { recursive: true }); const writer = createQaScriptEvidenceWriter({ artifactBase: options.artifactBase, @@ -539,6 +533,16 @@ export async function runGatewaySshTunnels( ], }, }); + if (process.env.OPENCLAW_TESTBOX !== "1") { + return await writer.write({ + details: "Gateway SSH tunnel QA requires OPENCLAW_TESTBOX=1 before privileged setup", + durationMs: 1, + status: "blocked", + }); + } + if (process.env[SSH_NAMESPACE_MARKER] !== "1") { + return await runInSshNamespace(options); + } const startedAt = Date.now(); // openclaw-temp-dir: normal runs remove the fixture root; the SIGKILL test tracks its injected root const root = @@ -714,7 +718,7 @@ async function main(argv: readonly string[]) { const status = evidence.entries[0]?.result.status; process.stdout.write(`Gateway SSH tunnel evidence: ${QA_EVIDENCE_FILENAME}\n`); process.stdout.write(`Gateway SSH tunnel status: ${status}\n`); - return status === "pass" ? 0 : 1; + return status === "pass" || status === "blocked" ? 0 : 1; } if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {