Commit Graph

110 Commits

  • linux-sandbox: use standalone bundled bwrap (#21255)
    **Summary**
    - Add `codex-bwrap`, a standalone `bwrap` binary built from the existing
    vendored bubblewrap sources.
    - Remove the linked vendored bwrap path from `codex-linux-sandbox`;
    runtime now prefers system `bwrap` and falls back to bundled
    `codex-resources/bwrap`.
    - Add bundled SHA-256 verification with missing/all-zero digest as the
    dev-mode skip value, then exec the verified file through
    `/proc/self/fd`.
    - Keep `launcher.rs` focused on choosing and dispatching the preferred
    launcher. Bundled lookup, digest verification, and bundled exec now live
    in `linux-sandbox/src/bundled_bwrap.rs`; Bazel runfiles lookup lives in
    `linux-sandbox/src/bazel_bwrap.rs`; shared argv/fd exec helpers live in
    `linux-sandbox/src/exec_util.rs`.
    - Teach Bazel tests to surface the Bazel-built `//codex-rs/bwrap:bwrap`
    through `CARGO_BIN_EXE_bwrap`; `codex-linux-sandbox` only honors that
    fallback in debug Bazel runfiles environments so release/user runtime
    lookup stays tied to `codex-resources/bwrap`.
    - Allow `codex-exec-server` filesystem helpers to preserve just the
    Bazel bwrap/runfiles variables they need in debug Bazel builds, since
    those helpers intentionally rebuild a small environment before spawning
    `codex-linux-sandbox`.
    - Verify the Bazel bwrap target in Linux release CI with a build-only
    check. Running `bwrap --version` is too strong for GitHub runners
    because bubblewrap still attempts namespace setup there.
    
    **Verification**
    - Latest update: `cargo test -p codex-linux-sandbox`
    - Latest update: `just fix -p codex-linux-sandbox`
    - `cargo check --target x86_64-unknown-linux-gnu -p codex-linux-sandbox`
    could not run locally because this macOS machine does not have
    `x86_64-linux-gnu-gcc`; GitHub Linux Bazel CI is expected to cover the
    Linux-only modules.
    - Earlier in this PR: `cargo test -p codex-bwrap`
    - Earlier in this PR: `cargo test -p codex-exec-server`
    - Earlier in this PR: `cargo check --release -p codex-exec-server`
    - Earlier in this PR: `just fix -p codex-linux-sandbox -p
    codex-exec-server`
    - Earlier in this PR: `bazel test --nobuild
    //codex-rs/linux-sandbox:linux-sandbox-all-test
    //codex-rs/core:core-all-test
    //codex-rs/exec-server:exec-server-file_system-test
    //codex-rs/app-server:app-server-all-test` (analysis completed; Bazel
    then refuses to run tests under `--nobuild`)
    - Earlier in this PR: `bazel build --nobuild //codex-rs/bwrap:bwrap`
    - Prior to this update: `just bazel-lock-update`, `just
    bazel-lock-check`, and YAML parse check for
    `.github/workflows/bazel.yml`
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/21255).
    * #21257
    * #21256
    * __->__ #21255
  • Add cloud executor registration to exec-server (#19575)
    ## Summary
    This PR adds the first `codex-rs` milestone for remote-exec e2e: a local
    `codex exec-server` can now register itself with
    `codex-cloud-environments` and attach to the returned rendezvous
    websocket.
    
    At a high level, `codex exec-server --cloud ...` now:
    - loads ChatGPT auth from normal Codex config
    - registers an executor with `codex-cloud-environments`
    - receives a signed rendezvous websocket URL
    - serves the existing exec-server JSON-RPC protocol over that websocket
    
    ## What Changed
    - Added `--cloud`, `--cloud-base-url`, `--cloud-environment-id`, and
    `--cloud-name` to `codex exec-server`
    - Added a new `exec-server/src/cloud.rs` module that handles:
      - registration requests
      - auth/header setup
      - bounded auth retry on `401/403`
      - reconnect/backoff after websocket disconnects
    - Reused the existing `ConnectionProcessor` / `ExecServerHandler` path
    so cloud mode serves the same exec/filesystem RPC surface as local
    websocket mode
    - Added cloud-specific error variants and minimal docs for the new mode
    
    ## Testing
    Manual e2e test that fully goes through exec server flow with our codex
    cloud agent as orchestrator
  • Add stdio exec-server listener (#20663)
    ## Why
    
    This stack adds configured exec-server environments, including
    environments reached over stdio. Before client-side stdio transports or
    config can use that path, the exec-server binary itself needs a
    first-class stdio listen mode so it can speak the same JSON-RPC protocol
    over stdin/stdout that it already speaks over websockets.
    
    **Stack position:** this is PR 1 of 5. It is the server-side transport
    foundation for the stack.
    
    ## What Changed
    
    - Accept `stdio` and `stdio://` for `codex exec-server --listen`.
    - Promote the existing stdio `JsonRpcConnection` helper from test-only
    code into normal exec-server transport code.
    - Add parse coverage for stdio listen URLs while preserving the existing
    websocket default.
    
    ## Stack
    
    - **1. This PR:** https://github.com/openai/codex/pull/20663 - Add stdio
    exec-server listener
    - 2. https://github.com/openai/codex/pull/20664 - Add stdio exec-server
    client transport
    - 3. https://github.com/openai/codex/pull/20665 - Make environment
    providers own default selection
    - 4. https://github.com/openai/codex/pull/20666 - Add CODEX_HOME
    environments TOML provider
    - 5. https://github.com/openai/codex/pull/20667 - Load configured
    environments from CODEX_HOME
    
    Split from original draft: https://github.com/openai/codex/pull/20508
    
    ## Validation
    
    Not run locally; this was split out of the original draft stack.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix(linux-sandbox): fall back when system bwrap lacks perms (#20628)
    ## Why
    
    Codex `0.128` started using `--perms` in more routine Linux sandbox
    construction when protected workspace metadata mounts landed in #19852.
    Upstream bubblewrap added `--perms` in `v0.5.0`, so system `bwrap`
    versions older than that, including the `v0.4.0` and `v0.4.1` family, do
    not support the flag. The launcher still selected those binaries as long
    as they existed on `PATH`.
    
    That means affected hosts can fail every sandboxed command up front
    with:
    
    ```text
    bwrap: Unknown option --perms
    ```
    
    The reports in #20590 and duplicate #20623 match that compatibility gap;
    #20623 explicitly shows system bubblewrap `0.4.0`.
    
    ## What changed
    
    - Replace the single `--argv0` probe with a small system-bwrap
    capability probe in `codex-rs/linux-sandbox/src/launcher.rs`.
    - Continue using the old-system `--argv0` compatibility path when
    needed, but only select a system `bwrap` if it also advertises
    `--perms`.
    - Fall back to the vendored `bwrap` when the system binary is too old
    for the flags Codex now requires.
    - Add regression coverage for the old-system-bwrap case so binaries
    without `--perms` stay on the vendored path.
    
    ## Verification
    
    - Added `falls_back_to_vendored_when_system_bwrap_lacks_perms` to cover
    the reported compatibility gap.
    - Ran `cargo test -p codex-linux-sandbox` and `cargo clippy -p
    codex-linux-sandbox --tests` locally. On macOS, the crate builds but its
    Linux-only tests are cfg-gated out, so the new regression test still
    needs Linux CI or a Linux devbox run for real execution coverage.
    
    ## Related issues
    
    - Fixes #20590
    - Duplicate report: #20623
  • Add environment provider snapshot (#20058)
    ## Summary
    - Change `EnvironmentProvider` to return concrete `Environment`
    instances instead of `EnvironmentConfigurations`.
    - Make `DefaultEnvironmentProvider` provide the provider-visible `local`
    environment plus optional `remote` environment from
    `CODEX_EXEC_SERVER_URL`.
    - Keep `EnvironmentManager` as the concrete cache while exposing its own
    explicit local environment for `local_environment()` fallback paths.
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Refactor exec-server filesystem API into codex-file-system (#19892)
    ## Summary
    - Extracted the shared filesystem types and `ExecutorFileSystem` trait
    into a new `codex-file-system` crate
    - Switched `codex-config` and `codex-git-utils` to depend on that crate
    instead of `codex-exec-server`
    - Kept `codex-exec-server` re-exporting the same API for existing
    callers
    
    ## Testing
    - Ran `cargo test -p codex-file-system`
    - Ran `cargo test -p codex-git-utils`
    - Ran `cargo test -p codex-config`
    - Ran `cargo test -p codex-exec-server`
    - Ran `just fix -p codex-file-system`, `just fix -p codex-git-utils`,
    `just fix -p codex-config`, `just fix -p codex-exec-server`
    - Ran `just fmt`
    - Updated and verified the Bazel module lockfile
  • 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`
  • [codex] Move config loading into codex-config (#19487)
    ## Why
    
    Config loading had become split across crates: `codex-config` owned the
    config types and merge logic, while `codex-core` still owned the loader
    that assembled the layer stack. This change consolidates that
    responsibility in `codex-config`, so the crate that defines config
    behavior also owns how configs are discovered and loaded.
    
    To make that move possible without reintroducing the old dependency
    cycle, the shell-environment policy types and helpers that
    `codex-exec-server` needs now live in `codex-protocol` instead of
    flowing through `codex-config`.
    
    This also makes the migrated loader tests more deterministic on machines
    that already have managed or system Codex config installed by letting
    tests override the system config and requirements paths instead of
    reading the host's `/etc/codex`.
    
    ## What Changed
    
    - moved the config loader implementation from `codex-core` into
    `codex-config::loader` and deleted the old `core::config_loader` module
    instead of leaving a compatibility shim
    - moved shell-environment policy types and helpers into
    `codex-protocol`, then updated `codex-exec-server` and other downstream
    crates to import them from their new home
    - updated downstream callers to use loader/config APIs from
    `codex-config`
    - added test-only loader overrides for system config and requirements
    paths so loader-focused tests do not depend on host-managed config state
    - cleaned up now-unused dependency entries and platform-specific cfgs
    that were surfaced by post-push CI
    
    ## Testing
    
    - `cargo test -p codex-config`
    - `cargo test -p codex-core config_loader_tests::`
    - `cargo test -p codex-protocol -p codex-exec-server -p
    codex-cloud-requirements -p codex-rmcp-client --lib`
    - `cargo test --lib -p codex-app-server-client -p codex-exec`
    - `cargo test --no-run --lib -p codex-app-server`
    - `cargo test -p codex-linux-sandbox --lib`
    - `cargo shear`
    - `just bazel-lock-check`
    
    ## Notes
    
    - I did not chase unrelated full-suite failures outside the migrated
    loader surface.
    - `cargo test -p codex-core --lib` still hits unrelated proxy-sensitive
    failures on this machine, and Windows CI still shows unrelated
    long-running/timeouting test noise outside the loader migration itself.
  • permissions: make runtime config profile-backed (#19606)
    ## Why
    
    This supersedes #19391. During stack repair, GitHub marked #19391 as
    merged into a temporary stack branch rather than into `main`, so the
    runtime-config change needed a fresh PR.
    
    `PermissionProfile` is now the canonical permissions shape after #19231
    because it can distinguish `Managed`, `Disabled`, and `External`
    enforcement while also carrying filesystem rules that legacy
    `SandboxPolicy` cannot represent cleanly. Core config and session state
    still needed to accept profile-backed permissions without forcing every
    profile through the strict legacy bridge, which rejected valid runtime
    profiles such as direct write roots.
    
    The unrelated CI/test hardening that previously rode along with this PR
    has been split into #19683 so this PR stays focused on the permissions
    model migration.
    
    ## What Changed
    
    - Adds `Permissions.permission_profile` and
    `SessionConfiguration.permission_profile` as constrained runtime state,
    while keeping `sandbox_policy` as a legacy compatibility projection.
    - Introduces profile setters that keep `PermissionProfile`, split
    filesystem/network policies, and legacy `SandboxPolicy` projections
    synchronized.
    - Uses a compatibility projection for requirement checks and legacy
    consumers instead of rejecting profiles that cannot round-trip through
    `SandboxPolicy` exactly.
    - Updates config loading, config overrides, session updates, turn
    context plumbing, prompt permission text, sandbox tags, and exec request
    construction to carry profile-backed runtime permissions.
    - Preserves configured deny-read entries and `glob_scan_max_depth` when
    command/session profiles are narrowed.
    - Adds `PermissionProfile::read_only()` and
    `PermissionProfile::workspace_write()` presets that match legacy
    defaults.
    
    ## Verification
    
    - `cargo test -p codex-core direct_write_roots`
    - `cargo test -p codex-core runtime_roots_to_legacy_projection`
    - `cargo test -p codex-app-server
    requested_permissions_trust_project_uses_permission_profile_intent`
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19606).
    * #19395
    * #19394
    * #19393
    * #19392
    * __->__ #19606
  • 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
  • permissions: make legacy profile conversion cwd-free (#19414)
    ## Why
    
    The profile conversion path still required a `cwd` even when it was only
    translating a legacy `SandboxPolicy` into a `PermissionProfile`. That
    made profile producers invent an ambient `cwd`, which is exactly the
    anchoring we are trying to remove from permission-profile data. A legacy
    workspace-write policy can be represented symbolically instead: `:cwd =
    write` plus read-only `:project_roots` metadata subpaths.
    
    This PR creates that cwd-free base so the rest of the stack can stop
    threading cwd through profile construction. Callers that actually need a
    concrete runtime filesystem policy for a specific cwd still have an
    explicitly named cwd-bound conversion.
    
    ## What Changed
    
    - `PermissionProfile::from_legacy_sandbox_policy` now takes only
    `&SandboxPolicy`.
    - `FileSystemSandboxPolicy::from_legacy_sandbox_policy` is now the
    symbolic, cwd-free projection for profiles.
    - The old concrete projection is retained as
    `FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd` for
    runtime/boundary code that must materialize legacy cwd behavior.
    - Workspace-write profiles preserve `CurrentWorkingDirectory` and
    `ProjectRoots` special entries instead of materializing cwd into
    absolute paths.
    
    ## Verification
    
    - `cargo check -p codex-protocol -p codex-core -p
    codex-app-server-protocol -p codex-app-server -p codex-exec -p
    codex-exec-server -p codex-tui -p codex-sandboxing -p
    codex-linux-sandbox -p codex-analytics --tests`
    - `just fix -p codex-protocol -p codex-core -p codex-app-server-protocol
    -p codex-app-server -p codex-exec -p codex-exec-server -p codex-tui -p
    codex-sandboxing -p codex-linux-sandbox -p codex-analytics`
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19414).
    * #19395
    * #19394
    * #19393
    * #19392
    * #19391
    * __->__ #19414
  • permissions: make profiles represent enforcement (#19231)
    ## Why
    
    `PermissionProfile` is becoming the canonical permissions abstraction,
    but the old shape only carried optional filesystem and network fields.
    It could describe allowed access, but not who is responsible for
    enforcing it. That made `DangerFullAccess` and `ExternalSandbox` lossy
    when profiles were exported, cached, or round-tripped through app-server
    APIs.
    
    The important model change is that active permissions are now a disjoint
    union over the enforcement mode. Conceptually:
    
    ```rust
    pub enum PermissionProfile {
        Managed {
            file_system: FileSystemSandboxPolicy,
            network: NetworkSandboxPolicy,
        },
        Disabled,
        External {
            network: NetworkSandboxPolicy,
        },
    }
    ```
    
    This distinction matters because `Disabled` means Codex should apply no
    outer sandbox at all, while `External` means filesystem isolation is
    owned by an outside caller. Those are not equivalent to a broad managed
    sandbox. For example, macOS cannot nest Seatbelt inside Seatbelt, so an
    inner sandbox may require the outer Codex layer to use no sandbox rather
    than a permissive one.
    
    ## How Existing Modeling Maps
    
    Legacy `SandboxPolicy` remains a boundary projection, but it now maps
    into the higher-fidelity profile model:
    
    - `ReadOnly` and `WorkspaceWrite` map to `PermissionProfile::Managed`
    with restricted filesystem entries plus the corresponding network
    policy.
    - `DangerFullAccess` maps to `PermissionProfile::Disabled`, preserving
    the “no outer sandbox” intent instead of treating it as a lax managed
    sandbox.
    - `ExternalSandbox { network_access }` maps to
    `PermissionProfile::External { network }`, preserving external
    filesystem enforcement while still carrying the active network policy.
    - Split runtime policies that legacy `SandboxPolicy` cannot faithfully
    express, such as managed unrestricted filesystem plus restricted
    network, stay `Managed` instead of being collapsed into
    `ExternalSandbox`.
    - Per-command/session/turn grants remain partial overlays via
    `AdditionalPermissionProfile`; full `PermissionProfile` is reserved for
    complete active runtime permissions.
    
    ## What Changed
    
    - Change active `PermissionProfile` into a tagged union: `managed`,
    `disabled`, and `external`.
    - Keep partial permission grants separate with
    `AdditionalPermissionProfile` for command/session/turn overlays.
    - Represent managed filesystem permissions as either `restricted`
    entries or `unrestricted`; `glob_scan_max_depth` is non-zero when
    present.
    - Preserve old rollout compatibility by accepting the pre-tagged `{
    network, file_system }` profile shape during deserialization.
    - Preserve fidelity for important edge cases: `DangerFullAccess`
    round-trips as `disabled`, `ExternalSandbox` round-trips as `external`,
    and managed unrestricted filesystem + restricted network stays managed
    instead of being mistaken for external enforcement.
    - Preserve configured deny-read entries and bounded glob scan depth when
    full profiles are projected back into runtime policies, including
    unrestricted replacements that now become `:root = write` plus deny
    entries.
    - Regenerate the experimental app-server v2 JSON/TypeScript schema and
    update the `command/exec` README example for the tagged
    `permissionProfile` shape.
    
    ## Compatibility
    
    Legacy `SandboxPolicy` remains available at config/API boundaries as the
    compatibility projection. Existing rollout lines with the old
    `PermissionProfile` shape continue to load. The app-server
    `permissionProfile` field is experimental, so its v2 wire shape is
    intentionally updated to match the higher-fidelity model.
    
    ## Verification
    
    - `just write-app-server-schema`
    - `cargo check --tests`
    - `cargo test -p codex-protocol permission_profile`
    - `cargo test -p codex-protocol
    preserving_deny_entries_keeps_unrestricted_policy_enforceable`
    - `cargo test -p codex-app-server-protocol
    permission_profile_file_system_permissions`
    - `cargo test -p codex-app-server-protocol serialize_client_response`
    - `cargo test -p codex-core
    session_configured_reports_permission_profile_for_external_sandbox`
    - `just fix`
    - `just fix -p codex-protocol`
    - `just fix -p codex-app-server-protocol`
    - `just fix -p codex-core`
    - `just fix -p codex-app-server`
  • Add sticky environment API and thread state (#18897)
    ## Summary
    - add sticky environment selections to app-server v2 thread/start and
    turn/start request flow
    - carry thread-level selections through core session/thread state
    - add app-server coverage for sticky selections and turn overrides
    
    ## Stack
    1. This PR: API and thread persistence
    2. #18898: config.toml named environment loading
    3. #18899: downstream tool/runtime consumers
    
    ## Validation
    - Not run locally; split only.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix(exec-server): retain output until streams close (#18946)
    ## Why
    
    A Mac Bazel run hit a flake in
    `server::handler::tests::output_and_exit_are_retained_after_notification_receiver_closes`
    where the read path observed process exit but lost the expected buffered
    stdout (`first\nsecond\n`). See the [GitHub Actions
    job](https://github.com/openai/codex/actions/runs/24758468552/job/72436716505)
    and [BuildBuddy
    invocation](https://app.buildbuddy.io/invocation/37475a12-4ef2-45fb-ab8a-e49a2aba1d59).
    
    The underlying race is that process exit is not the same thing as
    stdout/stderr closure. If a child or grandchild inherits the pipe write
    end, or a process duplicates it with `dup2`, the watched process can
    exit while the stream is still open and more output can still arrive.
    The exec-server was starting exited-process retention cleanup from the
    exit event, so the process entry could be removed before the output
    streams had actually closed.
    
    While stress-testing the exec-server unit suite,
    `server::handler::tests::long_poll_read_fails_after_session_resume`
    exposed a separate test race: it started a short-lived command that
    could exit and wake the pending long-poll read before the session-resume
    assertion observed the resumed-session error. That test is intended to
    cover resume eviction, not process-exit delivery, so this change keeps
    the process alive and quiet while the second connection resumes the
    session.
    
    ## What changed
    
    - Keep exec-server process entries retained until stdout/stderr streams
    close, then start the post-exit retention timer from the closed event.
    - Wake long-poll readers when the closed event is emitted.
    - Add focused `local_process` unit coverage that proves late output is
    still retained after the short test retention interval has elapsed, and
    that closed process entries are eventually evicted.
    - Add a local and remote regression test where a parent exits while a
    child keeps inherited stdout open. The child waits on an explicit
    release file, so the test deterministically observes exit first,
    releases the child, then requires a nonzero-wait read from the exit
    sequence to receive the late output.
    - In `codex-rs/exec-server/src/server/handler/tests.rs`, make
    `long_poll_read_fails_after_session_resume` run a long-lived silent
    command instead of a short command that prints and exits. This isolates
    the test to session-resume behavior and prevents a normal process exit
    from satisfying the pending long-poll read first.
    
    ## Testing
    
    - `cargo test -p codex-exec-server
    exec_process_retains_output_after_exit_until_streams_close`
    - `cargo test -p codex-exec-server local_process::tests`
    - `cargo test -p codex-exec-server`
    - `just fix -p codex-exec-server`
    - `bazel test //codex-rs/exec-server:exec-server-unit-tests
    //codex-rs/exec-server:exec-server-exec_process-test
    //codex-rs/exec-server:exec-server-file_system-test
    //codex-rs/exec-server:exec-server-http_client-test
    //codex-rs/exec-server:exec-server-initialize-test
    //codex-rs/exec-server:exec-server-process-test
    //codex-rs/exec-server:exec-server-websocket-test`
    - `bazel test --runs_per_test=25
    //codex-rs/exec-server:exec-server-unit-tests`
    
    ## Documentation
    
    No docs update needed; this is an internal exec-server correctness fix.
  • exec-server: wait for close after observed exit (#19130)
    ## Why
    
    Windows CI can flake in
    `server::handler::tests::output_and_exit_are_retained_after_notification_receiver_closes`
    after a process has exited but before both output streams have closed.
    `exec/read` returned immediately whenever `exited` was true, so callers
    that had already observed the exit event could spin instead of
    long-polling for the later `closed` state.
    
    ## What Changed
    
    - Keep returning immediately when a terminal exit event is newly
    observable.
    - Allow later reads, after the caller has advanced past that event, to
    wait for `closed` or new output until `wait_ms` expires.
    
    ## Verification
    
    - CI pending.
  • [3/4] Add executor-backed RMCP HTTP client (#18583)
    ### Why
    The RMCP layer needs a Streamable HTTP client that can talk either
    directly over `reqwest` or through the executor HTTP runner without
    duplicating MCP session logic higher in the stack. This PR adds that
    client-side transport boundary so remote Streamable HTTP MCP can reuse
    the same RMCP flow as the local path.
    
    ### What
    - Add a shared `rmcp-client/src/streamable_http/` module with:
      - `transport_client.rs` for the local-or-remote transport enum
      - `local_client.rs` for the direct `reqwest` implementation
      - `remote_client.rs` for the executor-backed implementation
      - `common.rs` for the small shared Streamable HTTP helpers
    - Teach `RmcpClient` to build Streamable HTTP transports in either local
    or remote mode while keeping the existing OAuth ownership in RMCP.
    - Translate remote POST, GET, and DELETE session operations into
    executor `http/request` calls.
    - Preserve RMCP session expiry handling and reconnect behavior for the
    remote transport.
    - Add remote transport coverage in
    `rmcp-client/tests/streamable_http_remote.rs` and keep the shared test
    support in `rmcp-client/tests/streamable_http_test_support.rs`.
    
    ### Verification
    - `cargo check -p codex-rmcp-client`
    - online CI
    
    ### Stack
    1. #18581 protocol
    2. #18582 runner
    3. #18583 RMCP client
    4. #18584 manager wiring and local/remote coverage
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • exec-server: require explicit filesystem sandbox cwd (#19046)
    ## Why
    
    This is a cleanup PR for the `PermissionProfile` migration stack. #19016
    fixed remote exec-server sandbox contexts so Docker-backed filesystem
    requests use a request/container `cwd` instead of leaking the local test
    runner `cwd`. That exposed the broader API problem:
    `FileSystemSandboxContext::new(SandboxPolicy)` could still reconstruct
    filesystem permissions by reading the exec-server process cwd with
    `AbsolutePathBuf::current_dir()`.
    
    That made `cwd`-dependent legacy entries, such as `:cwd`,
    `:project_roots`, and relative deny globs, depend on ambient process
    state instead of the request sandbox `cwd`. As later PRs make
    `PermissionProfile` the primary permissions abstraction, sandbox
    contexts should be explicit about whether they carry a request `cwd` or
    are profile-only. Removing the implicit constructor prevents new call
    sites from accidentally rebuilding permissions against the wrong `cwd`.
    
    ## What changed
    
    - Removed `FileSystemSandboxContext::new(SandboxPolicy)`.
    - Kept production callers on explicit constructors:
    `from_legacy_sandbox_policy(..., cwd)`, `from_permission_profile(...)`,
    and `from_permission_profile_with_cwd(...)`.
    - Updated exec-server test helpers to construct `PermissionProfile`
    values directly instead of routing through legacy `SandboxPolicy`
    projections.
    - Updated the environment regression test to use an explicit restricted
    profile with no synthetic `cwd`.
    
    ## Verification
    
    - `cargo test -p codex-exec-server`
    - `just fix -p codex-exec-server`
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19046).
    * #18288
    * #18287
    * #18286
    * #18285
    * #18284
    * #18283
    * #18282
    * #18281
    * #18280
    * __->__ #19046
  • exec-server: expose arg0 alias root to fs sandbox (#19016)
    ## Why
    
    The post-merge `rust-ci-full` run for #18999 still failed the Ubuntu
    remote `suite::remote_env` sandboxed filesystem tests. That run checked
    out merge commit `ddde50c611e4800cb805f243ed3c50bbafe7d011`, so the arg0
    guard lifetime fix was present.
    
    The Docker-backed failure had two remaining pieces:
    
    - The sandboxed filesystem helper needs to execute Codex through the
    `codex-linux-sandbox` arg0 alias path. The helper sandbox was only
    granting read access to the real Codex executable parent, so the alias
    parent also has to be visible inside the helper sandbox.
    - The remote-env tests were building sandbox contexts with
    `FileSystemSandboxContext::new()`, which captures the local test runner
    cwd. In the Docker remote exec-server, that host checkout path does not
    exist, so spawning the filesystem helper failed with `No such file or
    directory` before the helper could process the request.
    
    ## What Changed
    
    - Track all helper runtime read roots instead of a single root.
    - Add both the real Codex executable parent and the
    `codex-linux-sandbox` alias parent to sandbox readable roots.
    - Avoid sending an unused local cwd in remote filesystem sandbox
    contexts when the permission profile has no cwd-dependent entries.
    - Build the Docker remote-env test sandbox contexts with a cwd path that
    exists inside the container.
    - Add unit coverage for the alias-parent root and remote sandbox cwd
    handling.
    
    ## Verification
    
    - `cargo test -p codex-exec-server`
    - `cargo test -p codex-core
    remote_test_env_sandboxed_read_allows_readable_root`
    - `just fix -p codex-exec-server`
    - `just fix -p codex-core`
  • [2/4] Implement executor HTTP request runner (#18582)
    ### Why
    Remote streamable HTTP MCP needs the executor to perform ordinary HTTP
    requests on the executor side. This keeps network placement aligned with
    `experimental_environment = "remote"` without adding MCP-specific
    executor APIs.
    
    ### What
    - Add an executor-side `http/request` runner backed by `reqwest`.
    - Validate request method and URL scheme, preserving the transport
    boundary at plain HTTP.
    - Return buffered responses for ordinary calls and emit ordered
    `http/request/bodyDelta` notifications for streaming responses.
    - Register the request handler in the exec-server router.
    - Document the runner entrypoint, conversion helpers, body-stream
    bridge, notification sender, timeout behavior, and new integration-test
    helpers.
    - Add exec-server integration tests with the existing websocket harness
    and a local TCP HTTP peer for buffered and streamed responses, with
    comments spelling out what each test proves and its
    setup/exercise/assert phases.
    
    ### Stack
    1. #18581 protocol
    2. #18582 runner
    3. #18583 RMCP client
    4. #18584 manager wiring and local/remote coverage
    
    ### Verification
    - `just fmt`
    - `cargo check -p codex-exec-server -p codex-rmcp-client --tests`
    - `cargo check -p codex-core --test all` compile-only
    - `git diff --check`
    - Online full CI is running from the `full-ci` branch, including the
    remote Rust test job.
    
    Co-authored-by: Codex <noreply@openai.com>
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • exec-server: carry filesystem sandbox profiles (#18276)
    ## Why
    
    The exec-server still needs platform sandbox inputs, but the migration
    should preserve the `PermissionProfile` that produced them. Keeping only
    the derived legacy sandbox map would keep `SandboxPolicy` as the
    effective abstraction and would make full-disk vs. restricted profiles
    harder to preserve as the permissions stack starts round-tripping
    profiles.
    
    `PermissionProfile` entries can also be cwd-sensitive (`:cwd`,
    `:project_roots`, relative globs), so the exec-server must carry the
    request sandbox cwd instead of resolving those entries against the
    long-lived exec-server process cwd.
    
    ## What changed
    
    `FileSystemSandboxContext` now carries `permissions: PermissionProfile`
    plus an optional `cwd`:
    
    - removed `sandboxPolicy`, `sandboxPolicyCwd`,
    `fileSystemSandboxPolicy`, and `additionalPermissions`
    - added `permissions` and `cwd`
    - kept the platform knobs `windowsSandboxLevel`,
    `windowsSandboxPrivateDesktop`, and `useLegacyLandlock`
    
    Core turn and apply-patch paths populate the context from the active
    runtime permissions and request cwd. Exec-server derives platform
    `SandboxPolicy`/`FileSystemSandboxPolicy` at the filesystem boundary,
    adds helper runtime reads there, and rejects cwd-dependent profiles that
    arrive without a cwd.
    
    The legacy `FileSystemSandboxContext::new(SandboxPolicy)` constructor
    now preserves the old workspace-write conversion semantics for
    compatibility tests/callers.
    
    ## Verification
    
    - `cargo test -p codex-exec-server`
    - `cargo test -p codex-exec-server sandbox_cwd -- --nocapture`
    - `cargo test -p codex-exec-server
    sandbox_context_new_preserves_legacy_workspace_write_read_only_subpaths
    -- --nocapture`
    - `cargo test -p codex-core --lib
    file_system_sandbox_context_uses_active_attempt -- --nocapture`
  • Support multiple managed environments (#18401)
    ## Summary
    - refactor EnvironmentManager to own keyed environments with
    default/local lookup helpers
    - keep remote exec-server client creation lazy until exec/fs use
    - preserve disabled agent environment access separately from internal
    local environment access
    
    ## Validation
    - not run (per Codex worktree instruction to avoid tests/builds unless
    requested)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: fully revert agent identity runtime wiring (#18757)
    ## Summary
    
    This PR fully reverts the previously merged Agent Identity runtime
    integration from the old stack:
    https://github.com/openai/codex/pull/17387/changes
    
    It removes the Codex-side task lifecycle wiring, rollout/session
    persistence, feature flag plumbing, lazy `auth.json` mutation,
    background task auth paths, and request callsite changes introduced by
    that stack.
    
    This leaves the repo in a clean pre-AgentIdentity integration state so
    the follow-up PRs can reintroduce the pieces in smaller reviewable
    layers.
    
    ## Stack
    
    1. This PR: full revert
    2. https://github.com/openai/codex/pull/18871: move Agent Identity
    business logic into a crate
    3. https://github.com/openai/codex/pull/18785: add explicit
    AgentIdentity auth mode and startup task allocation
    4. https://github.com/openai/codex/pull/18811: migrate auth callsites
    through AuthProvider
    
    ## Testing
    
    Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
  • [1/4] Add executor HTTP request protocol (#18581)
    ### Why
    Remote streamable HTTP MCP needs a transport-shaped executor primitive
    before the MCP client can move network I/O to the executor. This layer
    keeps the executor unaware of MCP and gives later PRs an ordered
    streaming surface for response bodies.
    
    ### What
    - Add typed `http/request` and `http/request/bodyDelta` protocol
    payloads.
    - Add executor client helpers for buffered and streamed HTTP responses.
    - Route body-delta notifications to request-scoped streams with sequence
    validation and cleanup when a stream finishes or is dropped.
    - Document the new protocol constants, transport structs, public client
    methods, body-stream lifecycle, and request-scoped routing helpers.
    - Add in-memory JSON-RPC client coverage for streamed HTTP response-body
    notifications, with comments spelling out what the test proves and each
    setup/exercise/assert phase.
    
    ### Stack
    1. #18581 protocol
    2. #18582 runner
    3. #18583 RMCP client
    4. #18584 manager wiring and local/remote coverage
    
    ### Verification
    - `just fmt`
    - `cargo check -p codex-exec-server -p codex-rmcp-client --tests`
    - `cargo check -p codex-core --test all` compile-only
    - `git diff --check`
    - Online full CI is running from the `full-ci` branch, including the
    remote Rust test job.
    
    Co-authored-by: Codex <noreply@openai.com>
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [6/6] Fail exec client operations after disconnect (#18027)
    ## Summary
    - Reject new exec-server client operations once the transport has
    disconnected.
    - Convert pending RPC calls into closed errors instead of synthetic
    server errors.
    - Cover pending read and later write behavior after remote executor
    disconnect.
    
    ## Verification
    - `just fmt`
    - `cargo check -p codex-exec-server`
    
    ## Stack
    ```text
    @  #18027 [6/6] Fail exec client operations after disconnect
    │
    o  #18212 [5/6] Wire executor-backed MCP stdio
    │
    o  #18087 [4/6] Abstract MCP stdio server launching
    │
    o  #18020 [3/6] Add pushed exec process events
    │
    o  #18086 [2/6] Support piped stdin in exec process API
    │
    o  #18085 [1/6] Add MCP server environment config
    │
    o  main
    ```
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • protocol: canonicalize file system permissions (#18274)
    ## Why
    
    `PermissionProfile` needs stable, canonical file-system semantics before
    it can become the primary runtime permissions abstraction. Without a
    canonical form, callers have to keep re-deriving legacy sandbox maps and
    profile comparisons remain lossy or order-dependent.
    
    ## What changed
    
    This adds canonicalization helpers for `FileSystemPermissions` and
    `PermissionProfile`, expands special paths into explicit sandbox
    entries, and updates permission request/conversion paths to consume
    those canonical entries. It also tightens the legacy bridge so root-wide
    write profiles with narrower carveouts are not silently projected as
    full-disk legacy access.
    
    ## Verification
    
    - `cargo test -p codex-protocol
    root_write_with_read_only_child_is_not_full_disk_write -- --nocapture`
    - `cargo test -p codex-sandboxing permission -- --nocapture`
    - `cargo test -p codex-tui permissions -- --nocapture`
  • fix: fix fs sandbox helper for apply_patch (#18296)
    ## Summary
    
    - pass split filesystem sandbox policy/cwd through apply_patch contexts,
    while omitting legacy-equivalent policies to keep payloads small
    - keep the fs helper compatible with legacy Landlock by avoiding helper
    read-root permission expansion in that mode and disabling helper network
    access
    
    ## Root Cause
    
    `d626dc38950fb40a1a5ad0a8ffab2485e3348c53` routed exec-server filesystem
    operations through a sandboxed helper. That path forwarded legacy
    Landlock into a helper policy shape that could require direct
    split-policy enforcement. Sandboxed `apply_patch` hit that edge through
    the filesystem abstraction.
    
    The same 0.121 edit-regression path is consistent with #18354: normal
    writes route through the `apply_patch` filesystem helper, fail under
    sandbox, and then surface the generic retry-without-sandbox prompt.
    
    Fixes #18069
    Fixes #18354
    
    ## Validation
    
    - `cd codex-rs && just fmt`
    - earlier branch validation before merging current `origin/main` and
    dropping the now-separate PATH fix:
      - `cd codex-rs && cargo test -p codex-exec-server`
    - `cd codex-rs && cargo test -p codex-core file_system_sandbox_context`
      - `cd codex-rs && just fix -p codex-exec-server`
      - `cd codex-rs && just fix -p codex-core`
      - `git diff --check`
      - `cd codex-rs && cargo clean`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • exec-server: preserve fs helper runtime env (#18380)
    ## Summary
    - preserve a small fs-helper runtime env allowlist (`PATH`, temp vars)
    instead of launching the sandboxed helper with an empty env
    - add unit coverage for the allowlist and transformed sandbox request
    env
    - add a Linux smoke test that starts the test exec-server with a fake
    `bwrap` on `PATH`, runs a sandboxed fs write through the remote fs
    helper path, and asserts that bwrap path was exercised
    
    ## Validation
    - `cd /tmp/codex-worktrees/fs-helper-env-defaults/codex-rs && export
    PATH=$HOME/code/openai/project/dotslash-gen/bin:$HOME/.local/bin:$PATH
    && bazel test --bes_backend= --bes_results_url=
    //codex-rs/exec-server:exec-server-file_system-test
    --test_filter=sandboxed_file_system_helper_finds_bwrap_on_preserved_path`
    - `cd /tmp/codex-worktrees/fs-helper-env-defaults/codex-rs && export
    PATH=$HOME/code/openai/project/dotslash-gen/bin:$HOME/.local/bin:$PATH
    && bazel test --bes_backend= --bes_results_url=
    //codex-rs/exec-server:exec-server-unit-tests
    --test_filter="helper_env|sandbox_exec_request_carries_helper_env"`
    - earlier on this branch before the smoke-test harness adjustment: `cd
    /tmp/codex-worktrees/fs-helper-env-defaults/codex-rs && export
    PATH=$HOME/code/openai/project/dotslash-gen/bin:$HOME/.local/bin:$PATH
    && bazel test --bes_backend= --bes_results_url=
    //codex-rs/exec-server:all`
    
    Co-authored-by: Codex <noreply@openai.com>
  • [3/6] Add pushed exec process events (#18020)
    ## Summary
    - Add a pushed `ExecProcessEvent` stream alongside retained
    `process/read` output.
    - Publish local and remote output, exit, close, and failure events.
    - Cover the event stream with shared local/remote exec process tests.
    
    ## Testing
    - `cargo check -p codex-exec-server`
    - `cargo check -p codex-rmcp-client`
    - Not run: `cargo test` per repo instruction; CI will cover.
    
    ## Stack
    ```text
    o  #18027 [6/6] Fail exec client operations after disconnect
    │
    o  #18212 [5/6] Wire executor-backed MCP stdio
    │
    o  #18087 [4/6] Abstract MCP stdio server launching
    │
    @  #18020 [3/6] Add pushed exec process events
    │
    o  #18086 [2/6] Support piped stdin in exec process API
    │
    o  #18085 [1/6] Add MCP server environment config
    │
    o  main
    ```
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [2/8] Support piped stdin in exec process API (#18086)
    ## Summary
    - Add an explicit stdin mode to process/start.
    - Keep normal non-interactive exec stdin closed while allowing
    pipe-backed processes.
    
    ## Stack
    ```text
    o  #18027 [8/8] Fail exec client operations after disconnect
    │
    o  #18025 [7/8] Cover MCP stdio tests with executor placement
    │
    o  #18089 [6/8] Wire remote MCP stdio through executor
    │
    o  #18088 [5/8] Add executor process transport for MCP stdio
    │
    o  #18087 [4/8] Abstract MCP stdio server launching
    │
    o  #18020 [3/8] Add pushed exec process events
    │
    @  #18086 [2/8] Support piped stdin in exec process API
    │
    o  #18085 [1/8] Add MCP server environment config
    │
    o  main
    ```
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Restore remote exec-server filesystem tests (#17989)
    ## Summary
    
    - Re-enable remote variants for the exec-server filesystem
    sandbox/symlink tests that were made local-only in PR #17671.
    - Restore `use_remote` parameterization for the readable-root,
    normalized symlink escape, symlink removal, and symlink
    copy-preservation cases.
    - Preserve `mode={use_remote}` context on key async filesystem failures
    so CI failures point at the local or remote lane.
    
    ## Validation
    
    - `cd codex-rs && just fmt`
    - Not run: `bazel test
    //codex-rs/exec-server:exec-server-file_system-test` per local Codex
    development guidance to avoid test runs unless explicitly requested.
    
    Co-authored-by: Codex <noreply@openai.com>
  • Fix fs/readDirectory to skip broken symlinks (#17907)
    ## Summary
    - Skip directory entries whose metadata lookup fails during
    `fs/readDirectory`
    - Add an exec-server regression test covering a broken symlink beside
    valid entries
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-exec-server` (started, but dependency/network
    updates stalled before completion in this environment)
  • Remove exec-server fs sandbox request preflight (#17883)
    ## Summary
    - Remove the exec-server-side manual filesystem request path preflight
    before invoking the sandbox helper.
    - Keep sandbox helper policy construction and platform sandbox
    enforcement as the access boundary.
    - Add a portable local+remote regression for writing through an
    explicitly configured alias root.
    - Remove the metadata symlink-escape assertion that depended on the
    deleted manual preflight; no replacement metadata-specific access probe
    is added.
    
    ## Tests
    - `cargo test -p codex-exec-server --lib`
    - `cargo test -p codex-exec-server --test file_system`
    - `git diff --check`
  • Route apply_patch through the environment filesystem (#17674)
    ## Summary
    - route apply_patch runtime execution through the selected Environment
    filesystem instead of the local self-exec path
    - keep the standalone apply_patch command surface intact while restoring
    its launcher/test/docs contract
    - add focused apply_patch filesystem sandbox regression coverage
    
    ## Validation
    - remote devbox Bazel run in progress
    - passed: //codex-rs/apply-patch:apply-patch-unit-tests
    --test_filter=test_read_file_utf8_with_context_reports_invalid_utf8
    - in progress / follow-up: focused core and exec Bazel test slices on
    dev
    
    ## Follow-up under review
    - remote pre-verification and approval/retry behavior still need
    explicit scrutiny for delete/update flows
    - runtime sandbox-denial classification may need a tighter assertion
    path than rendered stderr matching
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Add symlink flag to fs metadata (#17719)
    Add `is_symlink` to FsMetadata struct.
  • Stabilize exec-server filesystem tests in CI (#17671)
    ## Summary\n- add an exec-server package-local test helper binary that
    can run exec-server and fs-helper flows\n- route exec-server filesystem
    tests through that helper instead of cross-crate codex helper
    binaries\n- stop relying on Bazel-only extra binary wiring for these
    tests\n\n## Testing\n- not run (per repo guidance for codex changes)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Build remote exec env from exec-server policy (#17216)
    ## Summary
    - add an exec-server `envPolicy` field; when present, the server starts
    from its own process env and applies the shell environment policy there
    - keep `env` as the exact environment for local/embedded starts, but
    make it an overlay for remote unified-exec starts
    - move the shell-environment-policy builder into `codex-config` so Core
    and exec-server share the inherit/filter/set/include behavior
    - overlay only runtime/sandbox/network deltas from Core onto the
    exec-server-derived env
    
    ## Why
    Remote unified exec was materializing the shell env inside Core and
    forwarding the whole map to exec-server, so remote processes could
    inherit the orchestrator machine's `HOME`, `PATH`, etc. This keeps the
    base env on the executor while preserving Core-owned runtime additions
    like `CODEX_THREAD_ID`, unified-exec defaults, network proxy env, and
    sandbox marker env.
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - `cargo test -p codex-exec-server --lib`
    - `cargo test -p codex-core --lib unified_exec::process_manager::tests`
    - `cargo test -p codex-core --lib exec_env::tests`
    - `cargo test -p codex-core --lib exec_env_tests` (compile-only; filter
    matched 0 tests)
    - `cargo test -p codex-config --lib shell_environment` (compile-only;
    filter matched 0 tests)
    - `just bazel-lock-update`
    
    ## Known local validation issue
    - `just bazel-lock-check` is not runnable in this checkout: it invokes
    `./scripts/check-module-bazel-lock.sh`, which is missing.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • Stabilize exec-server process tests (#17605)
    Problem: After #17294 switched exec-server tests to launch the top-level
    `codex exec-server` command, parallel remote exec-process cases can
    flake while waiting for the child server's listen URL or transport
    shutdown.
    
    Solution: Serialize remote exec-server-backed process tests and harden
    the harness so spawned servers are killed on drop and shutdown waits for
    the child process to exit.
  • Run exec-server fs operations through sandbox helper (#17294)
    ## Summary
    - run exec-server filesystem RPCs requiring sandboxing through a
    `codex-fs` arg0 helper over stdin/stdout
    - keep direct local filesystem execution for `DangerFullAccess` and
    external sandbox policies
    - remove the standalone exec-server binary path in favor of top-level
    arg0 dispatch/runtime paths
    - add sandbox escape regression coverage for local and remote filesystem
    paths
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - remote devbox: `cd codex-rs && bazel test --bes_backend=
    --bes_results_url= //codex-rs/exec-server:all` (6/6 passed)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Fix Windows exec-server output test flake (#17409)
    Problem: The Windows exec-server test command could let separator
    whitespace become part of `echo` output, making the exact
    retained-output assertion flaky.
    
    Solution: Tighten the Windows `cmd.exe` command by placing command
    separators directly after the echoed tokens so stdout remains
    deterministic while preserving the exact assertion.
  • feat: move exec-server ownership (#16344)
    This introduces session-scoped ownership for exec-server so ws
    disconnects no longer immediately kill running remote exec processes,
    and it prepares the protocol for reconnect-based resume.
    - add session_id / resume_session_id to the exec-server initialize
    handshake
      - move process ownership under a shared session registry
    - detach sessions on websocket disconnect and expire them after a TTL
    instead of killing processes immediately (we will resume based on this)
    - allow a new connection to resume an existing session and take over
    notifications/ownership
    - I use UUID to make them not predictable as we don't have auth for now
    - make detached-session expiry authoritative at resume time so teardown
    wins at the TTL boundary
    - reject long-poll process/read calls that get resumed out from under an
    older attachment
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Support remote exec cwd in TUI startup (#17142)
    When running with remote executor the cwd is the remote path. Today we
    check for existence of a local directory on startup and attempt to load
    config from it.
    
    For remote executors don't do that.
  • Add sandbox support to filesystem APIs (#16751)
    ## Summary
    - add optional `sandboxPolicy` support to the app-server filesystem
    request surface
    - thread sandbox-aware filesystem options through app-server and
    exec-server adapters
    - enforce sandboxed read/write access in the filesystem abstraction with
    focused local and remote coverage
    
    ## Validation
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-exec-server file_system`
    - `cargo test -p codex-app-server suite::v2::fs`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Migrate apply_patch to executor filesystem (#17027)
    - Migrate apply-patch verification and application internals to use the
    async `ExecutorFileSystem` abstraction from `exec-server`.
    - Convert apply-patch `cwd` handling to `AbsolutePathBuf` through the
    verifier/parser/handler boundary.
    
    Doesn't change how the tool itself works.
  • Make AGENTS.md discovery FS-aware (#15826)
    ## Summary
    - make AGENTS.md discovery and loading fully FS-aware and remove the
    non-FS discover helper
    - migrate remote-aware codex-core tests to use TestEnv workspace setup
    instead of syncing a local workspace copy
    - add AGENTS.md corner-case coverage, including directory fallbacks and
    remote-aware integration coverage
    
    ## Testing
    - cargo test -p codex-core project_doc -- --nocapture
    - cargo test -p codex-core hierarchical_agents -- --nocapture
    - cargo test -p codex-core agents_md -- --nocapture
    - cargo test -p codex-tui status -- --nocapture
    - cargo test -p codex-tui-app-server status -- --nocapture
    - just fix
    - just fmt
    - just bazel-lock-update
    - just bazel-lock-check
    - just argument-comment-lint
    - remote Linux executor tests in progress via scripts/test-remote-env.sh
  • Disable env-bound tools when exec server is none (#16349)
    ## Summary
    - make `CODEX_EXEC_SERVER_URL=none` map to an explicit disabled
    environment mode instead of inferring from a missing URL
    - expose environment capabilities (`exec_enabled`, `filesystem_enabled`)
    so tool building can gate behavior explicitly and future
    multi-environment work has a clearer seam
    - suppress env-backed tools when the relevant capability is unavailable,
    including exec tools, `js_repl`, `apply_patch`, `list_dir`, and
    `view_image`
    - keep handler/runtime backstops so disabled environments still reject
    execution if a tool path somehow bypasses registration
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-exec-server`
    - `cargo test -p codex-tools
    disabled_environment_omits_environment_backed_tools`
    - `cargo test -p codex-tools
    environment_capabilities_gate_exec_and_filesystem_tools_independently`
    - remote devbox Bazel build via `codex-applied-devbox`:
    `//codex-rs/cli:cli`
  • extract models manager and related ownership from core (#16508)
    ## Summary
    - split `models-manager` out of `core` and add `ModelsManagerConfig`
    plus `Config::to_models_manager_config()` so model metadata paths stop
    depending on `core::Config`
    - move login-owned/auth-owned code out of `core` into `codex-login`,
    move model provider config into `codex-model-provider-info`, move API
    bridge mapping into `codex-api`, move protocol-owned types/impls into
    `codex-protocol`, and move response debug helpers into a dedicated
    `response-debug-context` crate
    - move feedback tag emission into `codex-feedback`, relocate tests to
    the crates that now own the code, and keep broad temporary re-exports so
    this PR avoids a giant import-only rewrite
    
    ## Major moves and decisions
    - created `codex-models-manager` as the owner for model
    cache/catalog/config/model info logic, including the new
    `ModelsManagerConfig` struct
    - created `codex-model-provider-info` as the owner for provider config
    parsing/defaults and kept temporary `codex-login`/`codex-core`
    re-exports for old import paths
    - moved `api_bridge` error mapping + `CoreAuthProvider` into
    `codex-api`, while `codex-login::api_bridge` temporarily re-exports
    those symbols and keeps the `auth_provider_from_auth` wrapper
    - moved `auth_env_telemetry` and `provider_auth` ownership to
    `codex-login`
    - moved `CodexErr` ownership to `codex-protocol::error`, plus
    `StreamOutput`, `bytes_to_string_smart`, and network policy helpers to
    protocol-owned modules
    - created `codex-response-debug-context` for
    `extract_response_debug_context`, `telemetry_transport_error_message`,
    and related response-debug plumbing instead of leaving that behavior in
    `core`
    - moved `FeedbackRequestTags`, `emit_feedback_request_tags`, and
    `emit_feedback_request_tags_with_auth_env` to `codex-feedback`
    - deferred removal of temporary re-exports and the mechanical import
    rewrites to a stacked follow-up PR so this PR stays reviewable
    
    ## Test moves
    - moved auth refresh coverage from `core/tests/suite/auth_refresh.rs` to
    `login/tests/suite/auth_refresh.rs`
    - moved text encoding coverage from
    `core/tests/suite/text_encoding_fix.rs` to
    `protocol/src/exec_output_tests.rs`
    - moved model info override coverage from
    `core/tests/suite/model_info_overrides.rs` to
    `models-manager/src/model_info_overrides_tests.rs`
    
    ---------
    
    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.