From 964493b469f405454427732b75f23d77b2ff6216 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Fri, 19 Jun 2026 13:37:22 -0400 Subject: [PATCH 1/2] fix: bypass codex inner sandbox in sandboxes --- services/api/tests/test_codex_app_wrapper.py | 23 ++++++++++++++++- services/sandbox/codex-app-wrapper.py | 27 +++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/services/api/tests/test_codex_app_wrapper.py b/services/api/tests/test_codex_app_wrapper.py index 1ad350f91..1cdd74953 100644 --- a/services/api/tests/test_codex_app_wrapper.py +++ b/services/api/tests/test_codex_app_wrapper.py @@ -416,7 +416,13 @@ def fake_popen(args: list[str], *other_args, **kwargs) -> FakeProcess: wrapper.main() - assert popen_args == ["codex", "app-server", "--listen", "stdio://"] + assert popen_args == [ + "codex", + "--dangerously-bypass-approvals-and-sandbox", + "app-server", + "--listen", + "stdio://", + ] assert requests[0] == ( "initialize", { @@ -437,6 +443,21 @@ def fake_popen(args: list[str], *other_args, **kwargs) -> FakeProcess: assert {"type": "turn.completed"} in emitted +def test_codex_app_server_command_can_keep_inner_sandbox(monkeypatch) -> None: + wrapper = _load_wrapper() + + monkeypatch.setenv("CENTAUR_CODEX_BYPASS_INNER_SANDBOX", "0") + + assert wrapper._codex_app_server_command("high") == [ + "codex", + "app-server", + "-c", + "model_reasoning_effort=high", + "--listen", + "stdio://", + ] + + def test_reasoning_effort_bumps_on_code_work(monkeypatch) -> None: wrapper = _load_wrapper() monkeypatch.delenv("CENTAUR_CODEX_DYNAMIC_EFFORT", raising=False) diff --git a/services/sandbox/codex-app-wrapper.py b/services/sandbox/codex-app-wrapper.py index bbb60cf4e..aeb296ee6 100755 --- a/services/sandbox/codex-app-wrapper.py +++ b/services/sandbox/codex-app-wrapper.py @@ -89,6 +89,29 @@ def _reasoning_effort_for_text(text: str) -> str | None: if text and _CODE_WORK_RE.search(text): return (os.environ.get("CENTAUR_CODEX_EFFORT_HIGH") or "medium").strip() return None + + +def _bypass_codex_inner_sandbox() -> bool: + """Let Kubernetes be the sandbox boundary instead of Codex's bwrap layer.""" + return ( + os.environ.get("CENTAUR_CODEX_BYPASS_INNER_SANDBOX", "1") + .strip() + .lower() + not in ("0", "false", "no", "off") + ) + + +def _codex_app_server_command(reasoning_effort: str | None = None) -> list[str]: + cmd = ["codex"] + if _bypass_codex_inner_sandbox(): + cmd.append("--dangerously-bypass-approvals-and-sandbox") + cmd.append("app-server") + if reasoning_effort: + cmd += ["-c", f"model_reasoning_effort={reasoning_effort}"] + cmd += ["--listen", "stdio://"] + return cmd + + OTEL_PROXY: ThreadingHTTPServer | None = None OTEL_PROXY_TARGET_ENDPOINT: str | None = None OTEL_PROXY_SPAN_PREFIX = "codex." @@ -157,9 +180,8 @@ def start_app_server(reasoning_effort: str | None = None) -> None: APP = None APP_INITIALIZED = False - cmd = ["codex", "app-server"] + cmd = _codex_app_server_command(reasoning_effort) if reasoning_effort: - cmd += ["-c", f"model_reasoning_effort={reasoning_effort}"] emit( { "type": "system", @@ -167,7 +189,6 @@ def start_app_server(reasoning_effort: str | None = None) -> None: "effort": reasoning_effort, } ) - cmd += ["--listen", "stdio://"] APP = subprocess.Popen( cmd, stdin=subprocess.PIPE, From 85cfd9a7e59415c3c3fb47541dc824beff1f9c77 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Fri, 19 Jun 2026 13:37:43 -0400 Subject: [PATCH 2/2] docs: track codex sandbox bypass --- FORK.md | 1 + 1 file changed, 1 insertion(+) diff --git a/FORK.md b/FORK.md index 921f68a86..b9f06040c 100644 --- a/FORK.md +++ b/FORK.md @@ -22,3 +22,4 @@ line in the PR that syncs it back. | 5ac94c35 | slackbot: channel-thread replies require @-mention (undoes joined-thread auto-reply from #2); codex wrapper falls back to fresh thread on dead rollout | [#12](https://github.com/Tavus-Engineering/centaur/pull/12) | | a9d47a12 | api: finalize codex turn.failed as failed_permanent + post failure notice to Slack; raise iron-proxy upstream header timeout to 300s (codex remote compaction); fold signoz/aws header allowlist into base.yaml | [#13](https://github.com/Tavus-Engineering/centaur/pull/13) | | dcfd647c | slackbot: route in-thread Watch Agent mentions through DM and post results back only after approval | [#14](https://github.com/Tavus-Engineering/centaur/pull/14) | +| 964493b4 | sandbox: launch Codex with external-sandbox bypass so shell commands work in Kubernetes sandboxes | [#15](https://github.com/Tavus-Engineering/centaur/pull/15) |