From 968aca5663f93ef153f7f25c1cd4efbf00051403 Mon Sep 17 00:00:00 2001 From: IAMSamuelRodda Date: Mon, 18 May 2026 11:49:52 +0930 Subject: [PATCH 1/2] fix(provider): allow overriding Codex sandbox --- README.md | 5 +++++ src/provider.test.ts | 40 +++++++++++++++++++++++++++++++++++++++- src/provider.ts | 13 +++++++++++-- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4e4538f..d833584 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,11 @@ Provider calls use `codex exec` with strict JSON schemas. Review and revalidate run read-only; fix planning runs with workspace-write because Codex may edit the working tree during the explicit fix command. +Set `CLAWPATCH_CODEX_SANDBOX` to override the Codex sandbox passed by +Clawpatch. Use any Codex sandbox mode, or `bypass`/`none` to pass +`--dangerously-bypass-approvals-and-sandbox` when the host environment already +provides isolation. + Supported provider names today: - `codex`: local Codex CLI diff --git a/src/provider.test.ts b/src/provider.test.ts index 93a4666..1820c24 100644 --- a/src/provider.test.ts +++ b/src/provider.test.ts @@ -1,10 +1,11 @@ -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it } from "vitest"; import { ClawpatchError } from "./errors.js"; import { __testing, extractJson, providerByName } from "./provider.js"; import { reviewOutputSchema } from "./types.js"; // eslint-disable-next-line no-underscore-dangle const { + addCodexSandboxArgs, addCodexModelArgs, acpxFailureMessage, extractAcpxJson, @@ -127,6 +128,43 @@ describe("parseCodexJson", () => { }); describe("Codex provider args", () => { + const originalCodexSandbox = process.env["CLAWPATCH_CODEX_SANDBOX"]; + + afterEach(() => { + if (originalCodexSandbox === undefined) { + delete process.env["CLAWPATCH_CODEX_SANDBOX"]; + } else { + process.env["CLAWPATCH_CODEX_SANDBOX"] = originalCodexSandbox; + } + }); + + it("uses the requested Codex sandbox by default", () => { + delete process.env["CLAWPATCH_CODEX_SANDBOX"]; + const args = ["exec"]; + + addCodexSandboxArgs(args, "read-only"); + + expect(args).toEqual(["exec", "--sandbox", "read-only"]); + }); + + it("allows Codex sandbox mode to be overridden by environment", () => { + process.env["CLAWPATCH_CODEX_SANDBOX"] = "danger-full-access"; + const args = ["exec"]; + + addCodexSandboxArgs(args, "read-only"); + + expect(args).toEqual(["exec", "--sandbox", "danger-full-access"]); + }); + + it("can bypass Codex sandboxing when the host already provides isolation", () => { + process.env["CLAWPATCH_CODEX_SANDBOX"] = "bypass"; + const args = ["exec"]; + + addCodexSandboxArgs(args, "read-only"); + + expect(args).toEqual(["exec", "--dangerously-bypass-approvals-and-sandbox"]); + }); + it("passes model and reasoning effort through explicit CLI config", () => { const args = ["exec"]; diff --git a/src/provider.ts b/src/provider.ts index 5bbae55..f7b11e6 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -452,13 +452,12 @@ async function runCodexJson( "exec", "--cd", root, - "--sandbox", - sandbox, "--output-schema", schemaPath, "--output-last-message", outputPath, ]; + addCodexSandboxArgs(args, sandbox); addCodexModelArgs(args, options); args.push("-"); const result = await runCommandArgs("codex", args, root, prompt); @@ -479,6 +478,15 @@ async function runCodexJson( } } +function addCodexSandboxArgs(args: string[], sandbox: string): void { + const override = process.env["CLAWPATCH_CODEX_SANDBOX"]; + if (override === "bypass" || override === "none") { + args.push("--dangerously-bypass-approvals-and-sandbox"); + return; + } + args.push("--sandbox", override ?? sandbox); +} + function addCodexModelArgs(args: string[], options: ProviderOptions): void { if (options.skipGitRepoCheck) { args.push("--skip-git-repo-check"); @@ -974,6 +982,7 @@ function acpxTimeoutMs(): number { export const __testing = { acpxFailureMessage, addCodexModelArgs, + addCodexSandboxArgs, extractAcpxJson, extractOpencodeJson, parseAcpxAgent, From 40ba9fc444196047c5f5aba4695aec766dcd83a3 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 18 May 2026 03:41:40 +0100 Subject: [PATCH 2/2] fix(provider): normalize Codex sandbox override --- CHANGELOG.md | 1 + src/provider.test.ts | 13 +++++++++++-- src/provider.ts | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9f7c5c..841645b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Added a `pi` provider for routing review, fix, revalidate, and agent map through the [pi coding agent](https://pi.dev) in non-interactive print mode, thanks @danielmarbach. - Added explicit Codex reasoning effort selection via `--reasoning-effort`, `CLAWPATCH_REASONING_EFFORT`, and provider config, with `doctor` reporting the active setting. - Added `--skip-git-repo-check` for Codex-backed map, review, fix, and revalidate commands so initialized non-Git roots can run Codex, thanks @im-zayan. +- Added `CLAWPATCH_CODEX_SANDBOX` for overriding Codex provider sandbox mode when the host already provides isolation, thanks @IAMSamuelRodda. - Added deterministic Express, Fastify, and Hono route mapping for Node projects, thanks @rohitjavvadi. - Fixed provider commands with relative `--root` paths by canonicalizing explicit roots before invoking Codex or other providers. - Added first-pass Elixir Mix/Phoenix mapping for project metadata, contexts, Phoenix web slices, runtime config, Ecto migrations, project scripts, ExUnit tests, and Mix validation defaults, thanks @tears-mysthrala. diff --git a/src/provider.test.ts b/src/provider.test.ts index 1820c24..eb9197b 100644 --- a/src/provider.test.ts +++ b/src/provider.test.ts @@ -148,7 +148,7 @@ describe("Codex provider args", () => { }); it("allows Codex sandbox mode to be overridden by environment", () => { - process.env["CLAWPATCH_CODEX_SANDBOX"] = "danger-full-access"; + process.env["CLAWPATCH_CODEX_SANDBOX"] = " danger-full-access "; const args = ["exec"]; addCodexSandboxArgs(args, "read-only"); @@ -156,8 +156,17 @@ describe("Codex provider args", () => { expect(args).toEqual(["exec", "--sandbox", "danger-full-access"]); }); + it("ignores blank Codex sandbox overrides", () => { + process.env["CLAWPATCH_CODEX_SANDBOX"] = " "; + const args = ["exec"]; + + addCodexSandboxArgs(args, "read-only"); + + expect(args).toEqual(["exec", "--sandbox", "read-only"]); + }); + it("can bypass Codex sandboxing when the host already provides isolation", () => { - process.env["CLAWPATCH_CODEX_SANDBOX"] = "bypass"; + process.env["CLAWPATCH_CODEX_SANDBOX"] = " none "; const args = ["exec"]; addCodexSandboxArgs(args, "read-only"); diff --git a/src/provider.ts b/src/provider.ts index f7b11e6..972edf3 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -479,12 +479,12 @@ async function runCodexJson( } function addCodexSandboxArgs(args: string[], sandbox: string): void { - const override = process.env["CLAWPATCH_CODEX_SANDBOX"]; + const override = process.env["CLAWPATCH_CODEX_SANDBOX"]?.trim(); if (override === "bypass" || override === "none") { args.push("--dangerously-bypass-approvals-and-sandbox"); return; } - args.push("--sandbox", override ?? sandbox); + args.push("--sandbox", override && override.length > 0 ? override : sandbox); } function addCodexModelArgs(args: string[], options: ProviderOptions): void {