Skip to content

Resolve the task sandbox from config.toml and add task --read-only#508

Open
cubicj wants to merge 1 commit into
openai:mainfrom
cubicj:config-driven-sandbox
Open

Resolve the task sandbox from config.toml and add task --read-only#508
cubicj wants to merge 1 commit into
openai:mainfrom
cubicj:config-driven-sandbox

Conversation

@cubicj

@cubicj cubicj commented Jul 15, 2026

Copy link
Copy Markdown

Summary

The plugin always overrides the user's configured sandbox_mode with hardcoded sandbox values (#482). buildThreadParams/buildResumeParams fall back to "read-only" whenever the caller passes nothing, and the task path hardcodes the --write ternary to "workspace-write"/"read-only", so a sandbox_mode in ~/.codex/config.toml never reaches any job. Users who want config-driven sandboxes (e.g. danger-full-access for trusted delegation setups) end up patching the installed plugin by hand.

Change

Task paths now send sandbox: null when the caller does not ask for a specific sandbox, letting the app-server resolve it from config.toml — the same mechanism the plugin already relies on for model (model: options.model ?? null falls back to the configured model today). An explicit --write still forces workspace-write, and both review paths (native and adversarial) deliberately keep their pinned read-only sandbox.

  • lib/codex.mjs: buildThreadParams and buildResumeParams change options.sandbox ?? "read-only" to options.sandbox ?? null. ThreadStartParams.sandbox is declared SandboxMode | null, so this is type-clean.
  • codex-companion.mjs: the task path changes request.write ? "workspace-write" : "read-only" to request.write ? "workspace-write" : request.readOnly ? "read-only" : null.

Because omitting --write now defers to config instead of guaranteeing read-only, the same change adds a task --read-only flag as the per-run way to pin the read-only sandbox: it is mutually exclusive with --write (a combined call fails with a clear error), survives the background request round trip into the detached worker, and applies to resumed threads. The rescue command/agent/skill texts are updated one line each so that read-only intent means passing --read-only rather than merely omitting --write. The stop-review-gate hook's internal task now passes --read-only explicitly, so every review-shaped run — native review, adversarial review, and the stop-time gate task — keeps a pinned read-only sandbox regardless of config.

Behavior only changes for users who set sandbox_mode in config.toml: when it is absent, the app-server's own default for an unset sandbox remains read-only, so stock installations keep today's behavior. Inheriting a permissive mode from config is a deliberate user choice made in their own Codex configuration, and #506 (resolved model/effort/sandbox capture, from #481) makes the inherited value visible on every job record. An explicit per-run escalation flag (#145, PR #147) is complementary to this config-driven default and intentionally out of scope here.

Verification

  • Live probe against codex-cli 0.145.0-alpha.12: thread/start with sandbox: null and config.toml sandbox_mode = "danger-full-access" returned the config-resolved {"type":"dangerFullAccess"} sandbox in the response echo; explicit values still override.
  • npm test: 94/94 passing. The fake-codex fixture now records thread/start/thread/resume params, with assertions covering every path: a plain task sends sandbox: null, --write sends workspace-write, --read-only pins read-only on fresh, resumed, and background-worker threads, --write --read-only is rejected, and native review, adversarial review, and the stop-review-gate hook's task all still send read-only.
  • npm run build (typecheck via tsconfig.app-server.json): clean.
  • git diff --check against the base commit: clean.

Related Issues

Fixes #482

@cubicj cubicj requested a review from a team July 15, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hardcoded sandbox values always override config.toml sandbox_mode

1 participant