safety: honor filesystem policy carveouts in apply_patch#13445
safety: honor filesystem policy carveouts in apply_patch#13445viyatb-oai merged 6 commits intomainfrom
Conversation
💡 Codex Reviewcodex/codex-rs/core/src/config/mod.rs Lines 1898 to 1902 in d7e45d6 [permissions.network]
This validation path now treats any non-empty codex/codex-rs/core/src/config/mod.rs Lines 1851 to 1852 in d7e45d6 The runtime network proxy config now reads only ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
b9614d6 to
da1d510
Compare
e915ef6 to
ebe6f77
Compare
e919dba to
b1aa31b
Compare
4b6d18c to
f04febf
Compare
…guage in config.toml (#13434) ## Why `SandboxPolicy` currently mixes together three separate concerns: - parsing layered config from `config.toml` - representing filesystem sandbox state - carrying basic network policy alongside filesystem choices That makes the existing config awkward to extend and blocks the new TOML proposal where `[permissions]` becomes a table of named permission profiles selected by `default_permissions`. (The idea is that if `default_permissions` is not specified, we assume the user is opting into the "traditional" way to configure the sandbox.) This PR adds the config-side plumbing for those profiles while still projecting back to the legacy `SandboxPolicy` shape that the current macOS and Linux sandbox backends consume. It also tightens the filesystem profile model so scoped entries only exist for `:project_roots`, and so nested keys must stay within a project root instead of using `.` or `..` traversal. This drops support for the short-lived `[permissions.network]` in `config.toml` because now that would be interpreted as a profile named `network` within `[permissions]`. ## What Changed - added `PermissionsToml`, `PermissionProfileToml`, `FilesystemPermissionsToml`, and `FilesystemPermissionToml` so config can parse named profiles under `[permissions.<profile>.filesystem]` - added top-level `default_permissions` selection, validation for missing or unknown profiles, and compilation from a named profile into split `FileSystemSandboxPolicy` and `NetworkSandboxPolicy` values - taught config loading to choose between the legacy `sandbox_mode` path and the profile-based path without breaking legacy users - introduced `codex-protocol::permissions` for the split filesystem and network sandbox types, and stored those alongside the legacy projected `sandbox_policy` in runtime `Permissions` - modeled `FileSystemSpecialPath` so only `ProjectRoots` can carry a nested `subpath`, matching the intended config syntax instead of allowing invalid states for other special paths - restricted scoped filesystem maps to `:project_roots`, with validation that nested entries are non-empty descendant paths and cannot use `.` or `..` to escape the project root - kept existing runtime consumers working by projecting `FileSystemSandboxPolicy` back into `SandboxPolicy`, with an explicit error for profiles that request writes outside the workspace root - loaded proxy settings from top-level `[network]` - regenerated `core/config.schema.json` ## Verification - added config coverage for profile deserialization, `default_permissions` selection, top-level `[network]` loading, network enablement, rejection of writes outside the workspace root, rejection of nested entries for non-`:project_roots` special paths, and rejection of parent-directory traversal in `:project_roots` maps - added protocol coverage for the legacy bridge rejecting non-workspace writes ## Docs - update the Codex config docs on developers.openai.com/codex to document named `[permissions.<profile>]` entries, `default_permissions`, scoped `:project_roots` syntax, the descendant-path restriction for nested `:project_roots` entries, and top-level `[network]` proxy configuration --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13434). * #13453 * #13452 * #13451 * #13449 * #13448 * #13445 * #13440 * #13439 * __->__ #13434
25dfa21 to
b8b3565
Compare
## Why `#13434` introduces split `FileSystemSandboxPolicy` and `NetworkSandboxPolicy`, but the runtime still made most execution-time sandbox decisions from the legacy `SandboxPolicy` projection. That projection loses information about combinations like unrestricted filesystem access with restricted network access. In practice, that means the runtime can choose the wrong platform sandbox behavior or set the wrong network-restriction environment for a command even when config has already separated those concerns. This PR carries the split policies through the runtime so sandbox selection, process spawning, and exec handling can consult the policy that actually matters. ## What changed - threaded `FileSystemSandboxPolicy` and `NetworkSandboxPolicy` through `TurnContext`, `ExecRequest`, sandbox attempts, shell escalation state, unified exec, and app-server exec overrides - updated sandbox selection in `core/src/sandboxing/mod.rs` and `core/src/exec.rs` to key off `FileSystemSandboxPolicy.kind` plus `NetworkSandboxPolicy`, rather than inferring behavior only from the legacy `SandboxPolicy` - updated process spawning in `core/src/spawn.rs` and the platform wrappers to use `NetworkSandboxPolicy` when deciding whether to set `CODEX_SANDBOX_NETWORK_DISABLED` - kept additional-permissions handling and legacy `ExternalSandbox` compatibility projections aligned with the split policies, including explicit user-shell execution and Windows restricted-token routing - updated callers across `core`, `app-server`, and `linux-sandbox` to pass the split policies explicitly ## Verification - added regression coverage in `core/tests/suite/user_shell_cmd.rs` to verify `RunUserShellCommand` does not inherit `CODEX_SANDBOX_NETWORK_DISABLED` from the active turn - added coverage in `core/src/exec.rs` for Windows restricted-token sandbox selection when the legacy projection is `ExternalSandbox` - updated Linux sandbox coverage in `linux-sandbox/tests/suite/landlock.rs` to exercise the split-policy exec path - verified the current PR state with `just clippy` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13439). * #13453 * #13452 * #13451 * #13449 * #13448 * #13445 * #13440 * __->__ #13439 --------- Co-authored-by: viyatb-oai <viyatb@openai.com>
## Why `#13434` and `#13439` introduce split filesystem and network policies, but the only code that could answer basic filesystem questions like "is access effectively unrestricted?" or "which roots are readable and writable for this cwd?" still lived on the legacy `SandboxPolicy` path. That would force later backends to either keep projecting through `SandboxPolicy` or duplicate path-resolution logic. This PR moves those queries onto `FileSystemSandboxPolicy` itself so later runtime and platform changes can consume the split policy directly. ## What changed - added `FileSystemSandboxPolicy` helpers for full-read/full-write checks, platform-default reads, readable roots, writable roots, and explicit unreadable roots resolved against a cwd - added a shared helper for the default read-only carveouts under writable roots so the legacy and split-policy paths stay aligned - added protocol coverage for full-access detection and derived readable, writable, and unreadable roots ## Verification - added protocol coverage in `protocol/src/protocol.rs` and `protocol/src/permissions.rs` for full-root access and derived filesystem roots - verified the current PR state with `just clippy` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13440). * #13453 * #13452 * #13451 * #13449 * #13448 * #13445 * __->__ #13440 * #13439 --------- Co-authored-by: viyatb-oai <viyatb@openai.com>
Why
apply_patchsafety approval was still checking writable paths through the legacySandboxPolicyprojection.That can hide explicit
nonecarveouts when a split filesystem policy projects back to compatibilityExternalSandbox, which leaves one more approval path that can auto-approve writes inside paths that are intentionally blocked.What changed
turn.file_system_sandbox_policyintoassess_patch_safetyFileSystemSandboxPolicyinstead of the legacySandboxPolicyExternalSandboxcompatibility projection still asks for approval when the split filesystem policy blocks a subpathVerification
cargo test -p codex-core safety::tests::cargo test -p codex-core test_sandbox_config_parsingcargo clippy -p codex-core --all-targets -- -D warningsStack created with Sapling. Best reviewed with ReviewStack.