mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
b0236501e2c19164d47bda54cf523ea39bdba98b
36 Commits
-
fix(linux-sandbox): prefer system /usr/bin/bwrap when available (#14963)
## Problem Ubuntu/AppArmor hosts started failing in the default Linux sandbox path after the switch to vendored/default bubblewrap in `0.115.0`. The clearest report is in [#14919](https://github.com/openai/codex/issues/14919), especially [this investigation comment](https://github.com/openai/codex/issues/14919#issuecomment-4076504751): on affected Ubuntu systems, `/usr/bin/bwrap` works, but a copied or vendored `bwrap` binary fails with errors like `bwrap: setting up uid map: Permission denied` or `bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted`. The root cause is Ubuntu's `/etc/apparmor.d/bwrap-userns-restrict` profile, which grants `userns` access specifically to `/usr/bin/bwrap`. Once Codex started using a vendored/internal bubblewrap path, that path was no longer covered by the distro AppArmor exception, so sandbox namespace setup could fail even when user namespaces were otherwise enabled and `uidmap` was installed. ## What this PR changes - prefer system `/usr/bin/bwrap` whenever it is available - keep vendored bubblewrap as the fallback when `/usr/bin/bwrap` is missing - when `/usr/bin/bwrap` is missing, surface a Codex startup warning through the app-server/TUI warning path instead of printing directly from the sandbox helper with `eprintln!` - use the same launcher decision for both the main sandbox execution path and the `/proc` preflight path - document the updated Linux bubblewrap behavior in the Linux sandbox and core READMEs ## Why this fix This still fixes the Ubuntu/AppArmor regression from [#14919](https://github.com/openai/codex/issues/14919), but it keeps the runtime rule simple and platform-agnostic: if the standard system bubblewrap is installed, use it; otherwise fall back to the vendored helper. The warning now follows that same simple rule. If Codex cannot find `/usr/bin/bwrap`, it tells the user that it is falling back to the vendored helper, and it does so through the existing startup warning plumbing that reaches the TUI and app-server instead of low-level sandbox stderr. ## Testing - `cargo test -p codex-linux-sandbox` - `cargo test -p codex-app-server --lib` - `cargo test -p codex-tui-app-server tests::embedded_app_server_start_failure_is_returned` - `cargo clippy -p codex-linux-sandbox --all-targets` - `cargo clippy -p codex-app-server --all-targets` - `cargo clippy -p codex-tui-app-server --all-targets`
viyatb-oai ·
2026-03-17 23:05:34 +00:00 -
fix(linux-sandbox): ignore missing writable roots (#14890)
## Summary - skip nonexistent `workspace-write` writable roots in the Linux bubblewrap mount builder instead of aborting sandbox startup - keep existing writable roots mounted normally so mixed Windows/WSL configs continue to work - add unit and Linux integration regression coverage for the missing-root case ## Context This addresses regression A from #14875. Regression B will be handled in a separate PR. The old bubblewrap integration added `ensure_mount_targets_exist` as a preflight guard because bubblewrap bind targets must exist, and failing early let Codex return a clearer error than a lower-level mount failure. That policy turned out to be too strict once bubblewrap became the default Linux sandbox: shared Windows/WSL or mixed-platform configs can legitimately contain a well-formed writable root that does not exist on the current machine. This PR keeps bubblewrap's existing-target requirement, but changes Codex to skip missing writable roots instead of treating them as fatal configuration errors.
viyatb-oai ·
2026-03-17 00:21:00 -07:00 -
fix: canonicalize symlinked Linux sandbox cwd (#14849)
## Problem On Linux, Codex can be launched from a workspace path that is a symlink (for example, a symlinked checkout or a symlinked parent directory). Our sandbox policy intentionally canonicalizes writable/readable roots to the real filesystem path before building the bubblewrap mounts. That part is correct and needed for safety. The remaining bug was that bubblewrap could still inherit the helper process's logical cwd, which might be the symlinked alias instead of the mounted canonical path. In that case, the sandbox starts in a cwd that does not exist inside the sandbox namespace even though the real workspace is mounted. This can cause sandboxed commands to fail in symlinked workspaces. ## Fix This PR keeps the sandbox policy behavior the same, but separates two concepts that were previously conflated: - the canonical cwd used to define sandbox mounts and permissions - the caller's logical cwd used when launching the command On the Linux bubblewrap path, we now thread the logical command cwd through the helper explicitly and only add `--chdir <canonical path>` when the logical cwd differs from the mounted canonical path. That means: - permissions are still computed from canonical paths - bubblewrap starts the command from a cwd that definitely exists inside the sandbox - we do not widen filesystem access or undo the earlier symlink hardening ## Why This Is Safe This is a narrow Linux-only launch fix, not a policy change. - Writable/readable root canonicalization stays intact. - Protected metadata carveouts still operate on canonical roots. - We only override bubblewrap's inherited cwd when the logical path would otherwise point at a symlink alias that is not mounted in the sandbox. ## Tests - kept the existing protocol/core regression coverage for symlink canonicalization - added regression coverage for symlinked cwd handling in the Linux bubblewrap builder/helper path Local validation: - `just fmt` - `cargo test -p codex-protocol` - `cargo test -p codex-core normalize_additional_permissions_canonicalizes_symlinked_write_paths` - `cargo clippy -p codex-linux-sandbox -p codex-protocol -p codex-core --tests -- -D warnings` - `cargo build --bin codex` ## Context This is related to #14694. The earlier writable-root symlink fix addressed the mount/permission side; this PR fixes the remaining symlinked-cwd launch mismatch in the Linux sandbox path.
viyatb-oai ·
2026-03-16 22:39:18 -07:00 -
Apply argument comment lint across codex-rs (#14652)
## Why Once the repo-local lint exists, `codex-rs` needs to follow the checked-in convention and CI needs to keep it from drifting. This commit applies the fallback `/*param*/` style consistently across existing positional literal call sites without changing those APIs. The longer-term preference is still to avoid APIs that require comments by choosing clearer parameter types and call shapes. This PR is intentionally the mechanical follow-through for the places where the existing signatures stay in place. After rebasing onto newer `main`, the rollout also had to cover newly introduced `tui_app_server` call sites. That made it clear the first cut of the CI job was too expensive for the common path: it was spending almost as much time installing `cargo-dylint` and re-testing the lint crate as a representative test job spends running product tests. The CI update keeps the full workspace enforcement but trims that extra overhead from ordinary `codex-rs` PRs. ## What changed - keep a dedicated `argument_comment_lint` job in `rust-ci` - mechanically annotate remaining opaque positional literals across `codex-rs` with exact `/*param*/` comments, including the rebased `tui_app_server` call sites that now fall under the lint - keep the checked-in style aligned with the lint policy by using `/*param*/` and leaving string and char literals uncommented - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo registry/git metadata in the lint job - split changed-path detection so the lint crate's own `cargo test` step runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes - continue to run the repo wrapper over the `codex-rs` workspace, so product-code enforcement is unchanged Most of the code changes in this commit are intentionally mechanical comment rewrites or insertions driven by the lint itself. ## Verification - `./tools/argument-comment-lint/run.sh --workspace` - `cargo test -p codex-tui-app-server -p codex-tui` - parsed `.github/workflows/rust-ci.yml` locally with PyYAML --- * -> #14652 * #14651
Michael Bolin ·
2026-03-16 16:48:15 -07:00 -
fix: reopen writable linux carveouts under denied parents (#14514)
## Summary - preserve Linux bubblewrap semantics for `write -> none -> write` filesystem policies by recreating masked mount targets before rebinding narrower writable descendants - add a Linux runtime regression for `/repo = write`, `/repo/a = none`, `/repo/a/b = write` so the nested writable child is exercised under bubblewrap - document the supported legacy Landlock fallback and the split-policy bubblewrap behavior for overlapping carveouts ## Example Given a split filesystem policy like: ```toml "/repo" = "write" "/repo/a" = "none" "/repo/a/b" = "write" ``` this PR keeps `/repo` writable, masks `/repo/a`, and still reopens `/repo/a/b` as writable again under bubblewrap. ## Testing - `just fmt` - `cargo test -p codex-linux-sandbox` - `cargo clippy -p codex-linux-sandbox --tests -- -D warnings`
viyatb-oai ·
2026-03-13 01:36:06 +00:00 -
fix: preserve split filesystem semantics in linux sandbox (#14173)
## Stack fix: fail closed for unsupported split windows sandboxing #14172 -> fix: preserve split filesystem semantics in linux sandbox #14173 fix: align core approvals with split sandbox policies #14171 refactor: centralize filesystem permissions precedence #14174 ## Summary ## Summary - Preserve Linux split filesystem carveouts in bubblewrap by applying mount masks in the right order, so narrower rules still win under broader writable roots. - Preserve unreadable ancestors of writable roots by masking them first and then rebinding the narrower writable descendants. - Stop rejecting legacy-plus-split Linux configs that are sandbox-equivalent after `cwd` resolution by comparing semantics instead of raw legacy structs. - Fail closed when callers provide partial split policies, mismatched legacy-plus-split policies, or force `--use-legacy-landlock` for split-only shapes that legacy Landlock cannot enforce. - Add Linux regressions for overlapping writable, read-only, and denied paths, and document the supported split-policy enforcement path. ## Example Given a split filesystem policy like: ```toml [permissions.dev.filesystem] ":root" = "read" "/code" = "write" "/code/.git" = "read" "/code/secrets" = "none" "/code/secrets/tmp" = "write" ``` this PR makes Linux enforce the intended result under bubblewrap: - `/code` stays writable - `/code/.git` stays read-only - `/code/secrets` stays denied - `/code/secrets/tmp` can still be reopened as writable if explicitly allowed Before this, Linux could lose one of those carveouts depending on mount order or legacy-policy fallback. This PR keeps the split-policy semantics intact and rejects configurations that legacy Landlock cannot represent safely.
viyatb-oai ·
2026-03-12 10:56:32 -07:00 -
fix: follow up on linux sandbox review nits (#14440)
## Summary - address the follow-up review nits from #13996 in a separate PR - make the approvals test command a raw string and keep the managed-network path using env proxy routing - inline `--apply-seccomp-then-exec` in the Linux sandbox inner command builder - remove the bubblewrap-specific sandbox metric tag path and drop the `use_legacy_landlock` shim from `sandbox_tag`/`TurnMetadataState::new` - restore the `Feature` import that `origin/main` currently still needs in `connectors.rs` ## Testing - `cargo test -p codex-linux-sandbox` - focused `codex-core` tests were rerun/started, but the final verification pass was interrupted when I pushed at request
viyatb-oai ·
2026-03-11 23:59:50 -07:00 -
refactor: make bubblewrap the default Linux sandbox (#13996)
## Summary - make bubblewrap the default Linux sandbox and keep `use_legacy_landlock` as the only override - remove `use_linux_sandbox_bwrap` from feature, config, schema, and docs surfaces - update Linux sandbox selection, CLI/config plumbing, and related tests/docs to match the new default - fold in the follow-up CI fixes for request-permissions responses and Linux read-only sandbox error text
viyatb-oai ·
2026-03-11 23:31:18 -07:00 -
fix(protocol): preserve legacy workspace-write semantics (#13957)
## Summary This is a fast follow to the initial `[permissions]` structure. - keep the new split-policy carveout behavior for narrower non-write entries under broader writable roots - preserve legacy `WorkspaceWrite` semantics by using a cwd-aware bridge that drops only redundant nested readable roots when projecting from `SandboxPolicy` - route the legacy macOS seatbelt adapter through that same legacy bridge so redundant nested readable roots do not become read-only carveouts on macOS - derive the legacy bridge for `command_exec` using the sandbox root cwd rather than the request cwd so policy derivation matches later sandbox enforcement - add regression coverage for the legacy macOS nested-readable-root case ## Examples ### Legacy `workspace-write` on macOS A legacy `workspace-write` policy can redundantly list a nested readable root under an already-writable workspace root. For example, legacy config can effectively mean: - workspace root (`.` / `cwd`) is writable - `docs/` is also listed in `readable_roots` The new shared split-policy helper intentionally treats a narrower non-write entry under a broader writable root as a carveout for real `[permissions]` configs. Without this fast follow, the unchanged macOS seatbelt legacy adapter could project that legacy shape into a `FileSystemSandboxPolicy` that treated `docs/` like a read-only carveout under the writable workspace root. In practice, legacy callers on macOS could unexpectedly lose write access inside `docs/`, even though that path was writable before the `[permissions]` migration work. This change fixes that by routing the legacy seatbelt path through the cwd-aware legacy bridge, so: - legacy `workspace-write` keeps `docs/` writable when `docs/` was only a redundant readable root - explicit `[permissions]` entries like `'.' = 'write'` and `'docs' = 'read'` still make `docs/` read-only, which is the new intended split-policy behavior ### Legacy `command_exec` with a subdirectory cwd `command_exec` can run a command from a request cwd that is narrower than the sandbox root cwd. For example: - sandbox root cwd is `/repo` - request cwd is `/repo/subdir` - legacy policy is still `workspace-write` rooted at `/repo` Before this fast follow, `command_exec` derived the legacy bridge using the request cwd, but the sandbox was later built using the sandbox root cwd. That mismatch could miss redundant legacy readable roots during projection and accidentally reintroduce read-only carveouts for paths that should still be writable under the legacy model. This change fixes that by deriving the legacy bridge with the same sandbox root cwd that sandbox enforcement later uses. ## Verification - `just fmt` - `cargo test -p codex-core seatbelt_legacy_workspace_write_nested_readable_root_stays_writable` - `cargo test -p codex-core test_sandbox_config_parsing` - `cargo clippy -p codex-core -p codex-app-server --all-targets -- -D warnings` - `cargo clean`
viyatb-oai ·
2026-03-09 18:43:27 -07:00 -
linux-sandbox: honor split filesystem policies in bwrap (#13453)
## Why After `#13449`, the Linux helper could receive split filesystem and network policies, but the bubblewrap mount builder still reconstructed filesystem access from the legacy `SandboxPolicy`. That loses explicit unreadable carveouts under writable roots, and it also mishandles `Root` read access paired with explicit deny carveouts. In those cases bubblewrap could still expose paths that the split filesystem policy intentionally blocked. ## What changed - switched bubblewrap mount generation to consume `FileSystemSandboxPolicy` directly at the implementation boundary; legacy `SandboxPolicy` configs still flow through the existing `FileSystemSandboxPolicy::from(&sandbox_policy)` bridge before reaching bwrap - kept the Linux helper and preflight path on the split filesystem policy all the way into bwrap - re-applied explicit unreadable carveouts after readable and writable mounts so blocked subpaths still win under bubblewrap - masked denied directories with `--tmpfs` plus `--remount-ro` and denied files with `--ro-bind-data`, preserving the backing fd until exec - added comments in the unreadable-root masking block to explain why the mount order and directory/file split are intentional - updated Linux helper call sites and tests for the split-policy bwrap path ## Verification - added protocol coverage for root carveouts staying scoped - added core coverage that root-write plus deny carveouts still requires a platform sandbox - added bwrap unit coverage for reapplying blocked carveouts after writable binds - added Linux integration coverage for explicit split-policy carveouts under bubblewrap - validated the final branch state with `cargo test -p codex-linux-sandbox`, `cargo clippy -p codex-linux-sandbox --all-targets -- -D warnings`, and the PR CI reruns --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13453). * __->__ #13453 * #13452 * #13451 * #13449 * #13448 * #13445 * #13440 * #13439 --------- Co-authored-by: viyatb-oai <viyatb@openai.com>
Michael Bolin ·
2026-03-07 23:46:52 -08:00 -
linux-sandbox: plumb split sandbox policies through helper (#13449)
## Why The Linux sandbox helper still only accepted the legacy `SandboxPolicy` payload. That meant the runtime could compute split filesystem and network policies, but the helper would immediately collapse them back to the compatibility projection before applying seccomp or staging the bubblewrap inner command. ## What changed - added hidden `--file-system-sandbox-policy` and `--network-sandbox-policy` flags alongside the legacy `--sandbox-policy` flag so the helper can migrate incrementally - updated the core-side Landlock wrapper to pass the split policies explicitly when launching `codex-linux-sandbox` - added helper-side resolution logic that accepts either the legacy policy alone or a complete split-policy pair and normalizes that into one effective configuration - switched Linux helper network decisions to use `NetworkSandboxPolicy` directly - added `FromStr` support for the split policy types so the helper can parse them from CLI JSON ## Verification - added helper coverage in `linux-sandbox/src/linux_run_main_tests.rs` for split-policy flags and policy resolution - added CLI argument coverage in `core/src/landlock.rs` - verified the current PR state with `just clippy` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13449). * #13453 * #13452 * #13451 * __->__ #13449 * #13448 * #13445 * #13440 * #13439 --------- Co-authored-by: viyatb-oai <viyatb@openai.com>
Michael Bolin ·
2026-03-07 19:40:10 -08:00 -
fix(linux-sandbox): always unshare bwrap userns (#13624)
## Summary - always pass `--unshare-user` in the Linux bubblewrap argv builders - stop relying on bubblewrap's auto-userns behavior, which is skipped for `uid 0` - update argv expectations in tests and document the explicit user namespace behavior The installed Codex binary reproduced the same issue with: - `codex -c features.use_linux_sandbox_bwrap=true sandbox linux -- true` - `bwrap: Creating new namespace failed: Operation not permitted` This happens because Codex asked bubblewrap for mount/pid/network namespaces without explicitly asking for a user namespace. In a root-inside-container environment without ambient `CAP_SYS_ADMIN`, that fails. Adding `--unshare-user` makes bubblewrap create the user namespace first and then the remaining namespaces succeed.
viyatb-oai ·
2026-03-05 21:57:40 +00:00 -
Feat: Preserve network access on read-only sandbox policies (#13409)
## Summary `PermissionProfile.network` could not be preserved when additional or compiled permissions resolved to `SandboxPolicy::ReadOnly`, because `ReadOnly` had no network_access field. This change makes read-only + network enabled representable directly and threads that through the protocol, app-server v2 mirror, and permission- merging logic. ## What changed - Added `network_access: bool` to `SandboxPolicy::ReadOnly` in the core protocol and app-server v2 protocol. - Kept backward compatibility by defaulting the new field to false, so legacy read-only payloads still deserialize unchanged. - Updated `has_full_network_access()` and sandbox summaries to respect read-only network access. - Preserved PermissionProfile.network when: - compiling skill permission profiles into sandbox policies - normalizing additional permissions - merging additional permissions into existing sandbox policies - Updated the approval overlay to show network in the rendered permission rule when requested. - Regenerated app-server schema fixtures for the new v2 wire shape.Celia Chen ·
2026-03-04 02:41:57 +00:00 -
feat(linux-sandbox): support restricted ReadOnlyAccess in bwrap (#12369)
## Summary Implements Linux bubblewrap support for restricted `ReadOnlyAccess` (introduced in #11387) by honoring `readable_roots` and `include_platform_defaults` instead of failing closed. ## What changed - Added a Linux platform-default read allowlist for common system/runtime paths (e.g. /usr, /etc, /lib*, Nix store roots). - Updated the bwrap filesystem mount builder to support restricted read access: - Full-read policies still use `--ro-bind / /` - Restricted-read policies now start from` --tmpfs `/ and add scoped `--ro-bind` mounts - Preserved existing writable-root and protected-subpath behavior (`.git`, `.codex`, etc.). `ReadOnlyAccess::Restricted` was already modeled in protocol, but Linux bwrap still returned `UnsupportedOperation` for restricted read access. This closes that gap for the active Linux filesystem backend. ## Notes Legacy Linux Landlock fallback still fail-closes for restricted read access (unchanged).
viyatb-oai ·
2026-02-27 15:25:50 -08:00 -
feat(linux-sandbox): implement proxy-only egress via TCP-UDS-TCP bridge (#11293)
## Summary - Implement Linux proxy-only routing in `codex-rs/linux-sandbox` with a two-stage bridge: host namespace `loopback TCP proxy endpoint -> UDS`, then bwrap netns `loopback TCP listener -> host UDS`. - Add hidden `--proxy-route-spec` plumbing for outer-to-inner stage handoff. - Fail closed in proxy mode when no valid loopback proxy endpoints can be routed. - Introduce explicit network seccomp modes: `Restricted` (legacy restricted networking) and `ProxyRouted` (allow INET/INET6 for routed proxy access, deny `AF_UNIX` and `socketpair`). - Enforce that proxy bridge/routing is bwrap-only by validating `--apply-seccomp-then-exec` requires `--use-bwrap-sandbox`. - Keep landlock-only flows unchanged (no proxy bridge behavior outside bwrap). --------- Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
viyatb-oai ·
2026-02-21 18:16:34 +00:00 -
chore: remove codex-core public protocol/shell re-exports (#12432)
## Why `codex-rs/core/src/lib.rs` re-exported a broad set of types and modules from `codex-protocol` and `codex-shell-command`. That made it easy for workspace crates to import those APIs through `codex-core`, which in turn hides dependency edges and makes it harder to reduce compile-time coupling over time. This change removes those public re-exports so call sites must import from the source crates directly. Even when a crate still depends on `codex-core` today, this makes dependency boundaries explicit and unblocks future work to drop `codex-core` dependencies where possible. ## What Changed - Removed public re-exports from `codex-rs/core/src/lib.rs` for: - `codex_protocol::protocol` and related protocol/model types (including `InitialHistory`) - `codex_protocol::config_types` (`protocol_config_types`) - `codex_shell_command::{bash, is_dangerous_command, is_safe_command, parse_command, powershell}` - Migrated workspace Rust call sites to import directly from: - `codex_protocol::protocol` - `codex_protocol::config_types` - `codex_protocol::models` - `codex_shell_command` - Added explicit `Cargo.toml` dependencies (`codex-protocol` / `codex-shell-command`) in crates that now import those crates directly. - Kept `codex-core` internal modules compiling by using `pub(crate)` aliases in `core/src/lib.rs` (internal-only, not part of the public API). - Updated the two utility crates that can already drop a `codex-core` dependency edge entirely: - `codex-utils-approval-presets` - `codex-utils-cli` ## Verification - `cargo test -p codex-utils-approval-presets` - `cargo test -p codex-utils-cli` - `cargo check --workspace --all-targets` - `just clippy`Michael Bolin ·
2026-02-20 23:45:35 -08:00 -
fix(linux-sandbox): mount /dev in bwrap sandbox (#12081)
## Summary - Updates the Linux bubblewrap sandbox args to mount a minimal `/dev` using `--dev /dev` instead of only binding `/dev/null`. tools needing entropy (git, crypto libs, etc.) can fail. - Changed mount order so `--dev /dev` is added before writable-root `--bind` mounts, preserving writable `/dev/*` submounts like `/dev/shm` ## Why Fixes sandboxed command failures when reading `/dev/urandom` (and similar standard device-node access). Fixes https://github.com/openai/codex/issues/12056
viyatb-oai ·
2026-02-18 23:27:32 -08:00 -
build(linux-sandbox): always compile vendored bubblewrap on Linux; remove CODEX_BWRAP_ENABLE_FFI (#11498)
## Summary This PR removes the temporary `CODEX_BWRAP_ENABLE_FFI` flag and makes Linux builds always compile vendored bubblewrap support for `codex-linux-sandbox`. ## Changes - Removed `CODEX_BWRAP_ENABLE_FFI` gating from `codex-rs/linux-sandbox/build.rs`. - Linux builds now fail fast if vendored bubblewrap compilation fails (instead of warning and continuing). - Updated fallback/help text in `codex-rs/linux-sandbox/src/vendored_bwrap.rs` to remove references to `CODEX_BWRAP_ENABLE_FFI`. - Removed `CODEX_BWRAP_ENABLE_FFI` env wiring from: - `.github/workflows/rust-ci.yml` - `.github/workflows/bazel.yml` - `.github/workflows/rust-release.yml` --------- Co-authored-by: David Zbarsky <zbarsky@openai.com>
viyatb-oai ·
2026-02-11 21:30:41 -08:00 -
feat: make sandbox read access configurable with
ReadOnlyAccess(#11387)`SandboxPolicy::ReadOnly` previously implied broad read access and could not express a narrower read surface. This change introduces an explicit read-access model so we can support user-configurable read restrictions in follow-up work, while preserving current behavior today. It also ensures unsupported backends fail closed for restricted-read policies instead of silently granting broader access than intended. ## What - Added `ReadOnlyAccess` in protocol with: - `Restricted { include_platform_defaults, readable_roots }` - `FullAccess` - Updated `SandboxPolicy` to carry read-access configuration: - `ReadOnly { access: ReadOnlyAccess }` - `WorkspaceWrite { ..., read_only_access: ReadOnlyAccess }` - Preserved existing behavior by defaulting current construction paths to `ReadOnlyAccess::FullAccess`. - Threaded the new fields through sandbox policy consumers and call sites across `core`, `tui`, `linux-sandbox`, `windows-sandbox`, and related tests. - Updated Seatbelt policy generation to honor restricted read roots by emitting scoped read rules when full read access is not granted. - Added fail-closed behavior on Linux and Windows backends when restricted read access is requested but not yet implemented there (`UnsupportedOperation`). - Regenerated app-server protocol schema and TypeScript artifacts, including `ReadOnlyAccess`. ## Compatibility / rollout - Runtime behavior remains unchanged by default (`FullAccess`). - API/schema changes are in place so future config wiring can enable restricted read access without another policy-shape migration.Michael Bolin ·
2026-02-11 18:31:14 -08:00 -
feat(sandbox): enforce proxy-aware network routing in sandbox (#11113)
## Summary - expand proxy env injection to cover common tool env vars (`HTTP_PROXY`/`HTTPS_PROXY`/`ALL_PROXY`/`NO_PROXY` families + tool-specific variants) - harden macOS Seatbelt network policy generation to route through inferred loopback proxy endpoints and fail closed when proxy env is malformed - thread proxy-aware Linux sandbox flags and add minimal bwrap netns isolation hook for restricted non-proxy runs - add/refresh tests for proxy env wiring, Seatbelt policy generation, and Linux sandbox argument wiring
viyatb-oai ·
2026-02-10 07:44:21 +00:00 -
fix(linux-sandbox): block io_uring syscalls in no-network seccomp policy (#10814)
## Summary - Add seccomp deny rules for `io_uring` syscalls in the Linux sandbox network policy. - Specifically deny: - `SYS_io_uring_setup` - `SYS_io_uring_enter` - `SYS_io_uring_register`
viyatb-oai ·
2026-02-06 11:00:54 -08:00 -
feat(linux-sandbox): add bwrap support (#9938)
## Summary This PR introduces a gated Bubblewrap (bwrap) Linux sandbox path. The curent Linux sandbox path relies on in-process restrictions (including Landlock). Bubblewrap gives us a more uniform filesystem isolation model, especially explicit writable roots with the option to make some directories read-only and granular network controls. This is behind a feature flag so we can validate behavior safely before making it the default. - Added temporary rollout flag: - `features.use_linux_sandbox_bwrap` - Preserved existing default path when the flag is off. - In Bubblewrap mode: - Added internal retry without /proc when /proc mount is not permitted by the host/container.
viyatb-oai ·
2026-02-04 11:13:17 -08:00 -
feat(linux-sandbox): vendor bubblewrap and wire it with FFI (#10413)
## Summary Vendor Bubblewrap into the repo and add minimal build plumbing in `codex-linux-sandbox` to compile/link it. ## Why We want to move Linux sandboxing toward Bubblewrap, but in a safe two-step rollout: 1) vendoring/build setup (this PR), 2) runtime integration (follow-up PR). ## Included - Add `codex-rs/vendor/bubblewrap` sources. - Add build-time FFI path in `codex-rs/linux-sandbox`. - Update `build.rs` rerun tracking for vendored files. - Small vendored compile warning fix (`sockaddr_nl` full init). follow up in https://github.com/openai/codex/pull/9938
viyatb-oai ·
2026-02-02 23:33:46 -08:00 -
revert: remove pre-Landlock bind mounts apply (#9300)
**Description** This removes the pre‑Landlock read‑only bind‑mount step from the Linux sandbox so filesystem restrictions rely solely on Landlock again. `mounts.rs` is kept in place but left unused. The linux‑sandbox README is updated to match the new behavior and manual test expectations.
viyatb-oai ·
2026-01-15 09:47:57 -08:00 -
fix: fallback to Landlock-only when user namespaces unavailable and set PR_SET_NO_NEW_PRIVS early (#9250)
fixes https://github.com/openai/codex/issues/9236 ### Motivation - Prevent sandbox setup from failing when unprivileged user namespaces are denied so Landlock-only protections can still be applied. - Ensure `PR_SET_NO_NEW_PRIVS` is set before installing seccomp and Landlock restrictions to avoid kernel `EPERM`/`LandlockRestrict` ordering issues. ### Description - Add `is_permission_denied` helper that detects `EPERM` / `PermissionDenied` from `CodexErr` to drive fallback logic. - In `apply_read_only_mounts` skip read-only bind-mount setup and return `Ok(())` when `unshare_user_and_mount_namespaces()` fails with permission-denied so Landlock rules can still be installed. - Add `set_no_new_privs()` and call it from `apply_sandbox_policy_to_current_thread` before installing seccomp filters and Landlock rules when disk or network access is restricted.
viyatb-oai ·
2026-01-14 22:24:34 -08:00 -
fix: correct linux sandbox uid/gid mapping after unshare (#9234)
fixes https://github.com/openai/codex/issues/9233 ## Summary - capture effective uid/gid before unshare for user namespace maps - pass captured ids into uid/gid map writer ## Testing - just fmt - just fix -p codex-linux-sandbox - cargo test -p codex-linux-sandbox
viyatb-oai ·
2026-01-14 15:35:53 -08:00 -
feat: add support for read-only bind mounts in the linux sandbox (#9112)
### Motivation - Landlock alone cannot prevent writes to sensitive in-repo files like `.git/` when the repo root is writable, so explicit mount restrictions are required for those paths. - The sandbox must set up any mounts before calling Landlock so Landlock can still be applied afterwards and the two mechanisms compose correctly. ### Description - Add a new `linux-sandbox` helper `apply_read_only_mounts` in `linux-sandbox/src/mounts.rs` that: unshares namespaces, maps uids/gids when required, makes mounts private, bind-mounts targets, and remounts them read-only. - Wire the mount step into the sandbox flow by calling `apply_read_only_mounts(...)` before network/seccomp and before applying Landlock rules in `linux-sandbox/src/landlock.rs`.
viyatb-oai ·
2026-01-14 08:30:46 -08:00 -
fix: introduce AbsolutePathBuf as part of sandbox config (#7856)
Changes the `writable_roots` field of the `WorkspaceWrite` variant of the `SandboxPolicy` enum from `Vec<PathBuf>` to `Vec<AbsolutePathBuf>`. This is helpful because now callers can be sure the value is an absolute path rather than a relative one. (Though when using an absolute path in a Seatbelt config policy, we still have to _canonicalize_ it first.) Because `writable_roots` can be read from a config file, it is important that we are able to resolve relative paths properly using the parent folder of the config file as the base path.
Michael Bolin ·
2025-12-12 15:25:22 -08:00 -
fix: allow sendmsg(2) and recvmsg(2) syscalls in our Linux sandbox (#7779)
This changes our default Landlock policy to allow `sendmsg(2)` and `recvmsg(2)` syscalls. We believe these were originally denied out of an abundance of caution, but given that `send(2)` nor `recv(2)` are allowed today [which provide comparable capability to the `*msg` equivalents], we do not believe allowing them grants any privileges beyond what we already allow. Rather than using the syscall as the security boundary, preventing access to the potentially hazardous file descriptor in the first place seems like the right layer of defense. In particular, this makes it possible for `shell-tool-mcp` to run on Linux when using a read-only sandbox for the Bash process, as demonstrated by `accept_elicitation_for_prompt_rule()` now succeeding in CI.
Michael Bolin ·
2025-12-09 09:24:01 -08:00 -
chore: rework tools execution workflow (#5278)
Re-work the tool execution flow. Read `orchestrator.rs` to understand the structure
jif-oai ·
2025-10-20 20:57:37 +01:00 -
Fix AF_UNIX, sockpair, recvfrom in linux sandbox (#2309)
When using codex-tui on a linux system I was unable to run `cargo clippy` inside of codex due to: ``` [pid 3548377] socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, <unfinished ...> [pid 3548370] close(8 <unfinished ...> [pid 3548377] <... socketpair resumed>0x7ffb97f4ed60) = -1 EPERM (Operation not permitted) ``` And ``` 3611300 <... recvfrom resumed>0x708b8b5cffe0, 8, 0, NULL, NULL) = -1 EPERM (Operation not permitted) ``` This PR: * Fixes a bug that disallowed AF_UNIX to allow it on `socket()` * Adds recvfrom() to the syscall allow list, this should be fine since we disable opening new sockets. But we should validate there is not a open socket inheritance issue. * Allow socketpair to be called for AF_UNIX * Adds tests for AF_UNIX components * All of which allows running `cargo clippy` within the sandbox on linux, and possibly other tooling using a fork server model + AF_UNIX comms.
Parker Thompson ·
2025-08-14 17:12:41 -07:00 -
feat: make .git read-only within a writable root when using Seatbelt (#1765)
To make `--full-auto` safer, this PR updates the Seatbelt policy so that a `SandboxPolicy` with a `writable_root` that contains a `.git/` _directory_ will make `.git/` _read-only_ (though as a follow-up, we should also consider the case where `.git` is a _file_ with a `gitdir: /path/to/actual/repo/.git` entry that should also be protected). The two major changes in this PR: - Updating `SandboxPolicy::get_writable_roots_with_cwd()` to return a `Vec<WritableRoot>` instead of a `Vec<PathBuf>` where a `WritableRoot` can specify a list of read-only subpaths. - Updating `create_seatbelt_command_args()` to honor the read-only subpaths in `WritableRoot`. The logic to update the policy is a fairly straightforward update to `create_seatbelt_command_args()`, but perhaps the more interesting part of this PR is the introduction of an integration test in `tests/sandbox.rs`. Leveraging the new API in #1785, we test `SandboxPolicy` under various conditions, including ones where `$TMPDIR` is not readable, which is critical for verifying the new behavior. To ensure that Codex can run its own tests, e.g.: ``` just codex debug seatbelt --full-auto -- cargo test if_git_repo_is_writable_root_then_dot_git_folder_is_read_only ``` I had to introduce the use of `CODEX_SANDBOX=sandbox`, which is comparable to how `CODEX_SANDBOX_NETWORK_DISABLED=1` was already being used. Adding a comparable change for Landlock will be done in a subsequent PR.
Michael Bolin ·
2025-08-01 16:11:24 -07:00 -
Michael Bolin ·
2025-07-28 08:31:24 -07:00 -
feat: support dotenv (including ~/.codex/.env) (#1653)
This PR adds a `load_dotenv()` helper function to the `codex-common` crate that is available when the `cli` feature is enabled. The function uses [`dotenvy`](https://crates.io/crates/dotenvy) to update the environment from: - `$CODEX_HOME/.env` - `$(pwd)/.env` To test: - ran `printenv OPENAI_API_KEY` to verify the env var exists in my environment - ran `just codex exec hello` to verify the CLI uses my `OPENAI_API_KEY` - ran `unset OPENAI_API_KEY` - ran `just codex exec hello` again and got **ERROR: Missing environment variable: `OPENAI_API_KEY`**, as expected - created `~/.codex/.env` and added `OPENAI_API_KEY=sk-proj-...` (also ran `chmod 400 ~/.codex/.env` for good measure) - ran `just codex exec hello` again and it worked, verifying it picked up `OPENAI_API_KEY` from `~/.codex/.env` Note this functionality was available in the TypeScript CLI: https://github.com/openai/codex/pull/122 and was recently requested over on https://github.com/openai/codex/issues/1262#issuecomment-3093203551.
Michael Bolin ·
2025-07-22 15:54:33 -07:00 -
feat: redesign sandbox config (#1373)
This is a major redesign of how sandbox configuration works and aims to fix https://github.com/openai/codex/issues/1248. Specifically, it replaces `sandbox_permissions` in `config.toml` (and the `-s`/`--sandbox-permission` CLI flags) with a "table" with effectively three variants: ```toml # Safest option: full disk is read-only, but writes and network access are disallowed. [sandbox] mode = "read-only" # The cwd of the Codex task is writable, as well as $TMPDIR on macOS. # writable_roots can be used to specify additional writable folders. [sandbox] mode = "workspace-write" writable_roots = [] # Optional, defaults to the empty list. network_access = false # Optional, defaults to false. # Disable sandboxing: use at your own risk!!! [sandbox] mode = "danger-full-access" ``` This should make sandboxing easier to reason about. While we have dropped support for `-s`, the way it works now is: - no flags => `read-only` - `--full-auto` => `workspace-write` - currently, there is no way to specify `danger-full-access` via a CLI flag, but we will revisit that as part of https://github.com/openai/codex/issues/1254 Outstanding issue: - As noted in the `TODO` on `SandboxPolicy::is_unrestricted()`, we are still conflating sandbox preferences with approval preferences in that case, which needs to be cleaned up.
Michael Bolin ·
2025-06-24 16:59:47 -07:00 -
fix: overhaul how we spawn commands under seccomp/landlock on Linux (#1086)
Historically, we spawned the Seatbelt and Landlock sandboxes in substantially different ways: For **Seatbelt**, we would run `/usr/bin/sandbox-exec` with our policy specified as an arg followed by the original command: https://github.com/openai/codex/blob/d1de7bb383552e8fadd94be79d65d188e00fd562/codex-rs/core/src/exec.rs#L147-L219 For **Landlock/Seccomp**, we would do `tokio::runtime::Builder::new_current_thread()`, _invoke Landlock/Seccomp APIs to modify the permissions of that new thread_, and then spawn the command: https://github.com/openai/codex/blob/d1de7bb383552e8fadd94be79d65d188e00fd562/codex-rs/core/src/exec_linux.rs#L28-L49 While it is neat that Landlock/Seccomp supports applying a policy to only one thread without having to apply it to the entire process, it requires us to maintain two different codepaths and is a bit harder to reason about. The tipping point was https://github.com/openai/codex/pull/1061, in which we had to start building up the `env` in an unexpected way for the existing Landlock/Seccomp approach to continue to work. This PR overhauls things so that we do similar things for Mac and Linux. It turned out that we were already building our own "helper binary" comparable to Mac's `sandbox-exec` as part of the `cli` crate: https://github.com/openai/codex/blob/d1de7bb383552e8fadd94be79d65d188e00fd562/codex-rs/cli/Cargo.toml#L10-L12 We originally created this to build a small binary to include with the Node.js version of the Codex CLI to provide support for Linux sandboxing. Though the sticky bit is that, at this point, we still want to deploy the Rust version of Codex as a single, standalone binary rather than a CLI and a supporting sandboxing binary. To satisfy this goal, we use "the arg0 trick," in which we: * use `std::env::current_exe()` to get the path to the CLI that is currently running * use the CLI as the `program` for the `Command` * set `"codex-linux-sandbox"` as arg0 for the `Command` A CLI that supports sandboxing should check arg0 at the start of the program. If it is `"codex-linux-sandbox"`, it must invoke `codex_linux_sandbox::run_main()`, which runs the CLI as if it were `codex-linux-sandbox`. When acting as `codex-linux-sandbox`, we make the appropriate Landlock/Seccomp API calls and then use `execvp(3)` to spawn the original command, so do _replace_ the process rather than spawn a subprocess. Incidentally, we do this before starting the Tokio runtime, so the process should only have one thread when `execvp(3)` is called. Because the `core` crate that needs to spawn the Linux sandboxing is not a CLI in its own right, this means that every CLI that includes `core` and relies on this behavior has to (1) implement it and (2) provide the path to the sandboxing executable. While the path is almost always `std::env::current_exe()`, we needed to make this configurable for integration tests, so `Config` now has a `codex_linux_sandbox_exe: Option<PathBuf>` property to facilitate threading this through, introduced in https://github.com/openai/codex/pull/1089. This common pattern is now captured in `codex_linux_sandbox::run_with_sandbox()` and all of the `main.rs` functions that should use it have been updated as part of this PR. The `codex-linux-sandbox` crate added to the Cargo workspace as part of this PR now has the bulk of the Landlock/Seccomp logic, which makes `core` a bit simpler. Indeed, `core/src/exec_linux.rs` and `core/src/landlock.rs` were removed/ported as part of this PR. I also moved the unit tests for this code into an integration test, `linux-sandbox/tests/landlock.rs`, in which I use `env!("CARGO_BIN_EXE_codex-linux-sandbox")` as the value for `codex_linux_sandbox_exe` since `std::env::current_exe()` is not appropriate in that case.
Michael Bolin ·
2025-05-23 11:37:07 -07:00