diff --git a/test/hermes-runtime-config-guard-topology.test.ts b/test/hermes-runtime-config-guard-topology.test.ts index 56a4afa51e1..bcc6966fd28 100644 --- a/test/hermes-runtime-config-guard-topology.test.ts +++ b/test/hermes-runtime-config-guard-topology.test.ts @@ -1,12 +1,13 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { spawnSync } from "node:child_process"; +import { execFileSync, spawnSync } from "node:child_process"; import { readFileSync } from "node:fs"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { dockerSpawnSync } from "../src/lib/adapters/docker/exec"; +import { isWsl } from "../src/lib/platform"; const RUNTIME_CONFIG_GUARD = path.join( import.meta.dirname, @@ -17,12 +18,19 @@ const RUNTIME_CONFIG_GUARD = path.join( ); const ROOT_RUNTIME_IMAGE = "python:3.12-slim@sha256:cab2dbf575e971934a81e4622f5aba17aa7929719bd7e31033a3a83b97fd0464"; -const ROOT_CONTAINER_RUNTIME_AVAILABLE = - process.platform === "linux" && - dockerSpawnSync(["info"], { - stdio: "ignore", - timeout: 15_000, - }).status === 0; +function dockerAvailable(): boolean { + try { + execFileSync("docker", ["info"], { stdio: "ignore", timeout: 15_000 }); + return true; + } catch { + return false; + } +} + +// WSL does not require Docker. Native Linux must attempt this security contract +// so a missing or broken Docker boundary fails the test. +const shouldAttemptRootContainerContract = + process.platform === "linux" && (!isWsl() || dockerAvailable()); const ROOT_CONTAINER_DRIVER = String.raw` import json import os @@ -512,7 +520,7 @@ print(json.dumps({ }); // source-shape-contract: security -- Executes the shipped guard as root to prove real Linux repair and rollback metadata - it.skipIf(!ROOT_CONTAINER_RUNTIME_AVAILABLE)( + it.skipIf(!shouldAttemptRootContainerContract)( "restores exact locked posture after root-separated repair and later failure (#7033)", () => { const result = runRootContainerHarness(`${loadGuardModule} @@ -633,9 +641,13 @@ with tempfile.TemporaryDirectory() as tmp: })) `); - expect(result.status, result.error?.message || String(result.stderr || result.stdout)).toBe( - 0, - ); + const failureDetails = [ + `status: ${String(result.status)}`, + `signal: ${String(result.signal)}`, + `spawn error: ${result.error ? String(result.error) : "none"}`, + `stderr: ${String(result.stderr)}`, + ].join("\n"); + expect(result.status, failureDetails).toBe(0); expect(JSON.parse(String(result.stdout))).toEqual({ aborting_state: "shields-transition-aborting", applied_state: "shields-transition-applied",