Skip to content

Commit 6f34ebc

Browse files
wesmclaude
andauthored
fix: use --sandbox danger-full-access for Codex review mode (#616)
## Summary - Switch Codex review mode from `--sandbox read-only` to `--sandbox danger-full-access` to fix CI reviews failing on large diffs - The bwrap sandbox (used by both `read-only` and `workspace-write` modes) blocks loopback networking, causing git commands to fail with `bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted` — this makes Codex unable to inspect diffs, so reviews report the code is inaccessible - `workspace-write` has the same bwrap loopback bug ([openai/codex#15496](openai/codex#15496)), so `danger-full-access` is the only working option - Update `review_guidelines` to document the rationale so security reviewers don't flag it - Update `scripts/changelog.sh` to match 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e58e349 commit 6f34ebc

File tree

4 files changed

+25
-20
lines changed

4 files changed

+25
-20
lines changed

.roborev.toml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,17 @@ security findings:
4545
4646
## Agent tool permissions
4747
48-
Review agents run with shell access to inspect diffs and source files. The
49-
allow-all-tools plus deny-list approach used by agents like Copilot is
50-
intentional — it matches the trust level of Codex (--sandbox read-only still
51-
permits arbitrary shell execution) and Gemini (--approval-mode plan). The
48+
Review agents run with shell access to inspect diffs and source files. Codex
49+
runs with --sandbox danger-full-access because the bwrap sandbox (used by both
50+
read-only and workspace-write modes) blocks loopback networking, which prevents
51+
git commands (git diff, git log, git show) from working in CI review jobs.
52+
This is intentional — roborev is a local-only tool that runs in trusted
53+
environments where the code is the operator's own. The allow-all-tools plus
54+
deny-list approach used by agents like Copilot matches this trust level. The
5255
deny-list is defense-in-depth, not a security boundary. Users reviewing
5356
untrusted code are expected to run roborev in a sandboxed environment
54-
(container, VM). Do not flag agent tool permission patterns as security
55-
vulnerabilities when they follow this model.
57+
(container, VM). Do not flag agent sandbox or tool permission patterns as
58+
security vulnerabilities when they follow this model.
5659
5760
## Config loading and filesystem fallback
5861

internal/agent/codex.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,12 @@ func (a *CodexAgent) commandArgs(opts codexArgOptions) []string {
141141
args = append(args, codexDangerousFlag)
142142
}
143143
if opts.autoApprove {
144-
// Use read-only sandbox for review mode instead of --full-auto
145-
// (which implies --sandbox workspace-write). Background review
146-
// jobs run in the user's repo and must not take index.lock.
147-
args = append(args, "--sandbox", "read-only")
144+
// Use full-access sandbox for review mode. The read-only
145+
// sandbox blocks loopback networking, which prevents git
146+
// commands from working in CI review jobs. roborev runs in
147+
// trusted environments where the code is the operator's own,
148+
// so sandbox enforcement is unnecessary.
149+
args = append(args, "--sandbox", "danger-full-access")
148150
}
149151
if !opts.preview {
150152
args = append(args, "-C", opts.repoPath)
@@ -181,7 +183,7 @@ func codexSupportsDangerousFlag(ctx context.Context, command string) (bool, erro
181183
}
182184

183185
// codexSupportsNonInteractive checks that codex supports --sandbox,
184-
// needed for non-agentic review mode (--sandbox read-only).
186+
// needed for non-agentic review mode (--sandbox danger-full-access).
185187
func codexSupportsNonInteractive(ctx context.Context, command string) (bool, error) {
186188
if cached, ok := codexAutoApproveSupport.Load(command); ok {
187189
return cached.(bool), nil
@@ -210,8 +212,8 @@ func (a *CodexAgent) Review(ctx context.Context, repoPath, commitSHA, prompt str
210212
}
211213
}
212214

213-
// Non-agentic review mode uses --sandbox read-only for
214-
// non-interactive execution without writing to the working tree.
215+
// Non-agentic review mode uses --sandbox danger-full-access for
216+
// non-interactive execution that can still run git commands.
215217
autoApprove := false
216218
if !agenticMode {
217219
supported, err := codexSupportsNonInteractive(ctx, a.Command)

internal/agent/codex_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func TestCodex_buildArgs(t *testing.T) {
3636
name: "NonAgenticAutoApprove",
3737
agentic: false,
3838
autoApprove: true,
39-
wantFlags: []string{"--sandbox", "read-only", "--json"},
39+
wantFlags: []string{"--sandbox", "danger-full-access", "--json"},
4040
wantMissingFlags: []string{codexDangerousFlag, codexAutoApproveFlag},
4141
},
4242
{
@@ -96,7 +96,7 @@ func TestCodexCommandLineOmitsRuntimeOnlyArgs(t *testing.T) {
9696

9797
assert.Contains(t, cmdLine, "exec resume --json")
9898
assert.Contains(t, cmdLine, "session-123")
99-
assert.Contains(t, cmdLine, "--sandbox read-only")
99+
assert.Contains(t, cmdLine, "--sandbox danger-full-access")
100100
assert.NotContains(t, cmdLine, " -C ")
101101
assert.False(t, strings.HasSuffix(cmdLine, " -"), "command line should omit stdin marker: %q", cmdLine)
102102
}
@@ -118,7 +118,7 @@ func TestCodexReviewUnsafeMissingFlagErrors(t *testing.T) {
118118
assert.Contains(t, err.Error(), "does not support")
119119
}
120120

121-
func TestCodexReviewUsesReadOnlySandbox(t *testing.T) {
121+
func TestCodexReviewUsesSandboxNone(t *testing.T) {
122122
a, mock := setupMockCodex(t, false, MockCLIOpts{
123123
HelpOutput: "usage --sandbox",
124124
CaptureArgs: true,
@@ -133,10 +133,10 @@ func TestCodexReviewUsesReadOnlySandbox(t *testing.T) {
133133
args, err := os.ReadFile(mock.ArgsFile)
134134
require.NoError(t, err)
135135
argsStr := string(args)
136-
assert.Contains(t, argsStr, "--sandbox read-only",
137-
"expected --sandbox read-only in args, got %s", strings.TrimSpace(argsStr))
136+
assert.Contains(t, argsStr, "--sandbox danger-full-access",
137+
"expected --sandbox danger-full-access in args, got: %s", strings.TrimSpace(argsStr))
138138
assert.NotContains(t, argsStr, codexAutoApproveFlag,
139-
"expected no %s in review mode, got %s", codexAutoApproveFlag, strings.TrimSpace(argsStr))
139+
"expected no %s in review mode, got: %s", codexAutoApproveFlag, strings.TrimSpace(argsStr))
140140
}
141141

142142
func TestCodexReviewWithSessionResumePassesResumeArgs(t *testing.T) {

scripts/changelog.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ case "$AGENT" in
8282
codex)
8383
CODEX_RUST_LOG="${CHANGELOG_CODEX_RUST_LOG:-${RUST_LOG:-error,codex_core::rollout::list=off}}"
8484
set +e
85-
RUST_LOG="$CODEX_RUST_LOG" codex exec --json --skip-git-repo-check --sandbox read-only -c reasoning_effort=high -o "$TMPFILE" - >/dev/null < "$PROMPTFILE" 2>"$ERRFILE"
85+
RUST_LOG="$CODEX_RUST_LOG" codex exec --json --skip-git-repo-check --sandbox danger-full-access -c reasoning_effort=high -o "$TMPFILE" - >/dev/null < "$PROMPTFILE" 2>"$ERRFILE"
8686
AGENT_EXIT=$?
8787
set -e
8888
;;

0 commit comments

Comments
 (0)