Commit Graph

16 Commits

  • fix(linux-sandbox): isolate Linux sandbox synthetic mount registry per user for shared codex use case (#21234)
    ## Summary
    - make the Linux sandbox synthetic mount registry path unique per
    effective UID
    - keep same-user coordination intact while avoiding collisions between
    users sharing `/tmp`
    - add a regression test for the registry path contract
    
    ## Why
    Issue #21192 reports that the Linux sandbox currently uses one global
    temp path at `/tmp/codex-bwrap-synthetic-mount-targets`. If another user
    creates that directory first, later users can fail to open the shared
    lock file with `Permission denied`.
    
    ## Validation
    - `just fmt`
    - `cargo test -p codex-linux-sandbox`
    - `cargo clippy -p codex-linux-sandbox --all-targets`
    
    Fixes #21192
  • fix(linux-sandbox): avoid panic on bwrap build failures (#21127)
    ## Summary
    
    - Propagate Linux bubblewrap argument-construction failures instead of
    panicking in the helper
    - Keep mutable-symlink carveouts fail-closed while reporting them as
    ordinary sandbox build failures
    - Add regression coverage for a protected `.codex` symlink inside a
    writable workspace root
    
    ## Root cause
    
    Linux bubblewrap intentionally rejects read-only carveouts that cross a
    symlink the sandboxed process can still rewrite. That is the correct
    security behavior for protected metadata paths such as `.codex`.
    
    The bug was one layer higher: `linux_run_main` treated the expected
    build failure as impossible and panicked while constructing the
    bubblewrap argv. For issue #20716, that turned a normal fail-closed
    sandbox outcome into a noisy panic in the transcript.
    
    ## User impact
    
    Users with a project-local `.codex` symlink inside a writable workspace
    still get the conservative sandbox decision, but they no longer see a
    Rust panic for that condition. The helper now exits with the concise
    sandbox-build error so the normal denial / escalation path can handle
    it.
    
    
    Fixes #20716
  • Enforce workspace metadata protections in Linux sandbox (#19852)
    ## Summary
    
    Enforce FileSystemSandboxPolicy protected metadata names in the Linux
    bubblewrap adapter so `.git`, `.agents`, and `.codex` remain read only
    inside writable workspace roots unless the policy grants an explicit
    write carveout.
    
    ## Scope
    
    1. Translate protected metadata names from FileSystemSandboxPolicy into
    bubblewrap masks for existing metadata paths.
    2. Represent missing protected metadata paths as guarded mount targets
    so agents cannot create `.git`, `.agents`, or `.codex` under writable
    roots.
    3. Preserve normal git discovery for existing repos, worktrees, and
    parent repos.
    4. Keep explicit user write grants working when policy allows a
    protected metadata path directly.
    
    ## Not in scope
    
    1. No shell preflight UX.
    2. No TUI runtime profile propagation.
    3. No macOS Seatbelt changes in this PR.
    
    ## Reviewer focus
    
    1. This should be reviewed as the Linux enforcement adapter for the
    policy primitive from PR 19846.
    2. macOS enforcement already landed in PR 19847.
    3. The important invariant is that `FileSystemSandboxPolicy` is the
    source of truth for `.git`, `.agents`, and `.codex`.
    
    ## Validation
    
    1. `git diff` whitespace check passed.
    2. `cargo fmt` check passed with the existing stable rustfmt warning
    about `imports_granularity`.
    3. Full Linux sandbox Cargo test suite passed on the devbox.
    4. Devbox forty six case suite passed at head
    `012accb703c13bd28df5b40079a9bf183036336a`.
    5. Devbox summary: pass 46, fail 0.
    6. The devbox suite was run through `just c sandbox linux`.
    7. Focused repo test for Viyat parent repo case passed on the devbox.
  • linux-sandbox: switch helper plumbing to PermissionProfile (#20106)
    ## Why
    
    `PermissionProfile` is the canonical runtime permission model in the
    Rust workspace, but the Linux sandbox helper still accepted a legacy
    `SandboxPolicy` plus separate filesystem and network policy flags. That
    translation layer made the helper interface harder to reason about and
    left `linux-sandbox`-specific callers and tests coupled to the legacy
    policy representation.
    
    This change moves the helper onto `PermissionProfile` directly so the
    Linux sandbox plumbing matches the rest of the permission stack.
    
    ## What changed
    
    - changed `codex-linux-sandbox` to accept `--permission-profile` and
    derive the runtime filesystem and network policies internally
    - updated the in-process seccomp and legacy Landlock path in
    `codex-rs/linux-sandbox` to operate on `PermissionProfile`
    - updated Linux sandbox argv construction in `codex-rs/sandboxing`,
    `codex-rs/core`, and the CLI debug sandbox path to pass the canonical
    profile instead of serializing compatibility policy projections
    - simplified the Linux sandbox tests to build the exact permission
    profile under test, including the managed-proxy path and
    direct-runtime-enforcement carveout coverage
    - removed helper-local `SandboxPolicy` usage from `bwrap` tests where
    `FileSystemSandboxPolicy` is already the value being exercised
    
    ## Testing
    
    - `cargo test -p codex-sandboxing`
    - `cargo test -p codex-linux-sandbox` (on this macOS host, the crate
    compiled cleanly and its Linux-only tests were cfg-gated)
    - `cargo test -p codex-core --no-run`
    - `cargo test -p codex-cli --no-run`
  • permissions: remove cwd special path (#19841)
    ## Why
    
    The experimental `PermissionProfile` API had both `:cwd` and
    `:project_roots` special filesystem paths, which made the permission
    root ambiguous. This PR removes the unstable `current_working_directory`
    special path before the permissions API is stabilized, so callers use
    `:project_roots` for symbolic project-root access.
    
    ## What changed
    
    - Removes `FileSystemSpecialPath::CurrentWorkingDirectory` from protocol
    and app-server protocol models, plus regenerated app-server
    JSON/TypeScript schemas.
    - Replaces internal `:cwd` permission entries with `:project_roots`
    entries.
    - Keeps the existing cwd-update behavior for legacy-shaped
    workspace-write profiles, while removing the deleted
    `CurrentWorkingDirectory` case from that compatibility path.
    - Keeps `PermissionProfile::workspace_write()` as the reusable symbolic
    workspace-write helper, with docs noting that `:project_roots` entries
    resolve at enforcement time.
    - Updates app-server docs/examples and approval UI labeling to stop
    advertising `:cwd` as a permission token.
    
    ## Compatibility
    
    Persisted rollout items may contain the old
    `{"kind":"current_working_directory"}` tag from earlier experimental
    `permissionProfile` snapshots. This PR keeps that tag as a
    deserialize-only alias for `ProjectRoots { subpath: None }`, while
    continuing to serialize only the new `project_roots` tag.
    
    ## Follow-up
    
    This PR intentionally does not introduce an explicit project-root set on
    `SessionConfiguration` or runtime sandbox resolution. Today, the
    resolver still uses the active cwd as the single implicit project root.
    A follow-up should model project roots separately from tool cwd so
    `:project_roots` entries can resolve against the configured project
    roots, and resolve to no entries when there are no project roots.
    
    ## Verification
    
    - `cargo test -p codex-protocol permissions:: --lib`
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-sandboxing -p codex-exec-server --lib`
    - `cargo test -p codex-core session_configuration_apply_ --lib`
    - `cargo test -p codex-app-server
    command_exec_permission_profile_project_roots_use_command_cwd --test
    all`
    - `cargo test -p codex-tui
    thread_read_session_state_does_not_reuse_primary_permission_profile
    --lib`
    - `cargo test -p codex-tui
    preset_matching_accepts_workspace_write_with_extra_roots --lib`
    - `cargo test -p codex-config --lib`
  • permissions: remove legacy read-only access modes (#19449)
    ## Why
    
    `ReadOnlyAccess` was a transitional legacy shape on `SandboxPolicy`:
    `FullAccess` meant the historical read-only/workspace-write modes could
    read the full filesystem, while `Restricted` tried to carry partial
    readable roots. The partial-read model now belongs in
    `FileSystemSandboxPolicy` and `PermissionProfile`, so keeping it on
    `SandboxPolicy` makes every legacy projection reintroduce lossy
    read-root bookkeeping and creates unnecessary noise in the rest of the
    permissions migration.
    
    This PR makes the legacy policy model narrower and explicit:
    `SandboxPolicy::ReadOnly` and `SandboxPolicy::WorkspaceWrite` represent
    the old full-read sandbox modes only. Split readable roots, deny-read
    globs, and platform-default/minimal read behavior stay in the runtime
    permissions model.
    
    ## What changed
    
    - Removes `ReadOnlyAccess` from
    `codex_protocol::protocol::SandboxPolicy`, including the generated
    `access` and `readOnlyAccess` API fields.
    - Updates legacy policy/profile conversions so restricted filesystem
    reads are represented only by `FileSystemSandboxPolicy` /
    `PermissionProfile` entries.
    - Keeps app-server v2 compatible with legacy `fullAccess` read-access
    payloads by accepting and ignoring that no-op shape, while rejecting
    legacy `restricted` read-access payloads instead of silently widening
    them to full-read legacy policies.
    - Carries Windows sandbox platform-default read behavior with an
    explicit override flag instead of depending on
    `ReadOnlyAccess::Restricted`.
    - Refreshes generated app-server schema/types and updates tests/docs for
    the simplified legacy policy shape.
    
    ## Verification
    
    - `cargo check -p codex-app-server-protocol --tests`
    - `cargo check -p codex-windows-sandbox --tests`
    - `cargo test -p codex-app-server-protocol sandbox_policy_`
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19449).
    * #19395
    * #19394
    * #19393
    * #19392
    * #19391
    * __->__ #19449
  • feat(sandbox): add glob deny-read platform enforcement (#18096)
    ## Summary
    - adds macOS Seatbelt deny rules for unreadable glob patterns
    - expands unreadable glob matches on Linux and masks them in bwrap,
    including canonical symlink targets
    - keeps Linux glob expansion robust when `rg` is unavailable in minimal
    or Bazel test environments
    - adds sandbox integration coverage that runs `shell` and `exec_command`
    with a `**/*.env = none` policy and verifies the secret contents do not
    reach the model
    
    ## Linux glob expansion
    
    ```text
    Prefer:   rg --files --hidden --no-ignore --glob <pattern> -- <search-root>
    Fallback: internal globset walker when rg is not installed
    Failure:  any other rg failure aborts sandbox construction
    ```
    
    ```
    [permissions.workspace.filesystem]
    glob_scan_max_depth = 2
    
    [permissions.workspace.filesystem.":project_roots"]
    "**/*.env" = "none"
    ```
    
    
    This keeps the common path fast without making sandbox construction
    depend on an ambient `rg` binary. If `rg` is present but fails for
    another reason, the sandbox setup fails closed instead of silently
    omitting deny-read masks.
    
    ## Platform support
    - macOS: subprocess sandbox enforcement is handled by Seatbelt regex
    deny rules
    - Linux: subprocess sandbox enforcement is handled by expanding existing
    glob matches and masking them in bwrap
    - Windows: policy/config/direct-tool glob support is already on `main`
    from #15979; Windows subprocess sandbox paths continue to fail closed
    when unreadable split filesystem carveouts require runtime enforcement,
    rather than silently running unsandboxed
    
    ## Stack
    1. #15979 - merged: cross-platform glob deny-read
    policy/config/direct-tool support for macOS, Linux, and Windows
    2. This PR - macOS/Linux subprocess sandbox enforcement plus Windows
    fail-closed clarification
    3. #17740 - managed deny-read requirements
    
    ## Verification
    - Added integration coverage for `shell` and `exec_command` glob
    deny-read enforcement
    - `cargo check -p codex-sandboxing -p codex-linux-sandbox --tests`
    - `cargo check -p codex-core --test all`
    - `cargo clippy -p codex-linux-sandbox -p codex-sandboxing --tests`
    - `just bazel-lock-check`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • chore: clean up argument-comment lint and roll out all-target CI on macOS (#16054)
    ## Why
    
    `argument-comment-lint` was green in CI even though the repo still had
    many uncommented literal arguments. The main gap was target coverage:
    the repo wrapper did not force Cargo to inspect test-only call sites, so
    examples like the `latest_session_lookup_params(true, ...)` tests in
    `codex-rs/tui_app_server/src/lib.rs` never entered the blocking CI path.
    
    This change cleans up the existing backlog, makes the default repo lint
    path cover all Cargo targets, and starts rolling that stricter CI
    enforcement out on the platform where it is currently validated.
    
    ## What changed
    
    - mechanically fixed existing `argument-comment-lint` violations across
    the `codex-rs` workspace, including tests, examples, and benches
    - updated `tools/argument-comment-lint/run-prebuilt-linter.sh` and
    `tools/argument-comment-lint/run.sh` so non-`--fix` runs default to
    `--all-targets` unless the caller explicitly narrows the target set
    - fixed both wrappers so forwarded cargo arguments after `--` are
    preserved with a single separator
    - documented the new default behavior in
    `tools/argument-comment-lint/README.md`
    - updated `rust-ci` so the macOS lint lane keeps the plain wrapper
    invocation and therefore enforces `--all-targets`, while Linux and
    Windows temporarily pass `-- --lib --bins`
    
    That temporary CI split keeps the stricter all-targets check where it is
    already cleaned up, while leaving room to finish the remaining Linux-
    and Windows-specific target-gated cleanup before enabling
    `--all-targets` on those runners. The Linux and Windows failures on the
    intermediate revision were caused by the wrapper forwarding bug, not by
    additional lint findings in those lanes.
    
    ## Validation
    
    - `bash -n tools/argument-comment-lint/run.sh`
    - `bash -n tools/argument-comment-lint/run-prebuilt-linter.sh`
    - shell-level wrapper forwarding check for `-- --lib --bins`
    - shell-level wrapper forwarding check for `-- --tests`
    - `just argument-comment-lint`
    - `cargo test` in `tools/argument-comment-lint`
    - `cargo test -p codex-terminal-detection`
    
    ## Follow-up
    
    - Clean up remaining Linux-only target-gated callsites, then switch the
    Linux lint lane back to the plain wrapper invocation.
    - Clean up remaining Windows-only target-gated callsites, then switch
    the Windows lint lane back to the plain wrapper invocation.
  • fix: fix old system bubblewrap compatibility without falling back to vendored bwrap (#15693)
    Fixes #15283.
    
    ## Summary
    Older system bubblewrap builds reject `--argv0`, which makes our Linux
    sandbox fail before the helper can re-exec. This PR keeps using system
    `/usr/bin/bwrap` whenever it exists and only falls back to vendored
    bwrap when the system binary is missing. That matters on stricter
    AppArmor hosts, where the distro bwrap package also provides the policy
    setup needed for user namespaces.
    
    For old system bwrap, we avoid `--argv0` instead of switching binaries:
    - pass the sandbox helper a full-path `argv0`,
    - keep the existing `current_exe() + --argv0` path when the selected
    launcher supports it,
    - otherwise omit `--argv0` and re-exec through the helper's own
    `argv[0]` path, whose basename still dispatches as
    `codex-linux-sandbox`.
    
    Also updates the launcher/warning tests and docs so they match the new
    behavior: present-but-old system bwrap uses the compatibility path, and
    only absent system bwrap falls back to vendored.
    
    ### Validation
    
    1. Install Ubuntu 20.04 in a VM
    2. Compile codex and run without bubblewrap installed - see a warning
    about falling back to the vendored bwrap
    3. Install bwrap and verify version is 0.4.0 without `argv0` support
    4. run codex and use apply_patch tool without errors
    
    <img width="802" height="631" alt="Screenshot 2026-03-25 at 11 48 36 PM"
    src="https://github.com/user-attachments/assets/77248a29-aa38-4d7c-9833-496ec6a458b8"
    />
    <img width="807" height="634" alt="Screenshot 2026-03-25 at 11 47 32 PM"
    src="https://github.com/user-attachments/assets/5af8b850-a466-489b-95a6-455b76b5050f"
    />
    <img width="812" height="635" alt="Screenshot 2026-03-25 at 11 45 45 PM"
    src="https://github.com/user-attachments/assets/438074f0-8435-4274-a667-332efdd5cb57"
    />
    <img width="801" height="623" alt="Screenshot 2026-03-25 at 11 43 56 PM"
    src="https://github.com/user-attachments/assets/0dc8d3f5-e8cf-4218-b4b4-a4f7d9bf02e3"
    />
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • 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.
  • 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.
  • 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
  • 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>
  • 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>
  • 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.
  • 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>