diff --git a/config/knip.all-exports.config.ts b/config/knip.all-exports.config.ts index 71eed6689332..42c7c7b8b7c9 100644 --- a/config/knip.all-exports.config.ts +++ b/config/knip.all-exports.config.ts @@ -54,6 +54,8 @@ const ROOT_TEST_ENTRY_GLOBS = [ "test/e2e/qa-lab/runtime/system-agent-first-run-docker-client.ts!", // QA scenario YAML dispatches these scripts/tests by path rather than import. ...QA_SCENARIO_EXECUTION_ENTRIES, + // Invoked directly by the sandbox bind-conflict E2E verification script. + "scripts/e2e-sandbox-bind-conflict.mjs!", // The Voice Call QA scenario loads this fixture through a generated plugin directory. "test/e2e/qa-lab/runtime/fixtures/voice-call-runtime-plugin/index.js!", "test/scripts/fixtures/secret-provider-integrations-harness.mjs!", diff --git a/scripts/e2e-sandbox-bind-conflict.mjs b/scripts/e2e-sandbox-bind-conflict.mjs index 6c024b093070..1cc47f72837b 100644 --- a/scripts/e2e-sandbox-bind-conflict.mjs +++ b/scripts/e2e-sandbox-bind-conflict.mjs @@ -27,6 +27,15 @@ fs.writeFileSync(path.join(customBindHost, "data.txt"), "user data\n"); const userBinds = [`${customBindHost}:/workspace/skills:rw`]; const containerName = `oc-e2e-bind-${Date.now()}`.slice(0, 63); +let failureCount = 0; +function fail(label) { + console.log(`❌ FAIL: ${label}`); + failureCount += 1; +} +function pass(label) { + console.log(`✅ ${label}`); +} + // ── Load production code ────────────────────────────────────────────── const { resolveReadOnlyWorkspaceSkillMounts, @@ -59,6 +68,13 @@ console.log( safeBinds.length === 0 ? "(none)" : safeBinds, ); +// Conflicting bind should be filtered out (no safe binds remain) +if (safeBinds.length > 0) { + fail("conflicting user bind was not filtered out"); +} else { + pass("conflicting user bind correctly skipped"); +} + // ── Build docker create args ────────────────────────────────────────── const dockerArgs = [ "create", @@ -115,6 +131,8 @@ for (let i = 0; i < dockerArgs.length - 1; i++) { } if (dupes === 0) { console.log("✅ No duplicate container paths in -v args"); +} else { + fail(`found ${dupes} duplicate container paths`); } // ── Helper: run sudo docker with argv (no shell string) ─────────────── @@ -142,7 +160,7 @@ try { throw err; } created = true; - console.log("✅ Container created — no Duplicate mount point error"); + pass("Container created — no Duplicate mount point error"); const inspectResult = sudoDocker([ "inspect", @@ -154,7 +172,12 @@ try { const dests = output.split("|").filter(Boolean); const skillsCount = dests.filter((d) => d === "/workspace/skills").length; console.log(`Mount destinations: ${dests.join(" ")}`); - console.log(`/workspace/skills count: ${skillsCount} ${skillsCount <= 1 ? "✅" : "❌"}`); + console.log(`/workspace/skills count: ${skillsCount}`); + if (skillsCount <= 1) { + pass("/workspace/skills appears at most once"); + } else { + fail(`/workspace/skills appears ${skillsCount} times (expected ≤1)`); + } // Verify protected mount source (not user bind) const mountResult = sudoDocker([ @@ -167,15 +190,24 @@ try { console.log(`Mount source for /workspace/skills: ${mountSrc}`); const isReadOnly = mountSrc.includes("ro"); const isProtectedSource = mountSrc.includes(path.join(workspaceDir, "skills")); - console.log(`Read-only (protected): ${isReadOnly ? "✅" : "❌"}`); - console.log(`Source is protected skill dir: ${isProtectedSource ? "✅" : "❌"}`); + if (isReadOnly) { + pass("mount is read-only"); + } else { + fail("mount is NOT read-only"); + } + if (isProtectedSource) { + pass("mount source is the protected skill directory"); + } else { + fail("mount source is NOT the protected skill directory"); + } } catch (err) { const msg = err?.stderr ? String(err.stderr) : String(err.message ?? err); if (msg.includes("Duplicate mount point") || msg.includes("duplicate mount")) { - console.log("❌ FAIL: Duplicate mount point rejected by Docker"); + fail("Duplicate mount point rejected by Docker"); console.log(msg.slice(0, 500)); } else { console.log(`❌ Error: ${msg.slice(0, 500)}`); + fail(msg.slice(0, 200)); } } finally { if (created) { @@ -183,4 +215,8 @@ try { } fs.rmSync(workspaceDir, { recursive: true, force: true }); } -console.log("\nDone."); + +console.log( + failureCount > 0 ? `\n❌ Done. ${failureCount} failure(s)` : "\n✅ Done. All checks passed.", +); +process.exitCode = failureCount > 0 ? 1 : 0;