Commit Graph
54 Commits
Author SHA1 Message Date
Anton PanasenkoandGitHub b9dc3b7a8b feat(app-server): enforce managed remote control disable (#27961)
## Why

Managed deployments need a reliable deny gate for remote control.
Persisted enablement and explicit startup requests currently remain able
to start the transport, while the removed `features.remote_control` key
is intentionally only a compatibility no-op.

This adds a dedicated requirement that administrators can use to force
remote control off without deleting the user's persisted preference.
Removing the requirement and restarting restores the prior choice.

## What Changed

- Added top-level `allow_remote_control` requirements parsing, sourced
layer precedence, debug output, and `configRequirements/read` exposure
as `allowRemoteControl`.
- Added a typed transport policy captured from the startup requirements
snapshot. Managed disable forces the initial state to disabled and
prevents enrollment, refresh, connection, and persisted-preference
mutation.
- Rejected every `remoteControl/*` RPC before parameter deserialization
with JSON-RPC `-32600` and `remote control is disabled by managed
requirements`.
- Preserved the existing disabled status notification and the previous
behavior when the requirement is `true` or omitted.
- Regenerated app-server protocol schemas and documented the new
requirement.

## Verification

- Confirmed all remote-control RPCs, including a malformed request,
return the managed-policy error while the initial status notification
remains `disabled`.
- Confirmed explicit ephemeral startup and persisted enablement make no
backend connection and leave the SQLite preference unchanged.
- Confirmed `allow_remote_control = true` does not enable or block
remote control and `configRequirements/read` returns
`allowRemoteControl: false` for the deny policy.

Related issue: N/A (managed-policy hardening).
2026-06-12 20:10:12 -07:00
Eric TrautandGitHub 36fc79c6f4 Remove TUI legacy core test_support dependencies (#27484)
## Why

The TUI now sits on the app-server layer, but
`app-server-client::legacy_core` still exposed core test helpers solely
for TUI tests. We've been whittling away the remaining dependencies.
This is the next step on that journey.

There is no functional change — just a refactor, and this affects only
test code, so it should be low risk.

## What changed

- remove the `legacy_core::test_support` re-export and call
model-manager test helpers directly
- keep the bundled model-preset cache local to TUI test support
- import constraint types directly from `codex-config`
2026-06-10 17:55:49 -07:00
canvrno-oaiandGitHub 8534912df9 Show effective sandbox modes in /debug-config (#27068)
## Summary
- Render `/debug-config`'s `allowed_sandbox_modes` from the finalized
permission constraints instead of the raw requirements list.
- Add regression coverage for configured full-access and external
sandbox modes being omitted when effective permissions reject them.

## Details
`allowed_sandbox_modes` comes from managed requirements, but the final
permissions can be further constrained by derived validation rules. For
example, `permissions.filesystem.deny_read` requires sandbox
enforcement, so modes that disable or externalize Codex's sandbox are
not actually usable even if they were present in the raw requirements
TOML.

The debug renderer now enumerates the configured sandbox-mode labels and
keeps only those accepted by `Config.permissions`. That makes
`/debug-config` reflect the same effective permission-profile constraint
path used by runtime config validation, while preserving the existing
source/provenance display.

## Validation
- Added a regression test for effective sandbox-mode filtering in
`/debug-config`.
2026-06-08 17:03:52 -07:00
9e0d7f02c9 fix: preserve auto review across config and delegation (#26230)
## Why

Auto Review should remain the effective approval reviewer when settings
cross runtime boundaries. A config or app-server round trip must not
change the reviewer identity, and delegated work must not silently fall
back to user review.

This requires both a stable canonical serialized value and propagation
of the effective setting. `auto_review` is the canonical value across
protocol and app-server output, while `guardian_subagent` remains
accepted as backward-compatible input.

## What changed

- serialize `ApprovalsReviewer::AutoReview` consistently as
`auto_review` across core protocol and app-server v2
- continue accepting `guardian_subagent` when reading existing config or
client requests
- carry the active turn's approval reviewer into spawned agents
- update config/debug expectations and add delegated-task regression
coverage

## Scope

This does not change Guardian policy or remove compatibility with
existing `guardian_subagent` inputs. It preserves the selected reviewer
across serialization, config reloads, app-server settings, and delegated
task setup.

Related Guardian changes are split independently:

- #26231 adds denials and soft denials
- #26334 retries transient reviewer failures
- #26333 reuses narrowly scoped low-risk approvals
- #26232 adds TUI denial recovery

## Validation

- `just test -p codex-app-server-protocol` (224 passed)
- regression coverage for delegated task reviewer propagation
- serialization coverage for canonical `auto_review` output and legacy
`guardian_subagent` input

---------

Co-authored-by: saud-oai <saud@openai.com>
2026-06-08 18:59:50 +00:00
2f108f9fd9 permissions: enforce managed permission profile allowlists (#24852)
## Why

Permission profile allowlists are an enterprise security boundary, but
they also need to compose across the managed requirements layers added
in #24620.

A map representation lets each requirements layer add, allow, or revoke
individual profiles without replacing an entire array.

## Managed Contract

Administrators configure the mergeable allow map with
`allowed_permission_profiles`. A recommended enterprise configuration
explicitly lists every built-in and custom profile users should be able
to select:

```toml
default_permissions = "review_only"

[allowed_permission_profiles]
":read-only" = true
":workspace" = true
review_only = true
# ":danger-full-access" is intentionally omitted, so it is denied.

[permissions.review_only]
extends = ":read-only"
```

- Profiles whose effective merged value is `true` are allowed.
- Missing profiles and profiles set to `false` are denied.
- This is a closed allowlist: built-in profiles and profiles introduced
in future versions are denied unless explicitly allowed.
- Explicitly list each built-in profile the enterprise wants to make
available. Omit built-ins such as `:danger-full-access` when they should
remain unavailable.
- Set `default_permissions` explicitly to the allowed profile users
should receive when they have no local selection.
- Higher-precedence layers override only the profile keys they define.
- `false` is only needed when a higher-precedence layer must revoke a
`true` inherited from a lower layer.
- Explicit keys must refer to known built-in or managed profiles.

A custom or narrowed allowlist requires an allowed
`default_permissions`. For compatibility, if both `:workspace` and
`:read-only` are explicitly allowed, an omitted default resolves to
`:workspace`; customer configurations should still set the intended
default explicitly.

When `allowed_permission_profiles` is absent, existing implicit
permission and legacy `sandbox_mode` behavior is unchanged.

## What Changed

- Add `allowed_permission_profiles` as a `BTreeMap<String, bool>` that
merges per profile across requirements layers.
- Enforce managed defaults, strict denial of omitted profiles, and the
explicitly allowed standard-pair fallback.
- Expose `allowedPermissionProfiles` through `configRequirements/read`
and regenerate its schemas.
- Add regression coverage for map composition and revocation, managed
defaults, strict denial of omitted built-ins, and API output.

## Verification

- Focused `codex-config` coverage for layered map composition and
revocation
- Focused `codex-core` coverage for managed defaults, invalid defaults,
strict denial of omitted built-ins, and the standard built-in pair
- Focused `codex-app-server` coverage for requirements API output
- Scoped Clippy for `codex-config`, `codex-core`,
`codex-app-server-protocol`, and `codex-app-server`

## Documentation

The managed `requirements.toml` documentation should introduce
`allowed_permission_profiles` as a closed permission-profile allowlist
before this setting is published on developers.openai.com.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-06-05 18:06:29 -07:00
joeflorencio-openaiandGitHub d45cd26248 Switch runtime to cloud config bundle (#24622)
## Summary

- Adapts the moved `codex-cloud-config` crate from the legacy cloud
requirements endpoint to the new config bundle endpoint.
- Switches runtime consumers from `CloudRequirementsLoader` to
`CloudConfigBundleLoader` so one shared bundle supplies cloud-delivered
config and requirements.
- Removes the legacy cloud requirements domain loader path.

## Details

This intentionally keeps `codex-cloud-config` monolithic for review
lineage: the previous PR establishes the crate move, and this PR shows
the behavior change against that moved implementation. A follow-up PR
splits the module back into focused files.

The new bundle path preserves the important cloud requirements loader
semantics where intended: account-scoped signed cache, 30 minute TTL, 5
minute refresh cadence, retry/backoff, auth recovery, and fail-closed
startup loading. The cached payload changes from a single requirements
TOML string to the backend-delivered bundle, and validation rejects
malformed config or requirements fragments before cache write/use.
2026-06-02 13:18:59 -07:00
joeflorencio-openaiandGitHub 8a556296f0 Add cloud-managed config layer support (#24620)
## Summary

PR 3 of 5 in the cloud-managed config client stack.

Adds enterprise-managed cloud config as a first-class config layer
source. The layer metadata is preserved through config loading,
diagnostics, debug output, hook attribution, and app-server protocol
surfaces.

## Details

- Enterprise-managed config becomes a normal config layer source with
backend-supplied `id` and display `name` attached for provenance.
- These layers are designed to behave like non-file managed config: they
can surface syntax/type diagnostics by layer name even though there is
no physical config file.
- Relative path settings are resolved from a stored config base so
cloud-delivered config remains consistent with existing MDM-delivered
config semantics.
- Hook attribution distinguishes config-delivered hooks from
requirements-delivered hooks via `HookSource::CloudManagedConfig`.
- This remains pull-based and snapshot-oriented; the PR adds layer
identity/diagnostics, not dynamic reload behavior.

## Validation

Validated through the targeted stack checks after rebasing onto current
`main`:

- Rust crate tests for
config/hooks/cloud-config/backend-client/app-server-protocol
- Filtered `codex-core` and `codex-app-server` `cloud_config_bundle`
tests
- Python generated-file contract test
- `cargo shear --deny-warnings`
- Targeted `argument-comment-lint` for config/hooks
2026-05-31 15:54:31 -07:00
AbhinavandGitHub a5a94ee5a7 Constrain Windows sandbox requirements (#23766)
# Why

Managed requirements can already constrain sandbox policy choices, but
Windows sandbox implementation selection was still resolved
independently from those requirements. That left the TUI able to
continue through the unelevated fallback even when an organization wants
to require the elevated Windows sandbox implementation.

# What

- Add `[windows].allowed_sandbox_implementations` requirements support
for the Windows `elevated` and `unelevated` implementations.
- Apply that allowlist during core config resolution so disallowed
configured or feature-selected Windows sandbox implementations fall back
to an allowed implementation with the existing requirements warning
path.
- Reuse the existing TUI Windows setup prompts to block disallowed
unelevated continuation, keep required elevated setup in front of the
user, and refuse to persist a TUI-selected Windows sandbox mode that
requirements disallow.

# Semantics

| Allowed | Selected | Effective |
| --- | --- | --- |
| `["elevated"]` | `unelevated` / unset | `elevated` |
| `["unelevated"]` | `elevated` / unset | `unelevated` |
| `["elevated", "unelevated"]` | `elevated` | `elevated` |
| `["elevated", "unelevated"]` | `unelevated` | `unelevated` |
| `["elevated", "unelevated"]` | unset | `elevated` |

Availability is handled by interactive setup surfaces after allowlist
resolution. If the effective elevated implementation is not ready,
elevated-only requirements block on setup. When unelevated is also
allowed, the UI may offer the existing unelevated fallback.

## TUI Screens

If elevated setup is not already complete:
```
  Your organization requires the default Codex agent sandbox to continue. Set it up to protect your files and control
  network access.
  Learn more <https://developers.openai.com/codex/windows>

› 1. Set up default sandbox (requires Administrator permissions)
  2. Quit
```

If admin setup fails under `["elevated"]`:
```
  Couldn't set up your sandbox with Administrator permissions

  Your organization requires the default sandbox before Codex can continue.
  Learn more <https://developers.openai.com/codex/windows>

› 1. Try setting up admin sandbox again
  2. Quit
```

# Next Steps


- extend the requirements/readout surface, such as
`configRequirements/read`, so clients can inspect the loaded
`[windows].allowed_sandbox_implementations` requirement instead of
inferring it from Windows setup state
- consider extending `windowsSandbox/readiness` as well
- update the App startup guide, setup flow, and banner surfaces so an
elevated-only requirement omits any continue-unelevated escape hatch and
blocks startup until a permitted implementation is ready;
- preserve the existing unelevated fallback path when requirements allow
it, including the `["unelevated"]` case where elevated is disallowed
2026-05-29 16:31:33 -07:00
viyatb-oaiandGitHub bf72be5927 fix(config): use deny for Unix socket permissions (#24970)
## Why

Unix socket permissions still accepted and displayed `"none"` while file
permissions use the clearer `"deny"` spelling. This keeps network Unix
socket policy vocabulary consistent with filesystem policy vocabulary.

## What changed

- Replace the Unix socket permission variant and serialized spelling
from `none` to `deny` across config, feature configuration, and network
proxy types.
- Update app-server v2 serialization, TUI debug output, focused tests,
and generated schemas to expose `"deny"`.
- Add coverage for denied Unix socket entries in managed requirements
and profile overlay behavior.

## Security

This is a vocabulary change for explicit Unix socket rejection, not a
network access expansion. Denied entries continue to be omitted from the
effective allowlist.

## Validation

- `just fmt`
- `just write-config-schema`
- `just write-app-server-schema`
- `just test -p codex-config -p codex-core -p codex-app-server-protocol
-p codex-tui -E
'test(network_requirements_are_preserved_as_constraints_with_source) |
test(network_permission_containers_project_allowed_and_denied_entries) |
test(network_toml_overlays_unix_socket_permissions_by_path) |
test(permissions_profiles_resolve_extends_parent_first_with_child_overrides)
| test(network_requirements_serializes_canonical_and_legacy_fields) |
test(debug_config_output_formats_unix_socket_permissions)'`\n- Automatic
`bench-smoke` follow-up from `just test`\n- `cargo clippy -p
codex-config -p codex-core -p codex-features -p codex-network-proxy -p
codex-app-server-protocol -p codex-app-server -p codex-tui --all-targets
-- -D warnings`
2026-05-28 23:53:26 +00:00
adams-oaiandGitHub 865ca936db Add new enterprise requirement gate (#23736)
Add new enterprise requirement gate.

Validation:
- `cargo test -p codex-config --lib`
- `cargo test -p codex-app-server-protocol --lib`
- `cargo test -p codex-tui --lib debug_config`
- `cargo test -p codex-app-server --lib` *(fails: stack overflow in
`in_process::tests::in_process_start_initializes_and_handles_typed_v2_request`;
reproduces when run alone)*
2026-05-22 11:33:44 -07:00
viyatb-oaiandGitHub 713a5b1b00 feat: support managed permission profiles in requirements.toml (#23433)
## Why

Cloud-managed `requirements.toml` should be able to define the managed
permission profiles a client may select and constrain that selectable
set without requiring local user config to recreate the profile catalog.

This keeps requirements focused on restrictions. The selected default
remains a config or session choice, while requirements contribute the
managed profile bodies and `allowed_permissions` allowlist that the
config-loading boundary validates before a resolved runtime
`PermissionProfile` is installed.

## What changed

- Add `requirements.toml` support for a managed permission-profile
catalog plus its allowlist:

```toml
allowed_permissions = ["review", "build"]

[permissions.review]
extends = ":read-only"

[permissions.build]
extends = ":workspace"
```

- Merge requirements-defined profile bodies into the effective
permission catalog and reject profile ids that collide with
config-defined profiles.
- Validate that every `allowed_permissions` entry resolves to a built-in
or catalog profile before selection uses it.
- Preserve allowed configured named-profile selections. When a
configured named profile is disallowed, fall back to the first allowed
requirements profile with a startup warning.
- Keep built-in selections and the stock trust-based `:read-only` /
`:workspace` fallback path intact when no permission profile is
explicitly selected.
- Centralize the managed catalog and allowlist selection path in
`EffectivePermissionSelection` so the requirements boundary is visible
in config loading.
- Surface `allowedPermissions` through `configRequirements/read`, and
update the generated app-server schema fixtures plus the app-server
README.

## Validation

- `cargo test -p codex-config`
- `cargo test -p codex-core system_requirements_`
- `cargo test -p codex-core system_allowed_permissions_`
- `cargo test -p codex-app-server-protocol`
- `just write-app-server-schema`

## Related work

- Uses merged permission-profile inheritance support from #22270 and
#23705.
- Kept separate from the in-flight permission profile listing API in
#23412.
2026-05-20 17:33:01 -07:00
adams-oaiandGitHub d86352d520 Add CUA requirements subsection for locked computer use (#23555)
Adds a new top-level section for "CUA" requirements that can allow for
disablement of specific features as needed for enterprises.
2026-05-19 15:41:44 -07:00
deedf3b2c4 feat: add layered --profile-v2 config files (#17141)
## Why

`--profile-v2 <name>` gives launchers and runtime entry points a named
profile config without making each profile duplicate the base user
config. The base `$CODEX_HOME/config.toml` still loads first, then
`$CODEX_HOME/<name>.config.toml` layers above it and becomes the active
writable user config for that session.

That keeps shared defaults, plugin/MCP setup, and managed/user
constraints in one place while letting a named profile override only the
pieces that need to differ.

## What Changed

- Added the shared `--profile-v2 <name>` runtime option with validated
plain names, now represented by `ProfileV2Name`.
- Extended config layer state so the base user config and selected
profile config are both `User` layers; APIs expose the active user layer
and merged effective user config.
- Threaded profile selection through runtime entry points: `codex`,
`codex exec`, `codex review`, `codex resume`, `codex fork`, and `codex
debug prompt-input`.
- Made user-facing config writes go to the selected profile file when
active, including TUI/settings persistence, app-server config writes,
and MCP/app tool approval persistence.
- Made plugin, marketplace, MCP, hooks, and config reload paths read
from the merged user config so base and profile layers both participate.
- Updated app-server config layer schemas to mark profile-backed user
layers.

## Limits

`--profile-v2` is still rejected for config-management subcommands such
as feature, MCP, and marketplace edits. Those paths remain tied to the
base `config.toml` until they have explicit profile-selection semantics.

Some adjacent background writes may still update base or global state
rather than the selected profile:

- marketplace auto-upgrade metadata
- automatic MCP dependency installs from skills
- remote plugin sync or uninstall config edits
- personality migration marker/default writes

## Verification

Added targeted coverage for profile name validation, layer
ordering/merging, selected-profile writes, app-server config writes,
session hot reload, plugin config merging, hooks/config fixture updates,
and MCP/app approval persistence.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-05-14 15:16:15 +02:00
Andrei EternalandGitHub 913aad4d3c Add allow_managed_hooks_only hook requirement (#20319)
## Why

Enterprise-managed hook policy needs a narrow way to require Codex to
ignore user-controlled lifecycle hooks without adopting the broader
trust-precedence model from earlier hook work. This keeps the policy
anchored in `requirements.toml`, so admins can opt into managed hooks
only while normal `config.toml` files cannot enable the restriction
themselves.

## What changed

- Added `allow_managed_hooks_only` to the requirements data flow and
preserved explicit `false` values.
- Also adds it to /debug-config
- Marked MDM, system, and legacy managed config layers as managed for
hook discovery.
- Updated hook discovery so `allow_managed_hooks_only = true`:
  - keeps managed requirements hooks and managed config-layer hooks,
- skips user/project/session `hooks.json` and `[hooks]` entries with
concise startup warnings,
  - skips current unmanaged plugin hooks,
- ignores any `allow_managed_hooks_only` key placed in ordinary
`config.toml` layers.
2026-05-12 19:05:25 -07:00
AbhinavandGitHub 9ab7f4e6ac Add Windows hook command overrides (#22159)
# Why

Managed hook configs need a shared cross-platform shape without making
the existing `command` field polymorphic. The common case is still one
command string, with Windows needing a different entrypoint only when
the runtime is actually Windows.

Keeping `command` as the portable/default path and adding an optional
Windows override keeps the config easier to read, preserves the existing
scalar shape for non-Windows users, and avoids forcing every caller into
a `{ unix, windows }` object when only one platform needs special
handling.

# What

- Add optional `command_windows` / `commandWindows` alongside the
existing hook `command` field.
- Resolve `command_windows` only on Windows during hook discovery; other
platforms continue to use `command` unchanged.
- Keep trust hashing aligned to the effective command selected for the
current runtime.

# Docs

The Codex hooks/config reference should document `command_windows` as
the Windows-only override for command hooks.
2026-05-11 22:22:29 +00:00
Eric TrautandGitHub f2bc2f26a9 Remove core protocol dependency [2/2] (#20325)
## Why

With the local model layer and app-server routing in place from PR1,
this PR moves the active TUI runtime onto app-server notifications. The
affected pieces share the same event flow, so the command surface,
session state, bottom-pane prompts, chat rendering, history/status
views, and tests move together to keep the stacked branch buildable.

This PR also removes the obsolete compatibility surface that is no
longer used after the migration. The proposed protocol-boundary verifier
layer was dropped from the stack; enforcing that final boundary will be
simpler once `codex-tui` no longer needs any `codex_protocol`
references.

This PR is part 2 of a 2-PR stack:

1. Add TUI-owned replacement models and extract app-server event
routing.
2. Move the active TUI flow to app-server notifications and delete
obsolete adapter code.

## What changed

- Rewired app command and session handling to use app-server request and
notification shapes.
- Moved approval overlays, request-user-input flows, MCP elicitation,
realtime events, and review commands onto the app-server-facing model
surface.
- Updated chat rendering, history cells, status views, multi-agent UI,
replay state, and TUI tests to use app-server notifications plus the
local models introduced in PR1.
- Deleted `codex-rs/tui/src/app/app_server_adapter.rs` and the
superseded `chatwidget/tests/background_events.rs` fixture path.

## Verification

- `cargo check -p codex-tui --tests`
- Top of stack: `cargo test -p codex-tui`
2026-04-30 11:34:34 -07:00
Matthew ZengandGitHub e20391e567 [mcp] Fix plugin MCP approval policy. (#19537)
Plugin MCP servers are loaded from plugin manifests rather than
top-level `[mcp_servers]`, so their tool approval preferences need to be
stored and applied through the owning plugin config. Without this,
choosing "Always allow" for a plugin MCP tool could write a preference
that was not reliably used on later tool calls.

## Summary
- Add plugin-scoped MCP policy config under
`plugins.<plugin>.mcp_servers`, including server enablement, tool
allow/deny lists, server defaults, and per-tool approval modes.
- Overlay plugin MCP policy onto manifest-provided server configs when
plugins are loaded.
- Route persistent "Always allow" writes for plugin MCP tools back to
the owning `plugins.<plugin>.mcp_servers.<server>.tools.<tool>` config
entry.
- Reload user config after persisting an approval and make the plugin
load cache config-aware so stale plugin MCP policy is not reused after
`config.toml` changes.
- Regenerate the config schema and add coverage for plugin MCP policy
loading, approval lookup, persistence, and stale-cache prevention.

## Testing
- `cargo test -p codex-config`
- `cargo test -p codex-core-plugins`
- `cargo test -p codex-core --lib plugin_mcp`
2026-04-29 15:40:03 -07:00
Michael BolinandGitHub 523e4aa8e3 permissions: constrain requirements as profiles (#19736) 2026-04-26 21:49:30 -07:00
Won ParkandGitHub 17ae906048 Fix auto-review config compatibility across protocol and SDK (#19113)
## Why

This keeps the partial Guardian subagent -> Auto-review rename
forward-compatible across mixed Codex installations. Newer binaries need
to understand the new `auto_review` spelling, but they cannot write it
to shared `~/.codex/config.toml` yet because older CLI/app-server
bundles only know `user` and `guardian_subagent` and can fail during
config load before recovering.

The Python SDK had the opposite compatibility gap: app-server responses
can contain `approvalsReviewer: "auto_review"`, but the checked-in
generated SDK enum did not accept that value.

## What Changed

- Keep `ApprovalsReviewer::AutoReview` readable from both
`guardian_subagent` and `auto_review`, while serializing it as
`guardian_subagent` in both protocol crates.
- Update TUI Auto-review persistence tests so enabling Auto-review
writes `approvals_reviewer = "guardian_subagent"` while UI copy still
says Auto-review.
- Map managed/cloud `feature_requirements.auto_review` to the existing
`Feature::GuardianApproval` gate without adding a broad local
`[features].auto_review` key or changing config writes.
- Add `auto_review` to the Python SDK `ApprovalsReviewer` enum and cover
`ThreadResumeResponse` validation.

## Testing

- `cargo test -p codex-protocol approvals_reviewer`
- `cargo test -p codex-app-server-protocol approvals_reviewer`
- `cargo test -p codex-tui
update_feature_flags_enabling_guardian_selects_auto_review`
- `cargo test -p codex-tui
update_feature_flags_enabling_guardian_in_profile_sets_profile_auto_review_policy`
- `cargo test -p codex-core
feature_requirements_auto_review_disables_guardian_approval`
- `pytest
sdk/python/tests/test_client_rpc_methods.py::test_thread_resume_response_accepts_auto_review_reviewer`
- `git diff --check`
2026-04-23 03:12:56 -07:00
2b2de3f38b codex: support hooks in config.toml and requirements.toml (#18893)
## Summary

Support the existing hooks schema in inline TOML so hooks can be
configured from both `config.toml` and enterprise-managed
`requirements.toml` without requiring a separate `hooks.json` payload.

This gives enterprise admins a way to ship managed hook policy through
the existing requirements channel while still leaving script delivery to
MDM or other device-management tooling, and it keeps `hooks.json`
working unchanged for existing users.

This also lays the groundwork for follow-on managed filtering work such
as #15937, while continuing to respect project trust gating from #14718.
It does **not** implement `allow_managed_hooks_only` itself.

NOTE: yes, it's a bit unfortunate that the toml isn't formatted as
closely as normal to our default styling. This is because we're trying
to stay compatible with the spec for plugins/hooks that we'll need to
support & the main usecase here is embedding into requirements.toml

## What changed

- moved the shared hook serde model out of `codex-rs/hooks` into
`codex-rs/config` so the same schema can power `hooks.json`, inline
`config.toml` hooks, and managed `requirements.toml` hooks
- added `hooks` support to both `ConfigToml` and
`ConfigRequirementsToml`, including requirements-side `managed_dir` /
`windows_managed_dir`
- treated requirements-managed hooks as one constrained value via
`Constrained`, so managed hook policy is merged atomically and cannot
drift across requirement sources
- updated hook discovery to load requirements-managed hooks first, then
per-layer `hooks.json`, then per-layer inline TOML hooks, with a warning
when a single layer defines both representations
- threaded managed hook metadata through discovered handlers and exposed
requirements hooks in app-server responses, generated schemas, and
`/debug-config`
- added hook/config coverage in `codex-rs/config`, `codex-rs/hooks`,
`codex-rs/core/src/config_loader/tests.rs`, and
`codex-rs/core/tests/suite/hooks.rs`

## Testing

- `cargo test -p codex-config`
- `cargo test -p codex-hooks`
- `cargo test -p codex-app-server config_api`

## Documentation

Companion updates are needed in the developers website repo for:

- the hooks guide
- the config reference, sample, basic, and advanced pages
- the enterprise managed configuration guide

---------

Co-authored-by: Michael Bolin <mbolin@openai.com>
2026-04-22 21:20:09 -07:00
Won ParkandGitHub 83ec1eb5d6 Rename approvals reviewer variant to auto-review (#19056)
## Why

`approvals_reviewer` now uses `auto_review` as the canonical config/API
value after #18504, but the Rust enum variant and nearby helper/test
names still used `GuardianSubagent` / guardian approval wording. That
made follow-up code and reviews confusing even though the external value
had already moved to Auto-review.

## What changed

- Renamed `ApprovalsReviewer::GuardianSubagent` to
`ApprovalsReviewer::AutoReview`.
- Updated protocol, app-server, config, core, TUI, exec, and analytics
test callsites.
- Renamed nearby helper/test names from guardian approval wording to
Auto-review wording where they refer to the approvals reviewer mode.
- Preserved wire compatibility:
  - `auto_review` remains the canonical serialized value.
  - `guardian_subagent` remains accepted as a legacy alias.

This intentionally does not rename the `[features].guardian_approval`
key, `Feature::GuardianApproval`, `core/src/guardian`, analytics event
names, or app-server Guardian review event types.

## Verification

- `cargo test -p codex-protocol
approvals_reviewer_serializes_auto_review_and_accepts_legacy_guardian_subagent`
- `cargo test -p codex-app-server-protocol
approvals_reviewer_serializes_auto_review_and_accepts_legacy_guardian_subagent`
- `cargo test -p codex-config approvals_reviewer`
- `cargo test -p codex-tui update_feature_flags`
- `cargo test -p codex-core permissions_instructions`
- `cargo test -p codex-tui permissions_selection`
2026-04-22 17:22:35 -07:00
Won ParkandGitHub 46142c3cb0 Rebrand approvals reviewer config to auto-review (#18504)
### Why

Auto-review is the user-facing name for the approvals reviewer, but the
config/API value still exposed the old `guardian_subagent` name. That
made new configs and generated schemas point users at Guardian
terminology even though the intended product surface is Auto-review.

This PR updates the external `approvals_reviewer` value while preserving
compatibility for existing configs and clients.

### What changed

- Makes `auto_review` the canonical serialized value for
`approvals_reviewer`.
- Keeps `guardian_subagent` accepted as a legacy alias.
- Keeps `user` accepted and serialized as `user`.
- Updates generated config and app-server schemas so
`approvals_reviewer` includes:
  - `user`
  - `auto_review`
  - `guardian_subagent`
- Updates app-server README docs for the reviewer value.
- Updates analytics and config requirements tests for the canonical
auto_review value.


### Compatibility

Existing configs and API payloads using:

```toml
approvals_reviewer = "guardian_subagent"
```

continue to load and map to the Auto-review reviewer behavior. 

New serialization emits: 
```toml
approvals_reviewer = "auto_review" 
```

This PR intentionally does not rename the [features].guardian_approval
key or broad internal Guardian symbols. Those are split out for a
follow-up PR to keep this migration small and avoid touching large
TUI/internal surfaces.

**Verification**
cargo test -p codex-protocol
approvals_reviewer_serializes_auto_review_and_accepts_legacy_guardian_subagent
cargo test -p codex-app-server-protocol
approvals_reviewer_serializes_auto_review_and_accepts_legacy_guardian_subagent
2026-04-22 15:45:35 -07:00
Dylan HurdandGitHub 0e39614d87 chore(tui) debug-config guardian_policy_config (#18923)
## Summary
List guardian_policy_config_source in `/debug-config` output

## Testing
 - [x] Ran locally
2026-04-21 21:00:23 -07:00
AbhinavandGitHub ab26554a3a Add remote_sandbox_config to our config requirements (#18763)
## Why

Customers need finer-grained control over allowed sandbox modes based on
the host Codex is running on. For example, they may want stricter
sandbox limits on devboxes while keeping a different default elsewhere.

Our current cloud requirements can target user/account groups, but they
cannot vary sandbox requirements by host. That makes remote development
environments awkward because the same top-level `allowed_sandbox_modes`
has to apply everywhere.

## What

Adds a new `remote_sandbox_config` section to `requirements.toml`:

```toml
allowed_sandbox_modes = ["read-only"]

[[remote_sandbox_config]]
hostname_patterns = ["*.org"]
allowed_sandbox_modes = ["read-only", "workspace-write"]

[[remote_sandbox_config]]
hostname_patterns = ["*.sh", "runner-*.ci"]
allowed_sandbox_modes = ["read-only", "danger-full-access"]
```

During requirements resolution, Codex resolves the local host name once,
preferring the machine FQDN when available and falling back to the
cleaned kernel hostname. This host classification is best effort rather
than authenticated device proof.

Each requirements source applies its first matching
`remote_sandbox_config` entry before it is merged with other sources.
The shared merge helper keeps that `apply_remote_sandbox_config` step
paired with requirements merging so new requirements sources do not have
to remember the extra call.

That preserves source precedence: a lower-precedence requirements file
with a matching `remote_sandbox_config` cannot override a
higher-precedence source that already set `allowed_sandbox_modes`.

This also wires the hostname-aware resolution through app-server,
CLI/TUI config loading, config API reads, and config layer metadata so
they all evaluate remote sandbox requirements consistently.

## Verification

- `cargo test -p codex-config remote_sandbox_config`
- `cargo test -p codex-config host_name`
- `cargo test -p codex-core
load_config_layers_applies_matching_remote_sandbox_config`
- `cargo test -p codex-core
system_remote_sandbox_config_keeps_cloud_sandbox_modes`
- `cargo test -p codex-config`
- `cargo test -p codex-core` unit tests passed; `tests/all.rs`
integration matrix was intentionally stopped after the relevant focused
tests passed
- `just fix -p codex-config`
- `just fix -p codex-core`
- `cargo check -p codex-app-server`
2026-04-21 05:05:02 +00:00
Eric TrautandGitHub 164b6a0c78 Remove simple TUI legacy_core reexports (#18631)
## Problem
The TUI still imported path utilities and config-loader symbols through
app-server-client's legacy_core facade even though those APIs already
exist in utility/config crates. This is part of our ongoing effort to
whittle away at these old dependencies.

## Solution
Rewire imports to avoid the TUI directly importing from the core crate
and instead import from common lower-level crates. This PR doesn't
include any functional changes; it's just a simple rewiring.
2026-04-20 10:48:27 -07:00
dae0608c06 feat(config): support managed deny-read requirements (#17740)
## Summary
- adds managed requirements support for deny-read filesystem entries
- constrains config layers so managed deny-read requirements cannot be
widened by user-controlled config
- surfaces managed deny-read requirements through debug/config plumbing

This PR lets managed requirements inject deny-read filesystem
constraints into the effective filesystem sandbox policy.
User-controlled config can still choose the surrounding permission
profile, but it cannot remove or weaken the managed deny-read entries.

## Managed deny-read shape
A managed requirements file can declare exact paths and glob patterns
under `[permissions.filesystem]`:

```toml
# /etc/codex/requirements.toml
[permissions.filesystem]
deny_read = [
  "/Users/alice/.gitconfig",
  "/Users/alice/.ssh",
  "./managed-private/**/*.env",
]
```

Those entries are compiled into the effective filesystem policy as
`access = none` rules, equivalent in shape to filesystem permission
entries like:

```toml
[permissions.workspace.filesystem]
"/Users/alice/.gitconfig" = "none"
"/Users/alice/.ssh" = "none"
"/absolute/path/to/managed-private/**/*.env" = "none"
```

The important difference is that the managed entries come from
requirements, so lower-precedence user config cannot remove them or make
those paths readable again.

Relative managed `deny_read` entries are resolved relative to the
directory containing the managed requirements file. Glob entries keep
their glob suffix after the non-glob prefix is normalized.

## Runtime behavior
- Managed `deny_read` entries are appended to the effective
`FileSystemSandboxPolicy` after the selected permission profile is
resolved.
- Exact paths become `FileSystemPath::Path { access: None }`; glob
patterns become `FileSystemPath::GlobPattern { access: None }`.
- When managed deny-read entries are present, `sandbox_mode` is
constrained to `read-only` or `workspace-write`; `danger-full-access`
and `external-sandbox` cannot silently bypass the managed read-deny
policy.
- On Windows, the managed deny-read policy is enforced for direct file
tools, but shell subprocess reads are not sandboxed yet, so startup
emits a warning for that platform.
- `/debug-config` shows the effective managed requirement as
`permissions.filesystem.deny_read` with its source.

## Stack
1. #15979 - glob deny-read policy/config/direct-tool support
2. #18096 - macOS and Linux sandbox enforcement
3. This PR - managed deny-read requirements

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-17 08:40:09 -07:00
viyatb-oaiandGitHub 81c0bcc921 fix: Revert danger-full-access denylist-only mode (#17732)
## Summary

- Reverts openai/codex#16946 and removes the danger-full-access
denylist-only network mode.
- Removes the corresponding config requirements, app-server
protocol/schema, config API, TUI debug output, and network proxy
behavior.
- Drops stale tests that depended on the reverted mode while preserving
newer managed allowlist-only coverage.

## Verification

- `just write-app-server-schema`
- `just fmt`
- `cargo test -p codex-config network_requirements`
- `cargo test -p codex-core network_proxy_spec`
- `cargo test -p codex-core
managed_network_proxy_decider_survives_full_access_start`
- `cargo test -p codex-app-server map_requirements_toml_to_api`
- `cargo test -p codex-tui debug_config_output`
- `cargo test -p codex-app-server-protocol`
- `just fix -p codex-config -p codex-core -p codex-app-server-protocol
-p codex-app-server -p codex-tui`
- `git diff --cached --check`

Not run: full workspace `cargo test` (repo instructions ask for
confirmation before that broader run).
2026-04-14 09:50:14 -07:00
Eric TrautandGitHub 66e13efd9c TUI: enforce core boundary (#17399)
Problem: The TUI still depended on `codex-core` directly in a number of
places, and we had no enforcement from keeping this problem from getting
worse.

Solution: Route TUI core access through
`codex-app-server-client::legacy_core`, add CI enforcement for that
boundary, and re-export this legacy bridge inside the TUI as
`crate::legacy_core` so the remaining call sites stay readable. There is
no functional change in this PR — just changes to import targets.

Over time, we can whittle away at the remaining symbols in this legacy
namespace with the eventual goal of removing them all. In the meantime,
this linter rule will prevent us from inadvertently importing new
symbols from core.
2026-04-10 20:25:31 -07:00
dcbc91fd39 Update guardian output schema (#17061)
## Summary
- Update guardian output schema to separate risk, authorization,
outcome, and rationale.
- Feed guardian rationale into rejection messages.
- Split the guardian policy into template and tenant-config sections.

## Validation
- `cargo test -p codex-core mcp_tool_call`
- `env -u CODEX_SANDBOX_NETWORK_DISABLED INSTA_UPDATE=always cargo test
-p codex-core guardian::`

---------

Co-authored-by: Owen Lin <owen@openai.com>
2026-04-08 15:47:29 -07:00
Owen LinandGitHub e794457a59 fix(debug-config, guardian): fix /debug-config rendering and guardian… (#17138)
## Description

This PR fixes `/debug-config` so it shows more of the active
requirements state, including reviewer requirements and managed feature
pins. This made it clear that legacy MDM config was setting
`approvals_reviewer = "guardian_subagent"` and that we were translating
that into a requirements constraint.

Also, translate `approvals_reviewer = "guardian_subagent"` (from legacy
managed_config.toml) to `allowed_approvals_reviewers: guardian_subagent,
user` instead of `allowed_approvals_reviewers: guardian_subagent`.

Example `/debug-config`:
```
Config layer stack (lowest precedence first):
  1. system (/etc/codex/config.toml) (enabled)
  2. user (/Users/owen/.codex/config.toml) (enabled)
  3. project (/Users/owen/repos/codex/.codex/config.toml) (enabled)
  4. legacy managed_config.toml (MDM) (enabled)
     MDM value:
       ...

       # Enable Guardian Mode
       features.guardian_approval = true
       approvals_reviewer = "guardian_subagent"

Requirements:
  - allowed_approvals_reviewers: guardian_subagent, user (source: MDM managed_config.toml (legacy))
  - features: apps=true, plugins=true (source: cloud requirements)
```

Before this PR, the `Requirements` section showed None.
2026-04-08 11:08:09 -07:00
viyatb-oaiandGitHub 9d13d29acd [codex] Add danger-full-access denylist-only network mode (#16946)
## Summary

This adds `experimental_network.danger_full_access_denylist_only` for
orgs that want yolo / danger-full-access sessions to keep full network
access while still enforcing centrally managed deny rules.

When the flag is true and the session sandbox is `danger-full-access`,
the network proxy starts with:

- domain allowlist set to `*`
- managed domain `deny` entries enforced
- upstream proxy use allowed
- all Unix sockets allowed
- local/private binding allowed

Caveat: the denylist is best effort only. In yolo / danger-full-access
mode, Codex or the model can use an allowed socket or other
local/private network path to bypass the proxy denylist, so this should
not be treated as a hard security boundary.

The flag is intentionally scoped to `SandboxPolicy::DangerFullAccess`.
Read-only and workspace-write modes keep the existing managed/user
allowlist, denylist, Unix socket, and local-binding behavior. This does
not enable the non-loopback proxy listener setting; that still requires
its own explicit config.

This also threads the new field through config requirements parsing,
app-server protocol/schema output, config API mapping, and the TUI debug
config output.

## How to use

Add the flag under `[experimental_network]` in the network policy config
that is delivered to Codex. The setting is not under `[permissions]`.

```toml
[experimental_network]
enabled = true
danger_full_access_denylist_only = true

[experimental_network.domains]
"blocked.example.com" = "deny"
"*.blocked.example.com" = "deny"
```

With that configuration, yolo / danger-full-access sessions get broad
network access except for the managed denied domains above. The denylist
remains a best-effort proxy policy because the session may still use
allowed sockets to bypass it. Other sandbox modes do not get the
wildcard domain allowlist or the socket/local-binding relaxations from
this flag.

## Verification

- `cargo test -p codex-config network_requirements`
- `cargo test -p codex-core network_proxy_spec`
- `cargo test -p codex-app-server map_requirements_toml_to_api`
- `cargo test -p codex-tui debug_config_output`
- `cargo test -p codex-app-server-protocol`
- `just write-app-server-schema`
- `just fmt`
- `just fix -p codex-config -p codex-core -p codex-app-server-protocol
-p codex-app-server -p codex-tui`
- `just fix -p codex-core -p codex-config`
- `git diff --check`
- `cargo clean`
2026-04-06 19:38:51 -07:00
Owen LinandGitHub ded559680d feat(requirements): support allowed_approval_reviewers (#16701)
## Description

Add requirements.toml support for `allowed_approvals_reviewers =
["user", "guardian_subagent"]`, so admins can now restrict the use of
guardian mode.

Note: If a user sets a reviewer that isn’t allowed by requirements.toml,
config loading falls back to the first allowed reviewer and emits a
startup warning.

The table below describes the possible admin controls.
| Admin intent | `requirements.toml` | User `config.toml` | End result |
|---|---|---|---|
| Leave Guardian optional | omit `allowed_approvals_reviewers` or set
`["user", "guardian_subagent"]` | user chooses `approvals_reviewer =
"user"` or `"guardian_subagent"` | Guardian off for `user`, on for
`guardian_subagent` + `approval_policy = "on-request"` |
| Force Guardian off | `allowed_approvals_reviewers = ["user"]` | any
user value | Effective reviewer is `user`; Guardian off |
| Force Guardian on | `allowed_approvals_reviewers =
["guardian_subagent"]` and usually `allowed_approval_policies =
["on-request"]` | any user reviewer value; user should also have
`approval_policy = "on-request"` unless policy is forced | Effective
reviewer is `guardian_subagent`; Guardian on when effective approval
policy is `on-request` |
| Allow both, but default to manual if user does nothing |
`allowed_approvals_reviewers = ["user", "guardian_subagent"]` | omit
`approvals_reviewer` | Effective reviewer is `user`; Guardian off |
| Allow both, and user explicitly opts into Guardian |
`allowed_approvals_reviewers = ["user", "guardian_subagent"]` |
`approvals_reviewer = "guardian_subagent"` and `approval_policy =
"on-request"` | Guardian on |
| Invalid admin config | `allowed_approvals_reviewers = []` | anything |
Config load error |
2026-04-06 11:11:44 -07:00
Eric TrautandGitHub 61429a6c10 Rename tui_app_server to tui (#16104)
This is a follow-up to https://github.com/openai/codex/pull/15922. That
previous PR deleted the old `tui` directory and left the new
`tui_app_server` directory in place. This PR renames `tui_app_server` to
`tui` and fixes up all references.
2026-03-28 11:23:07 -06:00
Eric TrautandGitHub d65deec617 Remove the legacy TUI split (#15922)
This is the part 1 of 2 PRs that will delete the `tui` /
`tui_app_server` split. This part simply deletes the existing `tui`
directory and marks the `tui_app_server` feature flag as removed. I left
the `tui_app_server` feature flag in place for now so its presence
doesn't result in an error. It is simply ignored.

Part 2 will rename the `tui_app_server` directory `tui`. I did this as
two parts to reduce visible code churn.
2026-03-27 22:56:44 +00:00
Celia ChenandGitHub dd30c8eedd chore: refactor network permissions to use explicit domain and unix socket rule maps (#15120)
## Summary

This PR replaces the legacy network allow/deny list model with explicit
rule maps for domains and unix sockets across managed requirements,
permissions profiles, the network proxy config, and the app server
protocol.

Concretely, it:

- introduces typed domain (`allow` / `deny`) and unix socket permission
(`allow` / `none`) entries instead of separate `allowed_domains`,
`denied_domains`, and `allow_unix_sockets` lists
- updates config loading, managed requirements merging, and exec-policy
overlays to read and upsert rule entries consistently
- exposes the new shape through protocol/schema outputs, debug surfaces,
and app-server config APIs
- rejects the legacy list-based keys and updates docs/tests to reflect
the new config format

## Why

The previous representation split related network policy across multiple
parallel lists, which made merging and overriding rules harder to reason
about. Moving to explicit keyed permission maps gives us a single source
of truth per host/socket entry, makes allow/deny precedence clearer, and
gives protocol consumers access to the full rule state instead of
derived projections only.

## Backward Compatibility

### Backward compatible

- Managed requirements still accept the legacy
`experimental_network.allowed_domains`,
`experimental_network.denied_domains`, and
`experimental_network.allow_unix_sockets` fields. They are normalized
into the new canonical `domains` and `unix_sockets` maps internally.
- App-server v2 still deserializes legacy `allowedDomains`,
`deniedDomains`, and `allowUnixSockets` payloads, so older clients can
continue reading managed network requirements.
- App-server v2 responses still populate `allowedDomains`,
`deniedDomains`, and `allowUnixSockets` as legacy compatibility views
derived from the canonical maps.
- `managed_allowed_domains_only` keeps the same behavior after
normalization. Legacy managed allowlists still participate in the same
enforcement path as canonical `domains` entries.

### Not backward compatible

- Permissions profiles under `[permissions.<profile>.network]` no longer
accept the legacy list-based keys. Those configs must use the canonical
`[domains]` and `[unix_sockets]` tables instead of `allowed_domains`,
`denied_domains`, or `allow_unix_sockets`.
- Managed `experimental_network` config cannot mix canonical and legacy
forms in the same block. For example, `domains` cannot be combined with
`allowed_domains` or `denied_domains`, and `unix_sockets` cannot be
combined with `allow_unix_sockets`.
- The canonical format can express explicit `"none"` entries for unix
sockets, but those entries do not round-trip through the legacy
compatibility fields because the legacy fields only represent allow/deny
lists.
## Testing
`/target/debug/codex sandbox macos --log-denials /bin/zsh -c 'curl
https://www.example.com' ` gives 200 with config
```
[permissions.workspace.network.domains]
"www.example.com" = "allow"
```
and fails when set to deny: `curl: (56) CONNECT tunnel failed, response
403`.

Also tested backward compatibility path by verifying that adding the
following to `/etc/codex/requirements.toml` works:
```
[experimental_network]
allowed_domains = ["www.example.com"]
```
2026-03-27 06:17:59 +00:00
226241f035 Use workspace requirements for guardian prompt override (#14727)
## Summary
- move `guardian_developer_instructions` from managed config into
workspace-managed `requirements.toml`
- have guardian continue using the override when present and otherwise
fall back to the bundled local guardian prompt
- keep the generalized prompt-quality improvements in the shared
guardian default prompt
- update requirements parsing, layering, schema, and tests for the new
source of truth

## Context
This replaces the earlier managed-config / MDM rollout plan.

The intended rollout path is workspace-managed requirements, including
cloud enterprise policies, rather than backend model metadata, Statsig,
or Jamf-managed config. That keeps the default/fallback behavior local
to `codex-rs` while allowing faster policy updates through the
enterprise requirements plane.

This is intentionally an admin-managed policy input, not a user
preference: the guardian prompt should come either from the bundled
`codex-rs` default or from enterprise-managed `requirements.toml`, and
normal user/project/session config should not override it.

## Updating The OpenAI Prompt
After this lands, the OpenAI-specific guardian prompt should be updated
through the workspace Policies UI at `/codex/settings/policies` rather
than through Jamf or codex-backend model metadata.

Operationally:
- open the workspace Policies editor as a Codex admin
- edit the default `requirements.toml` policy, or a higher-precedence
group-scoped override if we ever want different behavior for a subset of
users
- set `guardian_developer_instructions = """..."""` to the full
OpenAI-specific guardian prompt text
- save the policy; codex-backend stores the raw TOML and `codex-rs`
fetches the effective requirements file from `/wham/config/requirements`

When updating the OpenAI-specific prompt, keep it aligned with the
shared default guardian policy in `codex-rs` except for intentional
OpenAI-only additions.

## Testing
- `cargo check --tests -p codex-core -p codex-config -p
codex-cloud-requirements --message-format short`
- `cargo run -p codex-core --bin codex-write-config-schema`
- `cargo fmt`
- `git diff --check`

Co-authored-by: Codex <noreply@openai.com>
2026-03-17 22:05:41 -07:00
Michael BolinandGitHub b77fe8fefe 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
2026-03-16 16:48:15 -07:00
canvrno-oaiandGitHub 914f7c7317 Override local apps settings with requirements.toml settings (#14304)
This PR changes app and connector enablement when `requirements.toml` is
present locally or via remote configuration.

For apps.* entries:
- `enabled = false` in `requirements.toml` overrides the user’s local
`config.toml` and forces the app to be disabled.
- `enabled = true` in `requirements.toml` does not re-enable an app the
user has disabled in config.toml.

This behavior applies whether or not the user has an explicit entry for
that app in `config.toml`. It also applies to cloud-managed policies and
configurations when the admin sets the override through
`requirements.toml`.

Scenarios tested and verified:
- Remote managed, user config (present) override
- Admin-defined policies & configurations include a connector override:
  `[apps.<appID>]
enabled = false`
- User's config.toml has the same connector configured with `enabled =
true`
  - TUI/App should show connector as disabled
  - Connector should be unavailable for use in the composer
  
- Remote managed, user config (absent) override
- Admin-defined policies & configurations include a connector override:
  `[apps.<appID>]
enabled = false`
  - User's config.toml has no entry for the the same connector
  - TUI/App should show connector as disabled
  - Connector should be unavailable for use in the composer
  
- Locally managed, user config (present) override
  - Local requirements.toml includes a connector override:
  `[apps.<appID>]
enabled = false`
- User's config.toml has the same connector configured with `enabled =
true`
  - TUI/App should show connector as disabled
  - Connector should be unavailable for use in the composer

- Locally managed, user config (absent) override
  - Local requirements.toml includes a connector override:
  `[apps.<appID>]
enabled = false`
  - User's config.toml has no entry for the the same connector
  - TUI/App should show connector as disabled
  - Connector should be unavailable for use in the composer




<img width="1446" height="753" alt="image"
src="https://github.com/user-attachments/assets/61c714ca-dcca-4952-8ad2-0afc16ff3835"
/>
<img width="595" height="233" alt="image"
src="https://github.com/user-attachments/assets/7c8ab147-8fd7-429a-89fb-591c21c15621"
/>
2026-03-13 12:40:24 -07:00
viyatb-oaiandGitHub 25fa974166 fix: support managed network allowlist controls (#12752)
## Summary
- treat `requirements.toml` `allowed_domains` and `denied_domains` as
managed network baselines for the proxy
- in restricted modes by default, build the effective runtime policy
from the managed baseline plus user-configured allowlist and denylist
entries, so common hosts can be pre-approved without blocking later user
expansion
- add `experimental_network.managed_allowed_domains_only = true` to pin
the effective allowlist to managed entries, ignore user allowlist
additions, and hard-deny non-managed domains without prompting
- apply `managed_allowed_domains_only` anywhere managed network
enforcement is active, including full access, while continuing to
respect denied domains from all sources
- add regression coverage for merged-baseline behavior, managed-only
behavior, and full-access managed-only enforcement

## Behavior
Assuming `requirements.toml` defines both
`experimental_network.allowed_domains` and
`experimental_network.denied_domains`.

### Default mode
- By default, the effective allowlist is
`experimental_network.allowed_domains` plus user or persisted allowlist
additions.
- By default, the effective denylist is
`experimental_network.denied_domains` plus user or persisted denylist
additions.
- Allowlist misses can go through the network approval flow.
- Explicit denylist hits and local or private-network blocks are still
hard-denied.
- When `experimental_network.managed_allowed_domains_only = true`, only
managed `allowed_domains` are respected, user allowlist additions are
ignored, and non-managed domains are hard-denied without prompting.
- Denied domains continue to be respected from all sources.

### Full access
- With managed requirements present, the effective allowlist is pinned
to `experimental_network.allowed_domains`.
- With managed requirements present, the effective denylist is pinned to
`experimental_network.denied_domains`.
- There is no allowlist-miss approval path in full access.
- Explicit denylist hits are hard-denied.
- `experimental_network.managed_allowed_domains_only = true` now also
applies in full access, so managed-only behavior remains in effect
anywhere managed network enforcement is active.
2026-03-06 17:52:54 -08:00
viyatb-oaiandGitHub 6a79ed5920 refactor: remove proxy admin endpoint (#13687)
## Summary
- delete the network proxy admin server and its runtime listener/task
plumbing
- remove the admin endpoint config, runtime, requirement, protocol,
schema, and debug-surface fields
- update proxy docs to reflect the remaining HTTP and SOCKS listeners
only
2026-03-05 22:03:16 -08:00
Michael BolinandGitHub bfff0c729f config: enforce enterprise feature requirements (#13388)
## Why

Enterprises can already constrain approvals, sandboxing, and web search
through `requirements.toml` and MDM, but feature flags were still only
configurable as managed defaults. That meant an enterprise could suggest
feature values, but it could not actually pin them.

This change closes that gap and makes enterprise feature requirements
behave like the other constrained settings. The effective feature set
now stays consistent with enterprise requirements during config load,
when config writes are validated, and when runtime code mutates feature
flags later in the session.

It also tightens the runtime API for managed features. `ManagedFeatures`
now follows the same constraint-oriented shape as `Constrained<T>`
instead of exposing panic-prone mutation helpers, and production code
can no longer construct it through an unconstrained `From<Features>`
path.

The PR also hardens the `compact_resume_fork` integration coverage on
Windows. After the feature-management changes,
`compact_resume_after_second_compaction_preserves_history` was
overflowing the libtest/Tokio thread stacks on Windows, so the test now
uses an explicit larger-stack harness as a pragmatic mitigation. That
may not be the ideal root-cause fix, and it merits a parallel
investigation into whether part of the async future chain should be
boxed to reduce stack pressure instead.

## What Changed

Enterprises can now pin feature values in `requirements.toml` with the
requirements-side `features` table:

```toml
[features]
personality = true
unified_exec = false
```

Only canonical feature keys are allowed in the requirements `features`
table; omitted keys remain unconstrained.

- Added a requirements-side pinned feature map to
`ConfigRequirementsToml`, threaded it through source-preserving
requirements merge and normalization in `codex-config`, and made the
TOML surface use `[features]` (while still accepting legacy
`[feature_requirements]` for compatibility).
- Exposed `featureRequirements` from `configRequirements/read`,
regenerated the JSON/TypeScript schema artifacts, and updated the
app-server README.
- Wrapped the effective feature set in `ManagedFeatures`, backed by
`ConstrainedWithSource<Features>`, and changed its API to mirror
`Constrained<T>`: `can_set(...)`, `set(...) -> ConstraintResult<()>`,
and result-returning `enable` / `disable` / `set_enabled` helpers.
- Removed the legacy-usage and bulk-map passthroughs from
`ManagedFeatures`; callers that need those behaviors now mutate a plain
`Features` value and reapply it through `set(...)`, so the constrained
wrapper remains the enforcement boundary.
- Removed the production loophole for constructing unconstrained
`ManagedFeatures`. Non-test code now creates it through the configured
feature-loading path, and `impl From<Features> for ManagedFeatures` is
restricted to `#[cfg(test)]`.
- Rejected legacy feature aliases in enterprise feature requirements,
and return a load error when a pinned combination cannot survive
dependency normalization.
- Validated config writes against enterprise feature requirements before
persisting changes, including explicit conflicting writes and
profile-specific feature states that normalize into invalid
combinations.
- Updated runtime and TUI feature-toggle paths to use the constrained
setter API and to persist or apply the effective post-constraint value
rather than the requested value.
- Updated the `core_test_support` Bazel target to include the bundled
core model-catalog fixtures in its runtime data, so helper code that
resolves `core/models.json` through runfiles works in remote Bazel test
environments.
- Renamed the core config test coverage to emphasize that effective
feature values are normalized at runtime, while conflicting persisted
config writes are rejected.
- Ran `compact_resume_after_second_compaction_preserves_history` inside
an explicit 8 MiB test thread and Tokio runtime worker stack, following
the existing larger-stack integration-test pattern, to keep the Windows
`compact_resume_fork` test slice from aborting while a parallel
investigation continues into whether some of the underlying async
futures should be boxed.

## Verification

- `cargo test -p codex-config`
- `cargo test -p codex-core feature_requirements_ -- --nocapture`
- `cargo test -p codex-core
load_requirements_toml_produces_expected_constraints -- --nocapture`
- `cargo test -p codex-core
compact_resume_after_second_compaction_preserves_history -- --nocapture`
- `cargo test -p codex-core compact_resume_fork -- --nocapture`
- Re-ran the built `codex-core` `tests/all` binary with
`RUST_MIN_STACK=262144` for
`compact_resume_after_second_compaction_preserves_history` to confirm
the explicit-stack harness fixes the deterministic low-stack repro.
- `cargo test -p codex-core`
- This still fails locally in unrelated integration areas that expect
the `codex` / `test_stdio_server` binaries or hit existing `search_tool`
wiremock mismatches.

## Docs

`developers.openai.com/codex` should document the requirements-side
`[features]` table for enterprise and MDM-managed configuration,
including that it only accepts canonical feature keys and that
conflicting config writes are rejected.
2026-03-04 04:40:22 +00:00
Michael BolinandGitHub 1af2a37ada chore: remove codex-core public protocol/shell re-exports (#12432)
## Why

`codex-rs/core/src/lib.rs` re-exported a broad set of types and modules
from `codex-protocol` and `codex-shell-command`. That made it easy for
workspace crates to import those APIs through `codex-core`, which in
turn hides dependency edges and makes it harder to reduce compile-time
coupling over time.

This change removes those public re-exports so call sites must import
from the source crates directly. Even when a crate still depends on
`codex-core` today, this makes dependency boundaries explicit and
unblocks future work to drop `codex-core` dependencies where possible.

## What Changed

- Removed public re-exports from `codex-rs/core/src/lib.rs` for:
- `codex_protocol::protocol` and related protocol/model types (including
`InitialHistory`)
  - `codex_protocol::config_types` (`protocol_config_types`)
- `codex_shell_command::{bash, is_dangerous_command, is_safe_command,
parse_command, powershell}`
- Migrated workspace Rust call sites to import directly from:
  - `codex_protocol::protocol`
  - `codex_protocol::config_types`
  - `codex_protocol::models`
  - `codex_shell_command`
- Added explicit `Cargo.toml` dependencies (`codex-protocol` /
`codex-shell-command`) in crates that now import those crates directly.
- Kept `codex-core` internal modules compiling by using `pub(crate)`
aliases in `core/src/lib.rs` (internal-only, not part of the public
API).
- Updated the two utility crates that can already drop a `codex-core`
dependency edge entirely:
  - `codex-utils-approval-presets`
  - `codex-utils-cli`

## Verification

- `cargo test -p codex-utils-approval-presets`
- `cargo test -p codex-utils-cli`
- `cargo check --workspace --all-targets`
- `just clippy`
2026-02-20 23:45:35 -08:00
viyatb-oaiGitHubCodex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
28c0089060 fix(network-proxy): add unix socket allow-all and update seatbelt rules (#11368)
## Summary
Adds support for a Unix socket escape hatch so we can bypass socket
allowlisting when explicitly enabled.

## Description
* added a new flag, `network.dangerously_allow_all_unix_sockets` as an
explicit escape hatch
* In codex-network-proxy, enabling that flag now allows any absolute
Unix socket path from x-unix-socket instead of requiring each path to be
explicitly allowlisted. Relative paths are still rejected.
* updated the macOS seatbelt path in core so it enforces the same Unix
socket behavior:
  * allowlisted sockets generate explicit network* subpath rules
  * allow-all generates a broad network* (subpath "/") rule

---------

Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
2026-02-20 10:56:57 -08:00
Michael BolinandGitHub a4cc1a4a85 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`
2026-02-12 14:42:54 -08:00
Michael BolinandGitHub abbd74e2be feat: make sandbox read access configurable with ReadOnlyAccess (#11387)
`SandboxPolicy::ReadOnly` previously implied broad read access and could
not express a narrower read surface.
This change introduces an explicit read-access model so we can support
user-configurable read restrictions in follow-up work, while preserving
current behavior today.

It also ensures unsupported backends fail closed for restricted-read
policies instead of silently granting broader access than intended.

## What

- Added `ReadOnlyAccess` in protocol with:
  - `Restricted { include_platform_defaults, readable_roots }`
  - `FullAccess`
- Updated `SandboxPolicy` to carry read-access configuration:
  - `ReadOnly { access: ReadOnlyAccess }`
  - `WorkspaceWrite { ..., read_only_access: ReadOnlyAccess }`
- Preserved existing behavior by defaulting current construction paths
to `ReadOnlyAccess::FullAccess`.
- Threaded the new fields through sandbox policy consumers and call
sites across `core`, `tui`, `linux-sandbox`, `windows-sandbox`, and
related tests.
- Updated Seatbelt policy generation to honor restricted read roots by
emitting scoped read rules when full read access is not granted.
- Added fail-closed behavior on Linux and Windows backends when
restricted read access is requested but not yet implemented there
(`UnsupportedOperation`).
- Regenerated app-server protocol schema and TypeScript artifacts,
including `ReadOnlyAccess`.

## Compatibility / rollout

- Runtime behavior remains unchanged by default (`FullAccess`).
- API/schema changes are in place so future config wiring can enable
restricted read access without another policy-shape migration.
2026-02-11 18:31:14 -08:00
Michael BolinandGitHub 577a416f9a Extract codex-config from codex-core (#11389)
`codex-core` had accumulated config loading, requirements parsing,
constraint logic, and config-layer state handling in a single crate.
This change extracts that subsystem into `codex-config` to reduce
`codex-core` rebuild/test surface area and isolate future config work.

## What Changed

### Added `codex-config`

- Added new workspace crate `codex-rs/config` (`codex-config`).
- Added workspace/build wiring in:
  - `codex-rs/Cargo.toml`
  - `codex-rs/config/Cargo.toml`
  - `codex-rs/config/BUILD.bazel`
- Updated lockfiles (`codex-rs/Cargo.lock`, `MODULE.bazel.lock`).
- Added `codex-core` -> `codex-config` dependency in
`codex-rs/core/Cargo.toml`.

### Moved config internals from `core` into `config`

Moved modules to `codex-rs/config/src/`:

- `core/src/config/constraint.rs` -> `config/src/constraint.rs`
- `core/src/config_loader/cloud_requirements.rs` ->
`config/src/cloud_requirements.rs`
- `core/src/config_loader/config_requirements.rs` ->
`config/src/config_requirements.rs`
- `core/src/config_loader/fingerprint.rs` -> `config/src/fingerprint.rs`
- `core/src/config_loader/merge.rs` -> `config/src/merge.rs`
- `core/src/config_loader/overrides.rs` -> `config/src/overrides.rs`
- `core/src/config_loader/requirements_exec_policy.rs` ->
`config/src/requirements_exec_policy.rs`
- `core/src/config_loader/state.rs` -> `config/src/state.rs`

`codex-config` now re-exports this surface from `config/src/lib.rs` at
the crate top level.

### Updated `core` to consume/re-export `codex-config`

- `core/src/config_loader/mod.rs` now imports/re-exports config-loader
types/functions from top-level `codex_config::*`.
- Local moved modules were removed from `core/src/config_loader/`.
- `core/src/config/mod.rs` now re-exports constraint types from
`codex_config`.
2026-02-11 10:02:49 -08:00
Michael BolinandGitHub f6dd9e37e7 tui: show non-file layer content in /debug-config (#11412)
The debug output listed non-file-backed layers such as session flags and
MDM managed config, but it did not show their values. That made it
difficult to explain unexpected effective settings because users could
not inspect those layers on disk.

Now `/debug-config` might include output like this:

```
Config layer stack (lowest precedence first):
  1. system (/etc/codex/config.toml) (enabled)
  2. user (/Users/mbolin/.codex/config.toml) (enabled)
  3. legacy managed_config.toml (mdm) (enabled)
     MDM value:
       # Production Codex configuration file.

       [otel]
       log_user_prompt = true
       environment = "prod"
       exporter = { otlp-http = {
         endpoint = "https://example.com/otel",
         protocol = "binary"
       }}
```
2026-02-11 06:23:08 +00:00
viyatb-oaiandGitHub 1d47927aa0 Enable SOCKS defaults for common local network proxy use cases (#11362)
## Summary
- enable local-use defaults in network proxy settings: SOCKS5 on, SOCKS5
UDP on, upstream proxying on, and local binding on
- add a regression test that asserts the full
`NetworkProxySettings::default()` baseline
- Fixed managed listener reservation behavior.
Before: we always reserved a loopback SOCKS listener, even when
enable_socks5 = false.
Now: SOCKS listener is only reserved when SOCKS is enabled.
- Fixed /debug-config env output for SOCKS-disabled sessions.
ALL_PROXY now shows the HTTP proxy URL when SOCKS is disabled (instead
of incorrectly showing socks5h://...).


## Validation
- just fmt
- cargo test -p codex-network-proxy
- cargo clippy -p codex-network-proxy --all-targets
2026-02-10 15:13:52 -08:00
Michael BolinandGitHub 44ebf4588f feat: retain NetworkProxy, when appropriate (#11207)
As of this PR, `SessionServices` retains a
`Option<StartedNetworkProxy>`, if appropriate.

Now the `network` field on `Config` is `Option<NetworkProxySpec>`
instead of `Option<NetworkProxy>`.

Over in `Session::new()`, we invoke `NetworkProxySpec::start_proxy()` to
create the `StartedNetworkProxy`, which is a new struct that retains the
`NetworkProxy` as well as the `NetworkProxyHandle`. (Note that `Drop` is
implemented for `NetworkProxyHandle` to ensure the proxies are shutdown
when it is dropped.)

The `NetworkProxy` from the `StartedNetworkProxy` is threaded through to
the appropriate places.


---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/11207).
* #11285
* __->__ #11207
2026-02-10 02:09:23 -08:00
gt-oaiandGitHub 9fe925b15a Load requirements on windows (#10770)
We support requirements on Unix, loading from
`/etc/codex/requirements.toml`. On MacOS, we also support MDM.

Now, on Windows, we'll load requirements from
`%ProgramData%\OpenAI\Codex\requirements.toml`
2026-02-09 16:05:38 +00:00