From 58920612fe0180fa116707442e73b4b94fb05db1 Mon Sep 17 00:00:00 2001 From: Aaron Erickson Date: Wed, 5 Aug 2026 17:34:31 -0700 Subject: [PATCH 1/6] fix(onboard): omit Docker-only Podman config Signed-off-by: Aaron Erickson --- src/lib/onboard/docker-driver-gateway-config.ts | 5 ++++- src/lib/onboard/docker-driver-gateway-env.test.ts | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/onboard/docker-driver-gateway-config.ts b/src/lib/onboard/docker-driver-gateway-config.ts index befc6b659d..9a1ea6980a 100644 --- a/src/lib/onboard/docker-driver-gateway-config.ts +++ b/src/lib/onboard/docker-driver-gateway-config.ts @@ -81,7 +81,10 @@ export function buildDockerDriverGatewayConfigToml( ["host_gateway_ip", driver === "podman" ? PORTABLE_HOST_GATEWAY_IP : undefined], ["network_name", gatewayEnv.OPENSHELL_DOCKER_NETWORK_NAME], ["supervisor_image", gatewayEnv.OPENSHELL_DOCKER_SUPERVISOR_IMAGE], - ["supervisor_bin", sandboxBin ?? undefined], + // OpenShell 0.0.85 accepts supervisor_bin only for the Docker driver. + // The Podman schema rejects the entire driver table when this Docker-only + // field is present, so portable onboarding must rely on supervisor_image. + ["supervisor_bin", driver === "docker" ? (sandboxBin ?? undefined) : undefined], ["guest_tls_ca", localTlsDir ? path.join(localTlsDir, "ca.crt") : undefined], ["guest_tls_cert", localTlsDir ? path.join(localTlsDir, "client", "tls.crt") : undefined], ["guest_tls_key", localTlsDir ? path.join(localTlsDir, "client", "tls.key") : undefined], diff --git a/src/lib/onboard/docker-driver-gateway-env.test.ts b/src/lib/onboard/docker-driver-gateway-env.test.ts index 8d5e948e3d..7763ab552f 100644 --- a/src/lib/onboard/docker-driver-gateway-env.test.ts +++ b/src/lib/onboard/docker-driver-gateway-env.test.ts @@ -88,6 +88,7 @@ describe("buildDockerDriverGatewayEnv", () => { expect(toml).toContain('compute_drivers = ["podman"]'); expect(toml).toContain("[openshell.drivers.podman]"); expect(toml).toContain('host_gateway_ip = "169.254.1.2"'); + expect(toml).not.toContain("supervisor_bin"); } finally { vi.unstubAllEnvs(); fs.rmSync(stateDir, { recursive: true, force: true }); From ea89db5abcbea583fd1df366934e7bd2302b3ee3 Mon Sep 17 00:00:00 2001 From: Aaron Erickson Date: Wed, 5 Aug 2026 17:44:33 -0700 Subject: [PATCH 2/6] test(e2e): launch pinned portable gateway Signed-off-by: Aaron Erickson --- .github/workflows/portable-profile-e2e.yaml | 5 ++ .../portable-profile-rootless-linux.test.ts | 75 +++++++++++++++++-- tools/e2e/check-semantic-phases.mts | 4 + 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/.github/workflows/portable-profile-e2e.yaml b/.github/workflows/portable-profile-e2e.yaml index 98c5471c0d..a839eb5a5a 100644 --- a/.github/workflows/portable-profile-e2e.yaml +++ b/.github/workflows/portable-profile-e2e.yaml @@ -58,6 +58,11 @@ jobs: - name: Build shared policy boundary run: npm run build:policy-boundary + - name: Install pinned OpenShell + run: | + env -u GH_TOKEN -u GITHUB_TOKEN NEMOCLAW_NON_INTERACTIVE=1 bash scripts/install-openshell.sh + echo "$HOME/.local/bin" >> "$GITHUB_PATH" + - name: Provision restricted rootless Linux runtime shell: bash run: | diff --git a/test/e2e/live/portable-profile-rootless-linux.test.ts b/test/e2e/live/portable-profile-rootless-linux.test.ts index 6f4da3f4e8..0e6afb94d3 100644 --- a/test/e2e/live/portable-profile-rootless-linux.test.ts +++ b/test/e2e/live/portable-profile-rootless-linux.test.ts @@ -9,16 +9,24 @@ import os from "node:os"; import path from "node:path"; import * as importedGatewayEnv from "../../../src/lib/onboard/docker-driver-gateway-env.ts"; +import * as importedGatewayLocalTls from "../../../src/lib/onboard/docker-driver-gateway-local-tls.ts"; import * as importedPortableHostPreparation from "../../../src/lib/onboard/experimental/portable-host-preparation.ts"; import * as importedSandboxPrebuild from "../../../src/lib/onboard/sandbox-prebuild.ts"; import * as importedBuildContext from "../../../src/lib/sandbox/build-context.ts"; import { test } from "../fixtures/e2e-test.ts"; +import { spawnObservedChild } from "../fixtures/observed-child-process.ts"; +import type { TestProgress } from "../fixtures/progress.ts"; const gatewayEnvModule = ( "default" in importedGatewayEnv && importedGatewayEnv.default ? importedGatewayEnv.default : importedGatewayEnv ) as typeof import("../../../src/lib/onboard/docker-driver-gateway-env.ts"); +const gatewayLocalTlsModule = ( + "default" in importedGatewayLocalTls && importedGatewayLocalTls.default + ? importedGatewayLocalTls.default + : importedGatewayLocalTls +) as typeof import("../../../src/lib/onboard/docker-driver-gateway-local-tls.ts"); const portableHostPreparationModule = ( "default" in importedPortableHostPreparation && importedPortableHostPreparation.default ? importedPortableHostPreparation.default @@ -36,6 +44,7 @@ const buildContextModule = ( ) as typeof import("../../../src/lib/sandbox/build-context.ts"); const { buildDockerDriverGatewayEnv } = gatewayEnvModule; +const { ensureDockerDriverGatewayLocalTlsBundle } = gatewayLocalTlsModule; const { preparePortableExperimentalHost } = portableHostPreparationModule; const { prebuildSandboxImageIfEligible } = sandboxPrebuildModule; const { SANDBOX_BUILD_CONTEXT_PREFIX } = buildContextModule; @@ -46,6 +55,7 @@ const PORTABLE_PROFILE_E2E_PHASES = [ "select the Podman-reported runtime socket", "prepare the rootless container runtime", "build and publish the sandbox image", + "start the pinned Podman gateway", "verify the fixed host route", "record portable environment completion", ] as const; @@ -86,6 +96,50 @@ async function waitForRegistry(attempt = 0): Promise { ); } +async function verifyPinnedPodmanGatewayStarts( + gatewayBin: string, + gatewayEnv: Record, + progress: TestProgress, +): Promise { + const child = spawnObservedChild(gatewayBin, [], { + activityLabel: "command: pinned OpenShell Podman gateway", + progress, + spawn: { + env: { ...process.env, ...gatewayEnv }, + stdio: ["ignore", "pipe", "pipe"], + }, + }); + let output = ""; + child.stdout?.on("data", (chunk) => { + output += String(chunk); + }); + child.stderr?.on("data", (chunk) => { + output += String(chunk); + }); + try { + const deadline = Date.now() + 15_000; + let driverSeenAt = 0; + while (Date.now() < deadline) { + if (/configuration error|invalid \[openshell\.drivers\.podman\] table/i.test(output)) { + assert.fail(`Pinned OpenShell rejected the generated Podman config:\n${output}`); + } + if (child.exitCode !== null) { + assert.fail( + `Pinned OpenShell Podman gateway exited with ${String(child.exitCode)}:\n${output}`, + ); + } + if (output.includes("Using compute driver driver=podman")) { + if (driverSeenAt === 0) driverSeenAt = Date.now(); + if (Date.now() - driverSeenAt >= 2_000) return; + } + await new Promise((resolve) => setTimeout(resolve, 100)); + } + assert.fail(`Pinned OpenShell did not keep the Podman driver healthy:\n${output}`); + } finally { + child.kill("SIGTERM"); + } +} + function writeSystemctlShim(binDir: string): void { const shim = path.join(binDir, "systemctl"); fs.writeFileSync( @@ -141,7 +195,7 @@ function selectInstallerPodmanRuntime(repoRoot: string): string { return run("bash", ["-c", script]); } -async function main(progress: { phase: (phase: string) => void }): Promise { +async function main(progress: TestProgress): Promise { assert.equal(process.platform, "linux", "portable profile E2E requires Linux"); assert.notEqual(process.getuid?.(), 0, "portable profile E2E must run without root privileges"); @@ -222,21 +276,32 @@ async function main(progress: { phase: (phase: string) => void }): Promise "nemoclaw-portable-registry", ]); - progress.phase("verify the fixed host route"); + const gatewayBin = run("bash", ["-lc", "command -v openshell-gateway"]); + const sandboxBin = run("bash", ["-lc", "command -v openshell-sandbox"]); const gatewayEnv = buildDockerDriverGatewayEnv({ platform: "linux", - gatewayPort: 5000, + gatewayPort: 8080, stateDir, getDockerSupervisorImage: () => "supervisor:e2e-not-launched", - resolveSandboxBin: () => null, + resolveSandboxBin: () => sandboxBin, }); assert.equal(gatewayEnv.OPENSHELL_DRIVERS, "podman"); assert.equal(gatewayEnv.OPENSHELL_BIND_ADDRESS, "0.0.0.0"); - assert.equal(gatewayEnv.OPENSHELL_GRPC_ENDPOINT, "https://169.254.1.2:5000"); + assert.equal(gatewayEnv.OPENSHELL_GRPC_ENDPOINT, "https://169.254.1.2:8080"); assert.match( fs.readFileSync(gatewayEnv.OPENSHELL_GATEWAY_CONFIG, "utf-8"), /host_gateway_ip = "169\.254\.1\.2"/, ); + assert.doesNotMatch( + fs.readFileSync(gatewayEnv.OPENSHELL_GATEWAY_CONFIG, "utf-8"), + /supervisor_bin/, + ); + + progress.phase("start the pinned Podman gateway"); + ensureDockerDriverGatewayLocalTlsBundle({ gatewayBin, stateDir }); + await verifyPinnedPodmanGatewayStarts(gatewayBin, gatewayEnv, progress); + + progress.phase("verify the fixed host route"); const routeProof = [ "exec 3<>/dev/tcp/169.254.1.2/5000", diff --git a/tools/e2e/check-semantic-phases.mts b/tools/e2e/check-semantic-phases.mts index 5b8d3fb6ab..08c1ee734e 100644 --- a/tools/e2e/check-semantic-phases.mts +++ b/tools/e2e/check-semantic-phases.mts @@ -387,6 +387,10 @@ const OBSERVED_CHILD_PROGRESS_POLICIES = new Map Date: Wed, 5 Aug 2026 17:51:16 -0700 Subject: [PATCH 3/6] test(e2e): normalize portable gateway logs Signed-off-by: Aaron Erickson --- test/e2e/live/portable-profile-rootless-linux.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/e2e/live/portable-profile-rootless-linux.test.ts b/test/e2e/live/portable-profile-rootless-linux.test.ts index 0e6afb94d3..633fa0aa27 100644 --- a/test/e2e/live/portable-profile-rootless-linux.test.ts +++ b/test/e2e/live/portable-profile-rootless-linux.test.ts @@ -16,6 +16,7 @@ import * as importedBuildContext from "../../../src/lib/sandbox/build-context.ts import { test } from "../fixtures/e2e-test.ts"; import { spawnObservedChild } from "../fixtures/observed-child-process.ts"; import type { TestProgress } from "../fixtures/progress.ts"; +import { stripAnsi } from "./json-envelope.ts"; const gatewayEnvModule = ( "default" in importedGatewayEnv && importedGatewayEnv.default @@ -120,7 +121,8 @@ async function verifyPinnedPodmanGatewayStarts( const deadline = Date.now() + 15_000; let driverSeenAt = 0; while (Date.now() < deadline) { - if (/configuration error|invalid \[openshell\.drivers\.podman\] table/i.test(output)) { + const plainOutput = stripAnsi(output); + if (/configuration error|invalid \[openshell\.drivers\.podman\] table/i.test(plainOutput)) { assert.fail(`Pinned OpenShell rejected the generated Podman config:\n${output}`); } if (child.exitCode !== null) { @@ -128,7 +130,7 @@ async function verifyPinnedPodmanGatewayStarts( `Pinned OpenShell Podman gateway exited with ${String(child.exitCode)}:\n${output}`, ); } - if (output.includes("Using compute driver driver=podman")) { + if (/Using compute driver\s+driver=podman/.test(plainOutput)) { if (driverSeenAt === 0) driverSeenAt = Date.now(); if (Date.now() - driverSeenAt >= 2_000) return; } From 1d952e82819856ff2ac46dd67cd4850cb4fea992 Mon Sep 17 00:00:00 2001 From: Aaron Erickson Date: Wed, 5 Aug 2026 18:01:38 -0700 Subject: [PATCH 4/6] test(e2e): isolate portable gateway observer Signed-off-by: Aaron Erickson --- .../live/portable-profile-gateway-proof.ts | 54 +++++++++++++++++++ .../portable-profile-rootless-linux.test.ts | 48 +---------------- tools/e2e/check-semantic-phases.mts | 2 +- 3 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 test/e2e/live/portable-profile-gateway-proof.ts diff --git a/test/e2e/live/portable-profile-gateway-proof.ts b/test/e2e/live/portable-profile-gateway-proof.ts new file mode 100644 index 0000000000..d2941fc7d0 --- /dev/null +++ b/test/e2e/live/portable-profile-gateway-proof.ts @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import assert from "node:assert/strict"; + +import { spawnObservedChild } from "../fixtures/observed-child-process.ts"; +import type { TestProgress } from "../fixtures/progress.ts"; +import { stripAnsi } from "./json-envelope.ts"; + +/** Prove the pinned gateway accepts the generated rootless Podman configuration. */ +export async function verifyPinnedPodmanGatewayStarts( + gatewayBin: string, + gatewayEnv: Record, + progress: TestProgress, +): Promise { + const child = spawnObservedChild(gatewayBin, [], { + activityLabel: "command: pinned OpenShell Podman gateway", + progress, + spawn: { + env: { ...process.env, ...gatewayEnv }, + stdio: ["ignore", "pipe", "pipe"], + }, + }); + let output = ""; + child.stdout?.on("data", (chunk) => { + output += String(chunk); + }); + child.stderr?.on("data", (chunk) => { + output += String(chunk); + }); + try { + const deadline = Date.now() + 15_000; + let driverSeenAt = 0; + while (Date.now() < deadline) { + const plainOutput = stripAnsi(output); + if (/configuration error|invalid \[openshell\.drivers\.podman\] table/i.test(plainOutput)) { + assert.fail(`Pinned OpenShell rejected the generated Podman config:\n${output}`); + } + if (child.exitCode !== null) { + assert.fail( + `Pinned OpenShell Podman gateway exited with ${String(child.exitCode)}:\n${output}`, + ); + } + if (/Using compute driver\s+driver=podman/.test(plainOutput)) { + if (driverSeenAt === 0) driverSeenAt = Date.now(); + if (Date.now() - driverSeenAt >= 2_000) return; + } + await new Promise((resolve) => setTimeout(resolve, 100)); + } + assert.fail(`Pinned OpenShell did not keep the Podman driver healthy:\n${output}`); + } finally { + child.kill("SIGTERM"); + } +} diff --git a/test/e2e/live/portable-profile-rootless-linux.test.ts b/test/e2e/live/portable-profile-rootless-linux.test.ts index 633fa0aa27..c4a31928c5 100644 --- a/test/e2e/live/portable-profile-rootless-linux.test.ts +++ b/test/e2e/live/portable-profile-rootless-linux.test.ts @@ -14,9 +14,8 @@ import * as importedPortableHostPreparation from "../../../src/lib/onboard/exper import * as importedSandboxPrebuild from "../../../src/lib/onboard/sandbox-prebuild.ts"; import * as importedBuildContext from "../../../src/lib/sandbox/build-context.ts"; import { test } from "../fixtures/e2e-test.ts"; -import { spawnObservedChild } from "../fixtures/observed-child-process.ts"; import type { TestProgress } from "../fixtures/progress.ts"; -import { stripAnsi } from "./json-envelope.ts"; +import { verifyPinnedPodmanGatewayStarts } from "./portable-profile-gateway-proof.ts"; const gatewayEnvModule = ( "default" in importedGatewayEnv && importedGatewayEnv.default @@ -97,51 +96,6 @@ async function waitForRegistry(attempt = 0): Promise { ); } -async function verifyPinnedPodmanGatewayStarts( - gatewayBin: string, - gatewayEnv: Record, - progress: TestProgress, -): Promise { - const child = spawnObservedChild(gatewayBin, [], { - activityLabel: "command: pinned OpenShell Podman gateway", - progress, - spawn: { - env: { ...process.env, ...gatewayEnv }, - stdio: ["ignore", "pipe", "pipe"], - }, - }); - let output = ""; - child.stdout?.on("data", (chunk) => { - output += String(chunk); - }); - child.stderr?.on("data", (chunk) => { - output += String(chunk); - }); - try { - const deadline = Date.now() + 15_000; - let driverSeenAt = 0; - while (Date.now() < deadline) { - const plainOutput = stripAnsi(output); - if (/configuration error|invalid \[openshell\.drivers\.podman\] table/i.test(plainOutput)) { - assert.fail(`Pinned OpenShell rejected the generated Podman config:\n${output}`); - } - if (child.exitCode !== null) { - assert.fail( - `Pinned OpenShell Podman gateway exited with ${String(child.exitCode)}:\n${output}`, - ); - } - if (/Using compute driver\s+driver=podman/.test(plainOutput)) { - if (driverSeenAt === 0) driverSeenAt = Date.now(); - if (Date.now() - driverSeenAt >= 2_000) return; - } - await new Promise((resolve) => setTimeout(resolve, 100)); - } - assert.fail(`Pinned OpenShell did not keep the Podman driver healthy:\n${output}`); - } finally { - child.kill("SIGTERM"); - } -} - function writeSystemctlShim(binDir: string): void { const shim = path.join(binDir, "systemctl"); fs.writeFileSync( diff --git a/tools/e2e/check-semantic-phases.mts b/tools/e2e/check-semantic-phases.mts index 08c1ee734e..8624e04d02 100644 --- a/tools/e2e/check-semantic-phases.mts +++ b/tools/e2e/check-semantic-phases.mts @@ -388,7 +388,7 @@ const OBSERVED_CHILD_PROGRESS_POLICIES = new Map Date: Wed, 5 Aug 2026 18:12:01 -0700 Subject: [PATCH 5/6] test(e2e): trigger portable gateway proof Signed-off-by: Aaron Erickson --- .github/workflows/portable-profile-e2e.yaml | 2 ++ test/e2e/live/portable-profile-gateway-proof.ts | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/portable-profile-e2e.yaml b/.github/workflows/portable-profile-e2e.yaml index a839eb5a5a..ff4579f44c 100644 --- a/.github/workflows/portable-profile-e2e.yaml +++ b/.github/workflows/portable-profile-e2e.yaml @@ -16,6 +16,7 @@ on: - "src/lib/onboard/**" - "src/lib/domain/sandbox/image-tag.ts" - "src/lib/sandbox/build-context.ts" + - "test/e2e/live/portable-profile-gateway-proof.ts" - "test/e2e/live/portable-profile-rootless-linux.test.ts" push: branches: @@ -27,6 +28,7 @@ on: - "src/lib/onboard/**" - "src/lib/domain/sandbox/image-tag.ts" - "src/lib/sandbox/build-context.ts" + - "test/e2e/live/portable-profile-gateway-proof.ts" - "test/e2e/live/portable-profile-rootless-linux.test.ts" permissions: diff --git a/test/e2e/live/portable-profile-gateway-proof.ts b/test/e2e/live/portable-profile-gateway-proof.ts index d2941fc7d0..4c2343ac95 100644 --- a/test/e2e/live/portable-profile-gateway-proof.ts +++ b/test/e2e/live/portable-profile-gateway-proof.ts @@ -7,7 +7,7 @@ import { spawnObservedChild } from "../fixtures/observed-child-process.ts"; import type { TestProgress } from "../fixtures/progress.ts"; import { stripAnsi } from "./json-envelope.ts"; -/** Prove the pinned gateway accepts the generated rootless Podman configuration. */ +/** Verify that the pinned gateway accepts the generated rootless Podman configuration. */ export async function verifyPinnedPodmanGatewayStarts( gatewayBin: string, gatewayEnv: Record, @@ -34,7 +34,7 @@ export async function verifyPinnedPodmanGatewayStarts( while (Date.now() < deadline) { const plainOutput = stripAnsi(output); if (/configuration error|invalid \[openshell\.drivers\.podman\] table/i.test(plainOutput)) { - assert.fail(`Pinned OpenShell rejected the generated Podman config:\n${output}`); + assert.fail(`Pinned OpenShell rejected the generated Podman configuration:\n${output}`); } if (child.exitCode !== null) { assert.fail( @@ -47,7 +47,9 @@ export async function verifyPinnedPodmanGatewayStarts( } await new Promise((resolve) => setTimeout(resolve, 100)); } - assert.fail(`Pinned OpenShell did not keep the Podman driver healthy:\n${output}`); + assert.fail( + `Pinned OpenShell did not report driver=podman and remain running for two seconds:\n${output}`, + ); } finally { child.kill("SIGTERM"); } From 9403b99efb2cd0f28279c7016aa0b653a1028ac7 Mon Sep 17 00:00:00 2001 From: Aaron Erickson Date: Wed, 5 Aug 2026 18:59:30 -0700 Subject: [PATCH 6/6] test(e2e): cover portable proof inputs Signed-off-by: Aaron Erickson --- .github/workflows/portable-profile-e2e.yaml | 4 ++++ test/e2e/support/e2e-workflow.test.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/.github/workflows/portable-profile-e2e.yaml b/.github/workflows/portable-profile-e2e.yaml index ff4579f44c..7c8d0599d7 100644 --- a/.github/workflows/portable-profile-e2e.yaml +++ b/.github/workflows/portable-profile-e2e.yaml @@ -13,11 +13,13 @@ on: - ".github/workflows/portable-profile-e2e.yaml" - "install.sh" - "scripts/install.sh" + - "scripts/install-openshell.sh" - "src/lib/onboard/**" - "src/lib/domain/sandbox/image-tag.ts" - "src/lib/sandbox/build-context.ts" - "test/e2e/live/portable-profile-gateway-proof.ts" - "test/e2e/live/portable-profile-rootless-linux.test.ts" + - "tools/e2e/check-semantic-phases.mts" push: branches: - main @@ -25,11 +27,13 @@ on: - ".github/workflows/portable-profile-e2e.yaml" - "install.sh" - "scripts/install.sh" + - "scripts/install-openshell.sh" - "src/lib/onboard/**" - "src/lib/domain/sandbox/image-tag.ts" - "src/lib/sandbox/build-context.ts" - "test/e2e/live/portable-profile-gateway-proof.ts" - "test/e2e/live/portable-profile-rootless-linux.test.ts" + - "tools/e2e/check-semantic-phases.mts" permissions: contents: read diff --git a/test/e2e/support/e2e-workflow.test.ts b/test/e2e/support/e2e-workflow.test.ts index 1a30d22c8b..f8091eb051 100644 --- a/test/e2e/support/e2e-workflow.test.ts +++ b/test/e2e/support/e2e-workflow.test.ts @@ -715,8 +715,26 @@ describe("e2e workflow boundary", () => { jobs: Record; if?: string }>; }; const workflowJobs = new Set(Object.keys(workflow.jobs)); + const portableWorkflow = YAML.parse( + fs.readFileSync( + path.join(process.cwd(), ".github", "workflows", "portable-profile-e2e.yaml"), + "utf8", + ), + ) as { + on?: { pull_request?: { paths?: string[] }; push?: { paths?: string[] } }; + }; + const portableProofInputs = [ + "scripts/install-openshell.sh", + "test/e2e/live/portable-profile-gateway-proof.ts", + "test/e2e/live/portable-profile-rootless-linux.test.ts", + "tools/e2e/check-semantic-phases.mts", + ]; expect(validateFreeStandingWorkflowInventory()).toEqual([]); + expect(portableWorkflow.on?.pull_request?.paths).toEqual( + expect.arrayContaining(portableProofInputs), + ); + expect(portableWorkflow.on?.push?.paths).toEqual(expect.arrayContaining(portableProofInputs)); expect(inventory.allowedJobs).not.toHaveLength(0); expect(inventory.targetToJob.size).toBeGreaterThan(0); expect(inventory.workflowJobs.every((job) => workflowJobs.has(job))).toBe(true);