Commit Graph

26 Commits

  • Add Windows sandbox provisioning setup command (#24831)
    ## Why
    
    Some Windows users do not have local admin access, so they cannot
    complete the elevated portion of the Windows sandbox setup when Codex
    first needs it. This adds an alpha provisioning path that an admin or IT
    deployment script can run ahead of time for the Codex user.
    
    The intended managed-deployment shape is:
    
    ```powershell
    codex sandbox setup --elevated --user "$env:COMPUTERNAME\Alice" --codex-home "C:\Users\Alice\.codex"
    ```
    
    `--elevated` is treated as the requested sandbox setup level, not as
    proof that the process is elevated. The Windows sandbox setup
    orchestration still checks that the caller is actually elevated before
    launching the helper without a UAC prompt.
    
    ## What changed
    
    - Added `codex sandbox setup --elevated` with explicit user selection
    via either `--current-user` or `--user ... --codex-home ...`.
    - Moved the CLI implementation into `cli/src/sandbox_setup.rs` instead
    of growing `cli/src/main.rs`.
    - Added a Windows sandbox `ProvisionOnly` helper mode that runs the
    elevation-required provisioning work without requiring a workspace cwd
    or runtime sandbox policy.
    - Reused the existing elevated helper path for creating/updating sandbox
    users, configuring firewall/WFP rules, and applying sandbox directory
    ACLs.
    - Persisted `windows.sandbox = "elevated"` into the target `CODEX_HOME`
    so the desktop app does not show the initial sandbox setup banner after
    pre-provisioning succeeds.
    
    ## Validation
    
    - `cargo fmt -p codex-windows-sandbox -p codex-core -p codex-cli`
    - `cargo test -p codex-cli sandbox_setup --target-dir
    target\sandbox-setup-check`
    - `cargo test -p codex-windows-sandbox
    payload_accepts_provision_only_mode --target-dir
    target\sandbox-setup-check`
    - `git diff --check`
    - Manual Windows alpha flow with a standard local user (`Mandi Lavida`):
    ran the new setup command from an admin shell, verified the target
    `.codex` contents, sandbox marker/secrets, ACLs, firewall rules, and
    desktop startup without the sandbox setup banner once experimental
    network proxy requirements were disabled.
    
    ## Notes
    
    This intentionally does not solve later elevated update coordination for
    IT-managed deployments. The setup command can still apply provisioning
    updates when run again, but a broader coordination/process story is out
    of scope for this alpha.
  • windows-sandbox: pass workspace roots to runner (#24108)
    ## Why
    
    #23813 switches the Windows sandbox runner path to `PermissionProfile`,
    but it still left one runtime anchor for resolving symbolic
    `:workspace_roots` entries. That is not enough once a turn has multiple
    effective workspace roots: exact entries and deny globs under
    `:workspace_roots` need to be materialized for every runtime root before
    the command runner chooses token mode or builds ACL plans.
    
    ## What Changed
    
    - Replaces the Windows runner/setup `permission_profile_cwd` plumbing
    with `workspace_roots: Vec<AbsolutePathBuf>`.
    - Resolves Windows-local `PermissionProfile` data with
    `materialize_project_roots_with_workspace_roots(...)` instead of the
    single-cwd helper.
    - Threads `Config::effective_workspace_roots()` through core execution,
    unified exec, TUI setup/read-grant flows, app-server setup, app-server
    `command/exec`, and `debug sandbox` on Windows.
    - Preserves those workspace roots through the zsh-fork escalation
    executor instead of rebuilding them from `sandbox_policy_cwd`.
    - Makes `ExecRequest::new(...)` and the remaining
    `build_exec_request(...)` helper path take
    `windows_sandbox_workspace_roots` explicitly so new call sites cannot
    silently fall back to `vec![cwd]`.
    - Clarifies the `debug sandbox` non-Windows comment: remaining
    cwd-dependent resolution still uses `sandbox_policy_cwd`, while
    `:workspace_roots` entries are already materialized from config roots.
    - Updates elevated runner IPC `SpawnRequest` to send `workspace_roots`
    and bumps the framed IPC protocol version to `3` for the payload shape
    change.
    - Adds Windows-local resolver coverage for expanding exact and glob
    `:workspace_roots` entries across multiple roots, plus core helper
    coverage proving explicit roots are preserved.
    
    ## Verification
    
    - `cargo check -p codex-windows-sandbox -p codex-core -p codex-tui -p
    codex-cli -p codex-app-server`
    - `cargo test -p codex-windows-sandbox`
    - `cargo test -p codex-core windows_sandbox`
    - `cargo test -p codex-core unix_escalation`
    - `cargo test -p codex-app-server windows_sandbox`
    - `cargo test -p codex-tui windows_sandbox`
    - `cargo test -p codex-cli debug_sandbox`
    - `just test -p codex-core unified_exec`
    - `just test -p codex-core
    build_exec_request_preserves_windows_workspace_roots`
    - `env -u CODEX_NETWORK_PROXY_ACTIVE -u
    CODEX_NETWORK_ALLOW_LOCAL_BINDING just test -p codex-app-server --lib
    command_exec`
    - `just test -p codex-windows-sandbox`
    - `just test -p codex-exec sandbox`
    - `just fix -p codex-core -p codex-app-server -p codex-windows-sandbox`
    
    A local macOS cross-check with `cargo check --target
    x86_64-pc-windows-msvc ...` did not reach crate Rust code because native
    dependencies require Windows SDK headers (`windows.h` / `assert.h`) in
    this environment; Windows CI remains the real target validation.
    
    Two local targeted filters compile but do not run assertions on macOS:
    `env -u CODEX_NETWORK_PROXY_ACTIVE -u CODEX_NETWORK_ALLOW_LOCAL_BINDING
    just test -p codex-app-server --lib command_exec_processor` matched zero
    tests, and `just test -p codex-linux-sandbox landlock` matched zero
    tests because the landlock suite is Linux-only.
  • windows-sandbox: remove SandboxPolicy runner plumbing (#23813)
    ## Why
    
    The Windows sandbox runner still carried the old `SandboxPolicy`
    compatibility path even though core now computes `PermissionProfile`.
    That meant Windows command-runner execution could only see the legacy
    projection, so profile-only filesystem rules such as deny globs were not
    part of the runner input.
    
    ## What Changed
    
    - Removed the Windows-local `SandboxPolicy` parser/export and deleted
    `windows-sandbox-rs/src/policy.rs`.
    - Changed restricted-token capture/session setup, elevated setup,
    world-writable audit, read-root grant, and command-runner session APIs
    to accept `PermissionProfile` plus the profile cwd.
    - Bumped the elevated command-runner IPC protocol to version 2 because
    `SpawnRequest` now carries `permission_profile` /
    `permission_profile_cwd` instead of the legacy `policy_json_or_preset` /
    `sandbox_policy_cwd` fields.
    - Updated core exec, unified exec, debug-sandbox, TUI setup/grant flows,
    and app-server setup to pass the actual effective `PermissionProfile`.
    - Left regression coverage asserting the old IPC policy fields are
    absent and the runner serializes tagged `PermissionProfile` JSON.
    
    ## Verification
    
    - `cargo test -p codex-windows-sandbox`
    - `cargo test -p codex-core windows_sandbox`
    - `cargo test -p codex-app-server
    request_processors::windows_sandbox_processor`
    - `just fix -p codex-windows-sandbox -p codex-core -p codex-app-server
    -p codex-cli -p codex-tui`
    - `just fix -p codex-cli -p codex-tui`
    - `just fix -p codex-windows-sandbox -p codex-tui`
    - `rg "\\bSandboxPolicy\\b" codex-rs/windows-sandbox-rs` returned no
    matches.
    
    Note: `cargo test -p codex-cli` was attempted but did not reach crate
    tests because local disk filled while compiling dependencies (`No space
    left on device`). The targeted clippy pass compiled the affected CLI/TUI
    surfaces afterward.
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23813).
    * #24108
    * __->__ #23813
  • config: remove legacy profile write paths (#24055)
    ## Why
    
    [#23883](https://github.com/openai/codex/pull/23883) moved the
    user-facing `--profile` flag onto profile v2 and
    [#23886](https://github.com/openai/codex/pull/23886) removed CLI
    forwarding for the legacy profile-v1 path. Core and TUI config
    persistence still carried `active_profile` and
    `ConfigEditsBuilder::with_profile`, which let later writes continue
    targeting legacy `[profiles.<name>]` tables after profile selection
    moved to profile-v2 config files.
    
    ## What
    
    - Remove legacy profile routing from
    [`ConfigEditsBuilder`](https://github.com/openai/codex/blob/4b38e9c22e762261d7f7eef49d8a21792e241a06/codex-rs/core/src/config/edit.rs#L1064-L1294),
    so core config edits no longer carry `with_profile` or infer
    `[profiles.*]` write targets from a `profile` key.
    - Drop `active_profile` plumbing from runtime `Config`, TUI
    startup/state, app-server config override forwarding, and Windows
    sandbox setup persistence.
    - Make app-server-backed TUI config edits use unscoped model,
    service-tier, feature, Auto-review, plan-mode, and Windows sandbox paths
    through
    [`tui/src/config_update.rs`](https://github.com/openai/codex/blob/4b38e9c22e762261d7f7eef49d8a21792e241a06/codex-rs/tui/src/config_update.rs#L43-L112).
    - Update config edit coverage so legacy `profile` state stays untouched
    by direct model writes, and remove tests whose only contract was the
    deleted profile-scoped persistence path.
    
    ## Testing
    
    - Not run locally.
  • config: remove legacy profile v1 resolution (#24051)
    ## Why
    
    [#23883](https://github.com/openai/codex/pull/23883) moved user-facing
    `--profile` selection onto profile v2, and
    [#23886](https://github.com/openai/codex/pull/23886) removed the old CLI
    `config_profile` override path. Core still had a second legacy path:
    `profile = "..."` could select `[profiles.*]` values while runtime
    config was built. Keeping that resolver alive preserves the old
    precedence model and profile-carrying surfaces even though profile
    selection now points at `$CODEX_HOME/<name>.config.toml`.
    
    ## What
    
    - Reject legacy top-level `profile = "..."` config while loading runtime
    config, with an error that points callers at `--profile <name>` and
    `<name>.config.toml` in the [core load
    path](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/mod.rs#L2524-L2531).
    - Remove the remaining profile-v1 merge points from runtime config
    resolution, including features, permissions, model/provider selection,
    web search, Windows sandbox settings, TUI settings, role reloads, and
    OSS provider lookup.
    - Drop the leftover profile override surface from
    [`ConfigOverrides`](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/mod.rs#L2118-L2148)
    and from the MCP server `codex` tool schema.
    - Prune profile-precedence tests that only exercised the removed
    resolver and replace them with rejection coverage for the legacy
    selector.
    
    ## Testing
    
    - Not run in this metadata pass.
    - Added
    [`legacy_profile_selection_is_rejected`](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/config_tests.rs#L7942-L7965)
    coverage for the new runtime guard.
  • windows-sandbox: feed setup from resolved permissions (#23167)
    ## Why
    
    This is the next step in the Windows sandbox migration away from the
    legacy `SandboxPolicy` abstraction. #22923 moved write-root and token
    decisions onto `ResolvedWindowsSandboxPermissions`, but setup and
    identity still accepted `SandboxPolicy` and converted internally. This
    PR pushes that conversion outward so the setup path consumes the
    resolved Windows permission view directly.
    
    ## What Changed
    
    - Changed `SandboxSetupRequest` to carry
    `ResolvedWindowsSandboxPermissions` instead of `SandboxPolicy` plus
    policy cwd.
    - Updated setup refresh/elevation and identity credential preparation to
    use resolved permissions for read roots, write roots, network identity,
    and deny-write payload planning.
    - Removed the production `allow.rs` legacy wrapper; allow-path
    computation now takes resolved permissions directly.
    - Added a permissions-based world-writable audit entry point while
    keeping the existing legacy wrapper for compatibility.
    - Updated legacy ACL setup and the core Windows setup bridge to
    construct resolved permissions at the boundary.
    - Hardened the Windows sandbox integration test helper staging so Bazel
    retries can reuse an already-staged helper if a prior sandbox helper
    process still has the executable open.
    
    ## Verification
    
    - `cargo test -p codex-windows-sandbox`
    - `cargo test -p codex-core --test all --no-run`
    - `just fix -p codex-windows-sandbox`
    - `just fix -p codex-core`
    - Attempted `cargo check -p codex-windows-sandbox --target
    x86_64-pc-windows-gnullvm`, but the local machine is missing
    `x86_64-w64-mingw32-clang`; Windows CI should cover that target.
    
    
    
    
    
    
    
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23167).
    * #23715
    * #23714
    * __->__ #23167
  • Configure multi_agent_v2 spawn agent hints (#17071)
    Allow multi_agent_v2 features to have its own temporary configuration
    under `[features.multi_agent_v2]`
    
    ```
    [features.multi_agent_v2]
    enabled = true
    usage_hint_enabled = false
    usage_hint_text = "Custom delegation guidance."
    hide_spawn_agent_metadata = true
    ```
    
    Absent `usage_hint_text` means use the default hint.
    
    ```
    [features]
    multi_agent_v2 = true
    ```
    
    still works as the boolean shorthand.
  • [codex] reduce module visibility (#16978)
    ## Summary
    - reduce public module visibility across Rust crates, preferring private
    or crate-private modules with explicit crate-root public exports
    - update external call sites and tests to use the intended public crate
    APIs instead of reaching through module trees
    - add the module visibility guideline to AGENTS.md
    
    ## Validation
    - `cargo check --workspace --all-targets --message-format=short` passed
    before the final fix/format pass
    - `just fix` completed successfully
    - `just fmt` completed successfully
    - `git diff --check` passed
  • Refactor config types into a separate crate (#16962)
    Move config types into a separate crate because their macros expand into
    a lot of new code.
  • [codex] Remove codex-core config type shim (#16529)
    ## Why
    
    This finishes the config-type move out of `codex-core` by removing the
    temporary compatibility shim in `codex_core::config::types`. Callers now
    depend on `codex-config` directly, which keeps these config model types
    owned by the config crate instead of re-expanding `codex-core` as a
    transitive API surface.
    
    ## What Changed
    
    - Removed the `codex-rs/core/src/config/types.rs` re-export shim and the
    `core::config::ApprovalsReviewer` re-export.
    - Updated `codex-core`, `codex-cli`, `codex-tui`, `codex-app-server`,
    `codex-mcp-server`, and `codex-linux-sandbox` call sites to import
    `codex_config::types` directly.
    - Added explicit `codex-config` dependencies to downstream crates that
    previously relied on the `codex-core` re-export.
    - Regenerated `codex-rs/core/config.schema.json` after updating the
    config docs path reference.
  • core: remove cross-crate re-exports from lib.rs (#16512)
    ## Why
    
    `codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
    which made downstream crates depend on `codex-core` as a proxy module
    instead of the actual owner crate.
    
    Removing those forwards makes crate boundaries explicit and lets leaf
    crates drop unnecessary `codex-core` dependencies. In this PR, this
    reduces the dependency on `codex-core` to `codex-login` in the following
    files:
    
    ```
    codex-rs/backend-client/Cargo.toml
    codex-rs/mcp-server/tests/common/Cargo.toml
    ```
    
    ## What
    
    - Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
    `codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
    `codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
    `codex-tools`, and `codex-utils-path`.
    - Delete the `default_client` forwarding shim in `codex-rs/core`.
    - Update in-crate and downstream callsites to import directly from the
    owning `codex-*` crate.
    - Add direct Cargo dependencies where callsites now target the owner
    crate, and remove `codex-core` from `codex-rs/backend-client`.
  • feat(windows-sandbox): add network proxy support (#12220)
    ## Summary
    
    This PR makes Windows sandbox proxying enforceable by routing proxy-only
    runs through the existing `offline` sandbox user and reserving direct
    network access for the existing `online` sandbox user.
    
    In brief:
    
    - if a Windows sandbox run should be proxy-enforced, we run it as the
    `offline` user
    - the `offline` user gets firewall rules that block direct outbound
    traffic and only permit the configured localhost proxy path
    - if a Windows sandbox run should have true direct network access, we
    run it as the `online` user
    - no new sandbox identity is introduced
    
    This brings Windows in line with the intended model: proxy use is not
    just env-based, it is backed by OS-level egress controls. Windows
    already has two sandbox identities:
    
    - `offline`: intended to have no direct network egress
    - `online`: intended to have full network access
    
    This PR makes proxy-enforced runs use that model directly.
    
    ### Proxy-enforced runs
    
    When proxy enforcement is active:
    
    - the run is assigned to the `offline` identity
    - setup extracts the loopback proxy ports from the sandbox env
    - Windows setup programs firewall rules for the `offline` user that:
      - block all non-loopback outbound traffic
      - block loopback UDP
      - block loopback TCP except for the configured proxy ports
    - optionally allow broader localhost access when `allow_local_binding=1`
    
    So the sandboxed process can only talk to the local proxy. It cannot
    open direct outbound sockets or do local UDP-based DNS on its own.The
    proxy then performs the real outbound network access outside that
    restricted sandbox identity.
    
    ### Direct-network runs
    
    When proxy enforcement is not active and full network access is allowed:
    
    - the run is assigned to the `online` identity
    - no proxy-only firewall restrictions are applied
    - the process gets normal direct network access
    
    ### Unelevated vs elevated
    
    The restricted-token / unelevated path cannot enforce per-identity
    firewall policy by itself.
    
    So for Windows proxy-enforced runs, we transparently use the logon-user
    sandbox path under the hood, even if the caller started from the
    unelevated mode. That keeps enforcement real instead of best-effort.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Use released DotSlash package for argument-comment lint (#15199)
    ## Why
    The argument-comment lint now has a packaged DotSlash artifact from
    [#15198](https://github.com/openai/codex/pull/15198), so the normal repo
    lint path should use that released payload instead of rebuilding the
    lint from source every time.
    
    That keeps `just clippy` and CI aligned with the shipped artifact while
    preserving a separate source-build path for people actively hacking on
    the lint crate.
    
    The current alpha package also exposed two integration wrinkles that the
    repo-side prebuilt wrapper needs to smooth over:
    - the bundled Dylint library filename includes the host triple, for
    example `@nightly-2025-09-18-aarch64-apple-darwin`, and Dylint derives
    `RUSTUP_TOOLCHAIN` from that filename
    - on Windows, Dylint's driver path also expects `RUSTUP_HOME` to be
    present in the environment
    
    Without those adjustments, the prebuilt CI jobs fail during `cargo
    metadata` or driver setup. This change makes the checked-in prebuilt
    wrapper normalize the packaged library name to the plain
    `nightly-2025-09-18` channel before invoking `cargo-dylint`, and it
    teaches both the wrapper and the packaged runner source to infer
    `RUSTUP_HOME` from `rustup show home` when the environment does not
    already provide it.
    
    After the prebuilt Windows lint job started running successfully, it
    also surfaced a handful of existing anonymous literal callsites in
    `windows-sandbox-rs`. This PR now annotates those callsites so the new
    cross-platform lint job is green on the current tree.
    
    ## What Changed
    - checked in the current
    `tools/argument-comment-lint/argument-comment-lint` DotSlash manifest
    - kept `tools/argument-comment-lint/run.sh` as the source-build wrapper
    for lint development
    - added `tools/argument-comment-lint/run-prebuilt-linter.sh` as the
    normal enforcement path, using the checked-in DotSlash package and
    bundled `cargo-dylint`
    - updated `just clippy` and `just argument-comment-lint` to use the
    prebuilt wrapper
    - split `.github/workflows/rust-ci.yml` so source-package checks live in
    a dedicated `argument_comment_lint_package` job, while the released lint
    runs in an `argument_comment_lint_prebuilt` matrix on Linux, macOS, and
    Windows
    - kept the pinned `nightly-2025-09-18` toolchain install in the prebuilt
    CI matrix, since the prebuilt package still relies on rustup-provided
    toolchain components
    - updated `tools/argument-comment-lint/run-prebuilt-linter.sh` to
    normalize host-qualified nightly library filenames, keep the `rustup`
    shim directory ahead of direct toolchain `cargo` binaries, and export
    `RUSTUP_HOME` when needed for Windows Dylint driver setup
    - updated `tools/argument-comment-lint/src/bin/argument-comment-lint.rs`
    so future published DotSlash artifacts apply the same nightly-filename
    normalization and `RUSTUP_HOME` inference internally
    - fixed the remaining Windows lint violations in
    `codex-rs/windows-sandbox-rs` by adding the required `/*param*/`
    comments at the reported callsites
    - documented the checked-in DotSlash file, wrapper split, archive
    layout, nightly prerequisite, and Windows `RUSTUP_HOME` requirement in
    `tools/argument-comment-lint/README.md`
  • Split features into codex-features crate (#15253)
    - Split the feature system into a new `codex-features` crate.
    - Cut `codex-core` and workspace consumers over to the new config and
    warning APIs.
    
    Co-authored-by: Ahmed Ibrahim <219906144+aibrahim-oai@users.noreply.github.com>
    Co-authored-by: Codex <noreply@openai.com>
  • Apply argument comment lint across codex-rs (#14652)
    ## Why
    
    Once the repo-local lint exists, `codex-rs` needs to follow the
    checked-in convention and CI needs to keep it from drifting. This commit
    applies the fallback `/*param*/` style consistently across existing
    positional literal call sites without changing those APIs.
    
    The longer-term preference is still to avoid APIs that require comments
    by choosing clearer parameter types and call shapes. This PR is
    intentionally the mechanical follow-through for the places where the
    existing signatures stay in place.
    
    After rebasing onto newer `main`, the rollout also had to cover newly
    introduced `tui_app_server` call sites. That made it clear the first cut
    of the CI job was too expensive for the common path: it was spending
    almost as much time installing `cargo-dylint` and re-testing the lint
    crate as a representative test job spends running product tests. The CI
    update keeps the full workspace enforcement but trims that extra
    overhead from ordinary `codex-rs` PRs.
    
    ## What changed
    
    - keep a dedicated `argument_comment_lint` job in `rust-ci`
    - mechanically annotate remaining opaque positional literals across
    `codex-rs` with exact `/*param*/` comments, including the rebased
    `tui_app_server` call sites that now fall under the lint
    - keep the checked-in style aligned with the lint policy by using
    `/*param*/` and leaving string and char literals uncommented
    - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo
    registry/git metadata in the lint job
    - split changed-path detection so the lint crate's own `cargo test` step
    runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes
    - continue to run the repo wrapper over the `codex-rs` workspace, so
    product-code enforcement is unchanged
    
    Most of the code changes in this commit are intentionally mechanical
    comment rewrites or insertions driven by the lint itself.
    
    ## Verification
    
    - `./tools/argument-comment-lint/run.sh --workspace`
    - `cargo test -p codex-tui-app-server -p codex-tui`
    - parsed `.github/workflows/rust-ci.yml` locally with PyYAML
    
    ---
    
    * -> #14652
    * #14651
  • Use a private desktop for Windows sandbox instead of Winsta0\Default (#14400)
    ## Summary
    - launch Windows sandboxed children on a private desktop instead of
    `Winsta0\Default`
    - make private desktop the default while keeping
    `windows.sandbox_private_desktop=false` as the escape hatch
    - centralize process launch through the shared
    `create_process_as_user(...)` path
    - scope the private desktop ACL to the launching logon SID
    
    ## Why
    Today sandboxed Windows commands run on the visible shared desktop. That
    leaves an avoidable same-desktop attack surface for window interaction,
    spoofing, and related UI/input issues. This change moves sandboxed
    commands onto a dedicated per-launch desktop by default so the sandbox
    no longer shares `Winsta0\Default` with the user session.
    
    The implementation stays conservative on security with no silent
    fallback back to `Winsta0\Default`
    
    If private-desktop setup fails on a machine, users can still opt out
    explicitly with `windows.sandbox_private_desktop=false`.
    
    ## Validation
    - `cargo build -p codex-cli`
    - elevated-path `codex exec` desktop-name probe returned
    `CodexSandboxDesktop-*`
    - elevated-path `codex exec` smoke sweep for shell commands, nested
    `pwsh`, jobs, and hidden `notepad` launch
    - unelevated-path full private-desktop compatibility sweep via `codex
    exec` with `-c windows.sandbox=unelevated`
  • fix: move inline codex-rs/core unit tests into sibling files (#14444)
    ## Why
    PR #13783 moved the `codex.rs` unit tests into `codex_tests.rs`. This
    applies the same extraction pattern across the rest of `codex-rs/core`
    so the production modules stay focused on runtime code instead of large
    inline test blocks.
    
    Keeping the tests in sibling files also makes follow-up edits easier to
    review because product changes no longer have to share a file with
    hundreds or thousands of lines of test scaffolding.
    
    ## What changed
    - replaced each inline `mod tests { ... }` in `codex-rs/core/src/**`
    with a path-based module declaration
    - moved each extracted unit test module into a sibling `*_tests.rs`
    file, using `mod_tests.rs` for `mod.rs` modules
    - preserved the existing `cfg(...)` guards and module-local structure so
    the refactor remains structural rather than behavioral
    
    ## Testing
    - `cargo test -p codex-core --lib` (`1653 passed; 0 failed; 5 ignored`)
    - `just fix -p codex-core`
    - `cargo fmt --check`
    - `cargo shear`
  • app-server support for Windows sandbox setup. (#12025)
    app-server support for initiating Windows sandbox setup.
    server responds quickly to setup request and makes a future RPC call
    back to client when the setup finishes.
    
    The TUI implementation is unaffected but in a future PR I'll update the
    TUI to use the shared setup helper
    (`windows_sandbox.run_windows_sandbox_setup`)
  • feat: introduce Permissions (#11633)
    ## Why
    We currently carry multiple permission-related concepts directly on
    `Config` for shell/unified-exec behavior (`approval_policy`,
    `sandbox_policy`, `network`, `shell_environment_policy`,
    `windows_sandbox_mode`).
    
    Consolidating these into one in-memory struct makes permission handling
    easier to reason about and sets up the next step: supporting named
    permission profiles (`[permissions.PROFILE_NAME]`) without changing
    behavior now.
    
    This change is mostly mechanical: it updates existing callsites to go
    through `config.permissions`, but it does not yet refactor those
    callsites to take a single `Permissions` value in places where multiple
    permission fields are still threaded separately.
    
    This PR intentionally **does not** change the on-disk `config.toml`
    format yet and keeps compatibility with legacy config keys.
    
    ## What Changed
    - Introduced `Permissions` in `core/src/config/mod.rs`.
    - Added `Config::permissions` and moved effective runtime permission
    fields under it:
      - `approval_policy`
      - `sandbox_policy`
      - `network`
      - `shell_environment_policy`
      - `windows_sandbox_mode`
    - Updated config loading/building so these effective values are still
    derived from the same existing config inputs and constraints.
    - Updated Windows sandbox helpers/resolution to read/write via
    `permissions`.
    - Threaded the new field through all permission consumers across core
    runtime, app-server, CLI/exec, TUI, and sandbox summary code.
    - Updated affected tests to reference `config.permissions.*`.
    - Renamed the struct/field from
    `EffectivePermissions`/`effective_permissions` to
    `Permissions`/`permissions` and aligned variable naming accordingly.
    
    ## Verification
    - `just fix -p codex-core -p codex-tui -p codex-cli -p codex-app-server
    -p codex-exec -p codex-utils-sandbox-summary`
    - `cargo build -p codex-core -p codex-tui -p codex-cli -p
    codex-app-server -p codex-exec -p codex-utils-sandbox-summary`
  • add a slash command to grant sandbox read access to inaccessible directories (#11512)
    There is an edge case where a directory is not readable by the sandbox.
    In practice, we've seen very little of it, but it can happen so this
    slash command unlocks users when it does.
    
    Future idea is to make this a tool that the agent knows about so it can
    be more integrated.
  • Promote Windows Sandbox (#11341)
    1. Move Windows Sandbox NUX to right after trust directory screen
    2. Don't offer read-only as an option in Sandbox NUX.
    Elevated/Legacy/Quit
    3. Don't allow new untrusted directories. It's trust or quit
    4. move experimental sandbox features to `[windows]
    sandbox="elevated|unelevatd"`
    5. Copy tweaks = elevated -> default, non-elevated -> non-admin
  • emit a separate metric when the user cancels UAT during elevated setup (#10399)
    Currently this shows up as elevated setup failure, which isn't quite
    accurate.
  • allow elevated sandbox to be enabled without base experimental flag (#10028)
    elevated flag = elevated sandbox
    experimental flag = non-elevated sandbox
    both = elevated
  • remove sandbox globals. (#9797)
    Threads sandbox updates through OverrideTurnContext for active turn
    Passes computed sandbox type into safety/exec
  • Elevated sandbox NUX (#8789)
    Elevated Sandbox NUX:
    
    * prompt for elevated sandbox setup when agent mode is selected (via
    /approvals or at startup)
    * prompt for degraded sandbox if elevated setup is declined or fails
    * introduce /elevate-sandbox command to upgrade from degraded
    experience.