Commit Graph
1370 Commits
Author SHA1 Message Date
Charles CunninghamandCodex 96fe896919 codex: fix CI failure on PR #14170
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 7250e82a9b tui: preserve world-writable warning opt-out
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex d8c0839fc2 tui: reject unavailable queued slash drafts
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex efa6715884 tui: cfg-gate realtime settings draft helper
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 93ead12235 tui: block queued replay behind open popups
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 2268f98488 tui: clean up slash help footer hints
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex e477780626 tui: clear slash help search before closing
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 541bc6ef34 tui: let shift-n go backward in slash help search
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 56c7646161 tui: shorten slash help close hint
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 0727144012 tui: space slash help footer
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 6e20c5af8c tui: refine slash help search controls
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 77e1e8029a tui: add slash help search and status
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 8fbc9d32fd tui: let q dismiss slash help
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:51 -07:00
Charles CunninghamandCodex 528e3df3f6 tui: let slash help grow with terminal
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 6a278e943f tui: make slash help dismissible
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 8fda4e0fc2 tui: add slash command help page
Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex ad586ba24c tui: share slash command shlex codec
Centralize slash command draft serialization on top of shlex so popup flows and queued replay use the same quoting and tokenization rules.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 7ea03de12b tui: resume queued replay after idle slash actions
Pause queued replay on local slash actions that need app-side updates or popup dismissal, then resume once the app event queue and bottom pane are idle. Add regression coverage for queued theme replay and popup-gated resume.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex bcb3555e70 tui: reject repeated model modifiers
Track whether /model effort and scope modifiers were provided so repeated sentinel values like default and global are rejected consistently.

Validation: cargo test -p codex-tui; just fix -p codex-tui; just fmt

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 8c45c1acfc tui: canonicalize interactive slash drafts
Route interactive slash-command pickers through canonical serialized drafts so live dispatch and queued replay share one parser/executor path.

Validation: cargo test -p codex-tui; just fix -p codex-tui; just fmt

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 217da0c113 tui: make slash command helpers exhaustive
Switch supports_inline_args() and requires_interaction() to exhaustive matches so newly added SlashCommand variants must be classified explicitly.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex bb3e61843a tui: clarify queue replay stop comment
Explain that the busy-path Stop return in dispatch_command() only matters for live dispatch because queued replay never reaches that branch.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 173d0ef4e3 tui: resolve interactive slash commands before queueing
Mark popup-opening slash commands as requiring interaction, open them immediately instead of queueing bare drafts while a task is running, and make queued replay restore any legacy bare interactive command draft instead of opening UI mid-drain.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 8267155494 tui: document slash dispatch replay contract
Explain above dispatch_command that live callers usually ignore its return value while queued replay uses QueueReplayControl to decide whether draining can continue.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex 393740dbed tui: clarify live slash queueing branch
Document that the busy-path queueing in dispatch_command is only reached during live slash dispatch, not queued replay, so the returned drain-control value is effectively a throwaway for that branch.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:50 -07:00
Charles CunninghamandCodex ed546bc217 tui: preserve queued slash draft intent
Serialize custom /review instructions with an explicit custom marker so queued replay cannot reinterpret branch-like text as a structured review target, and rename queued replay to better reflect that it drains inputs until blocked.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex 122e1475d5 tui: simplify interrupt status plumbing
Send interrupt ops directly from the bottom pane instead of routing them through the status indicator widget, and remove the now-unused event wiring from the widget and its tests.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex fa50564579 tui: restore interactive slash queue behavior
Keep bare /model and /review interactive while preserving serialized queue replay, restore queued slash drafts into the composer on interrupt, and align queued slash parsing with the same feature-gated lookup used by the composer.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex 35e8aa9ce0 Simplify queued slash command replay
Unify queued slash commands as serialized drafts, route popup actions through the same replay path, and stop replay after commands that submit a turn.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex 9ab49d2c37 narrow esc interrupts in tui
Limit Esc interrupts to an empty composer when no popup is active, while preserving the pending-steer interrupt path.

This keeps dialog dismissal on Esc working normally without interrupting the running conversation.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex e5f1b8435d queue interactive slash command selections
Keep interactive slash flows usable while a turn is running, and queue the resulting action instead of the bare slash token.

Also let Esc interrupt through popup-active states so queued drafts restore without dropping queued slash actions.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex a8f1f43c1f preserve queued slash actions on interrupt
Restore only queued user-message drafts into the composer when a turn is interrupted, keep queued slash-command actions replayable, and cover the interrupt replay behavior in codex-tui tests.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex 072d5d9e49 remove dead tui helper methods
Drop the unused bottom-pane mention-binding drain helpers introduced by the queueing refactor and switch the affected tests to the existing non-destructive composer mention accessor.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Charles CunninghamandCodex 9478b34e55 queue slash commands in tui
Allow slash commands entered during a running turn to be queued and replayed after the turn completes, including /review and inline slash-command variants tested in codex-tui.

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 23:32:49 -07:00
Matthew Zeng 029aab5563 fix(core): preserve tool_params for elicitations (#14769)
- [x] Preserve tool_params keys.
2026-03-15 23:15:52 -07:00
Charley CunninghamandCodex 6fdeb1d602 Reuse guardian session across approvals (#14668)
## Summary
- reuse a guardian subagent session across approvals so reviews keep a
stable prompt cache key and avoid one-shot startup overhead
- clear the guardian child history before each review so prior guardian
decisions do not leak into later approvals
- include the `smart_approvals` -> `guardian_approval` feature flag
rename in the same PR to minimize release latency on a very tight
timeline
- add regression coverage for prompt-cache-key reuse without
prior-review prompt bleed

## Request
- Bug/enhancement request: internal guardian prompt-cache and latency
improvement request

---------

Co-authored-by: Codex <noreply@openai.com>
2026-03-15 22:56:18 -07:00
friel-openai ba463a9dc7 Preserve background terminals on interrupt and rename cleanup command to /stop (#14602)
### Motivation
- Interrupting a running turn (Ctrl+C / Esc) currently also terminates
long‑running background shells, which is surprising for workflows like
local dev servers or file watchers.
- The existing cleanup command name was confusing; callers expect an
explicit command to stop background terminals rather than a UI clear
action.
- Make background‑shell termination explicit and surface a clearer
command name while preserving backward compatibility.

### Description
- Renamed the background‑terminal cleanup slash command from `Clean`
(`/clean`) to `Stop` (`/stop`) and kept `clean` as an alias in the
command parsing/visibility layer, updated the user descriptions and
command popup wiring accordingly.
- Updated the unified‑exec footer text and snapshots to point to `/stop`
(and trimmed corresponding snapshot output to match the new label).
- Changed interrupt behavior so `Op::Interrupt` (Ctrl+C / Esc interrupt)
no longer closes or clears tracked unified exec / background terminal
processes in the TUI or core cleanup path; background shells are now
preserved after an interrupt.
- Updated protocol/docs to clarify that `turn/interrupt` (or
`Op::Interrupt`) interrupts the active turn but does not terminate
background terminals, and that `thread/backgroundTerminals/clean` is the
explicit API to stop those shells.
- Updated unit/integration tests and insta snapshots in the TUI and core
unified‑exec suites to reflect the new semantics and command name.

### Testing
- Ran formatting with `just fmt` in `codex-rs` (succeeded). 
- Ran `cargo test -p codex-protocol` (succeeded). 
- Attempted `cargo test -p codex-tui` but the build could not complete
in this environment due to a native build dependency that requires
`libcap` development headers (the `codex-linux-sandbox` vendored build
step); install `libcap-dev` / make `libcap.pc` available in
`PKG_CONFIG_PATH` to run the TUI test suite locally.
- Updated and accepted the affected `insta` snapshots for the TUI
changes so visual diffs reflect the new `/stop` wording and preserved
interrupt behavior.

------
[Codex
Task](https://chatgpt.com/codex/tasks/task_i_69b39c44b6dc8323bd133ae206310fae)
2026-03-15 22:17:25 -07:00
69c8a1ef9e Fix Windows CI assertions for guardian and Smart Approvals (#14645)
- Normalize guardian assessment path serialization to use forward
slashes for cross-platform stability.
- Seed workspace-write defaults in the Smart Approvals
override-turn-context test so Windows and non-Windows selection flows
are consistent.

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Charles Cunningham <ccunningham@openai.com>
2026-03-14 02:15:58 +00:00
Eric Traut 4b9d5c8c1b Add openai_base_url config override for built-in provider (#12031)
We regularly get bug reports from users who mistakenly have the
`OPENAI_BASE_URL` environment variable set. This PR deprecates this
environment variable in favor of a top-level config key
`openai_base_url` that is used for the same purpose. By making it a
config key, it will be more visible to users. It will also participate
in all of the infrastructure we've added for layered and managed
configs.

Summary
- introduce the `openai_base_url` top-level config key, update
schema/tests, and route the built-in openai provider through it while
- fall back to deprecated `OPENAI_BASE_URL` env var but warn user of
deprecation when no `openai_base_url` config key is present
- update CLI, SDK, and TUI code to prefer the new config path (with a
deprecated env-var fallback) and document the SDK behavior change
2026-03-13 20:12:25 -06:00
Charley CunninghamandCodex bc24017d64 Add Smart Approvals guardian review across core, app-server, and TUI (#13860)
## Summary
- add `approvals_reviewer = "user" | "guardian_subagent"` as the runtime
control for who reviews approval requests
- route Smart Approvals guardian review through core for command
execution, file changes, managed-network approvals, MCP approvals, and
delegated/subagent approval flows
- expose guardian review in app-server with temporary unstable
`item/autoApprovalReview/{started,completed}` notifications carrying
`targetItemId`, `review`, and `action`
- update the TUI so Smart Approvals can be enabled from `/experimental`,
aligned with the matching `/approvals` mode, and surfaced clearly while
reviews are pending or resolved

## Runtime model
This PR does not introduce a new `approval_policy`.

Instead:
- `approval_policy` still controls when approval is needed
- `approvals_reviewer` controls who reviewable approval requests are
routed to:
  - `user`
  - `guardian_subagent`

`guardian_subagent` is a carefully prompted reviewer subagent that
gathers relevant context and applies a risk-based decision framework
before approving or denying the request.

The `smart_approvals` feature flag is a rollout/UI gate. Core runtime
behavior keys off `approvals_reviewer`.

When Smart Approvals is enabled from the TUI, it also switches the
current `/approvals` settings to the matching Smart Approvals mode so
users immediately see guardian review in the active thread:
- `approval_policy = on-request`
- `approvals_reviewer = guardian_subagent`
- `sandbox_mode = workspace-write`

Users can still change `/approvals` afterward.

Config-load behavior stays intentionally narrow:
- plain `smart_approvals = true` in `config.toml` remains just the
rollout/UI gate and does not auto-set `approvals_reviewer`
- the deprecated `guardian_approval = true` alias migration does
backfill `approvals_reviewer = "guardian_subagent"` in the same scope
when that reviewer is not already configured there, so old configs
preserve their original guardian-enabled behavior

ARC remains a separate safety check. For MCP tool approvals, ARC
escalations now flow into the configured reviewer instead of always
bypassing guardian and forcing manual review.

## Config stability
The runtime reviewer override is stable, but the config-backed
app-server protocol shape is still settling.

- `thread/start`, `thread/resume`, and `turn/start` keep stable
`approvalsReviewer` overrides
- the config-backed `approvals_reviewer` exposure returned via
`config/read` (including profile-level config) is now marked
`[UNSTABLE]` / experimental in the app-server protocol until we are more
confident in that config surface

## App-server surface
This PR intentionally keeps the guardian app-server shape narrow and
temporary.

It adds generic unstable lifecycle notifications:
- `item/autoApprovalReview/started`
- `item/autoApprovalReview/completed`

with payloads of the form:
- `{ threadId, turnId, targetItemId, review, action? }`

`review` is currently:
- `{ status, riskScore?, riskLevel?, rationale? }`
- where `status` is one of `inProgress`, `approved`, `denied`, or
`aborted`

`action` carries the guardian action summary payload from core when
available. This lets clients render temporary standalone pending-review
UI, including parallel reviews, even when the underlying tool item has
not been emitted yet.

These notifications are explicitly documented as `[UNSTABLE]` and
expected to change soon.

This PR does **not** persist guardian review state onto `thread/read`
tool items. The intended follow-up is to attach guardian review state to
the reviewed tool item lifecycle instead, which would improve
consistency with manual approvals and allow thread history / reconnect
flows to replay guardian review state directly.

## TUI behavior
- `/experimental` exposes the rollout gate as `Smart Approvals`
- enabling it in the TUI enables the feature and switches the current
session to the matching Smart Approvals `/approvals` mode
- disabling it in the TUI clears the persisted `approvals_reviewer`
override when appropriate and returns the session to default manual
review when the effective reviewer changes
- `/approvals` still exposes the reviewer choice directly
- the TUI renders:
- pending guardian review state in the live status footer, including
parallel review aggregation
  - resolved approval/denial state in history

## Scope notes
This PR includes the supporting core/runtime work needed to make Smart
Approvals usable end-to-end:
- shell / unified-exec / apply_patch / managed-network / MCP guardian
review
- delegated/subagent approval routing into guardian review
- guardian review risk metadata and action summaries for app-server/TUI
- config/profile/TUI handling for `smart_approvals`, `guardian_approval`
alias migration, and `approvals_reviewer`
- a small internal cleanup of delegated approval forwarding to dedupe
fallback paths and simplify guardian-vs-parent approval waiting (no
intended behavior change)

Out of scope for this PR:
- redesigning the existing manual approval protocol shapes
- persisting guardian review state onto app-server `ThreadItem`s
- delegated MCP elicitation auto-review (the current delegated MCP
guardian shim only covers the legacy `RequestUserInput` path)

---------

Co-authored-by: Codex <noreply@openai.com>
2026-03-13 15:27:00 -07:00
Ahmed IbrahimandCodex 36dfb84427 Stabilize multi-agent feature flag (#14622)
- make multi_agent stable and enabled by default
- update feature and tool-spec coverage to match the new default

---------

Co-authored-by: Codex <noreply@openai.com>
2026-03-13 14:38:15 -07:00
Won Park 6720caf778 Slash copy osc52 wsl support (#13201)
This PR is a followup to the /copy feature to support WSL and SSH!
2026-03-13 14:00:58 -07:00
canvrno-oai 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
Ahmed IbrahimandCodex d58620c852 Use subagents naming in the TUI (#14618)
- rename user-facing TUI multi-agent wording to subagents
- rename the surfaced slash command to `subagents` and update
tests/snapshots

Co-authored-by: Codex <noreply@openai.com>
2026-03-13 19:08:38 +00:00
Eric Traut 9dba7337f2 Start TUI on embedded app server (#14512)
This PR is part of the effort to move the TUI on top of the app server.
In a previous PR, we introduced an in-process app server and moved
`exec` on top of it.

For the TUI, we want to do the migration in stages. The app server
doesn't currently expose all of the functionality required by the TUI,
so we're going to need to support a hybrid approach as we make the
transition.

This PR changes the TUI initialization to instantiate an in-process app
server and access its `AuthManager` and `ThreadManager` rather than
constructing its own copies. It also adds a placeholder TUI event
handler that will eventually translate app server events into TUI
events. App server notifications are accepted but ignored for now. It
also adds proper shutdown of the app server when the TUI terminates.
2026-03-13 12:04:41 -06:00
Celia Chen 0c60eea4a5 feat: support skill-scoped managed network domain overrides in skill config (#14522)
## Summary

This lets skill loading split `permissions.network` into two distinct
pieces:

- `permissions.network.enabled` still feeds the skill
`PermissionProfile` and remains the coarse gate for whether the skill
can use network access at all.
- `permissions.network.allowed_domains` and
`permissions.network.denied_domains` are lifted into a new
`SkillManagedNetworkOverride` so managed-network sessions can start
per-skill scoped proxies with the right domain overrides.

The change also updates `SkillMetadata` construction sites and adds
loader tests covering YAML parsing plus normalization of the network
gate vs. domain override fields.

## Follow-up
A PR that uses the network_override to spin up a skill-specific proxy if
network_override is not none.
2026-03-13 04:45:14 +00:00
Jack Mousseau 7c7e267501 Simplify permissions available in request permissions tool (#14529) 2026-03-12 21:13:17 -07:00
6912da84a8 client: extend custom CA handling across HTTPS and websocket clients (#14239)
## Stacked PRs

This work is now effectively split across two steps:

- #14178: add custom CA support for browser and device-code login flows,
docs, and hermetic subprocess tests
- #14239: extend that shared custom CA handling across Codex HTTPS
clients and secure websocket TLS

Note: #14240 was merged into this branch while it was stacked on top of
this PR. This PR now subsumes that websocket follow-up and should be
treated as the combined change.

Builds on top of #14178.

## Problem

Custom CA support landed first in the login path, but the real
requirement is broader. Codex constructs outbound TLS clients in
multiple places, and both HTTPS and secure websocket paths can fail
behind enterprise TLS interception if they do not honor
`CODEX_CA_CERTIFICATE` or `SSL_CERT_FILE` consistently.

This PR broadens the shared custom-CA logic beyond login and applies the
same policy to websocket TLS, so the enterprise-proxy story is no longer
split between “HTTPS works” and “websockets still fail”.

## What This Delivers

Custom CA support is no longer limited to login. Codex outbound HTTPS
clients and secure websocket connections can now honor the same
`CODEX_CA_CERTIFICATE` / `SSL_CERT_FILE` configuration, so enterprise
proxy/intercept setups work more consistently end-to-end.

For users and operators, nothing new needs to be configured beyond the
same CA env vars introduced in #14178. The change is that more of Codex
now respects them, including websocket-backed flows that were previously
still using default trust roots.

I also manually validated the proxy path locally with mitmproxy using:
`CODEX_CA_CERTIFICATE=~/.mitmproxy/mitmproxy-ca-cert.pem
HTTPS_PROXY=http://127.0.0.1:8080 just codex`
with mitmproxy installed via `brew install mitmproxy` and configured as
the macOS system proxy.

## Mental model

`codex-client` is now the owner of shared custom-CA policy for outbound
TLS client construction. Reqwest callers start from the builder
configuration they already need, then pass that builder through
`build_reqwest_client_with_custom_ca(...)`. Websocket callers ask the
same module for a rustls client config when a custom CA bundle is
configured.

The env precedence is the same everywhere:
- `CODEX_CA_CERTIFICATE` wins
- otherwise fall back to `SSL_CERT_FILE`
- otherwise use system roots

The helper is intentionally narrow. It loads every usable certificate
from the configured PEM bundle into the appropriate root store and
returns either a configured transport or a typed error that explains
what went wrong.

## Non-goals

This does not add handshake-level integration tests against a live TLS
endpoint. It does not validate that the configured bundle forms a
meaningful certificate chain. It also does not try to force every
transport in the repo through one abstraction; it extends the shared CA
policy across the reqwest and websocket paths that actually needed it.

## Tradeoffs

The main tradeoff is centralizing CA behavior in `codex-client` while
still leaving adoption up to call sites. That keeps the implementation
additive and reviewable, but it means the rule "outbound Codex TLS that
should honor enterprise roots must use the shared helper" is still
partly enforced socially rather than by types.

For websockets, the shared helper only builds an explicit rustls config
when a custom CA bundle is configured. When no override env var is set,
websocket callers still use their ordinary default connector path.

## Architecture

`codex-client::custom_ca` now owns CA bundle selection, PEM
normalization, mixed-section parsing, certificate extraction, typed
CA-loading errors, and optional rustls client-config construction for
websocket TLS.

The affected consumers now call into that shared helper directly rather
than carrying login-local CA behavior:
- backend-client
- cloud-tasks
- RMCP client paths that use `reqwest`
- TUI voice HTTP paths
- `codex-core` default reqwest client construction
- `codex-api` websocket clients for both responses and realtime
websocket connections

The subprocess CA probe, env-sensitive integration tests, and shared PEM
fixtures also live in `codex-client`, which is now the actual owner of
the behavior they exercise.

## Observability

The shared CA path logs:
- which environment variable selected the bundle
- which path was loaded
- how many certificates were accepted
- when `TRUSTED CERTIFICATE` labels were normalized
- when CRLs were ignored
- where client construction failed

Returned errors remain user-facing and include the relevant env var,
path, and remediation hint. That same error model now applies whether
the failure surfaced while building a reqwest client or websocket TLS
configuration.

## Tests

Pure unit tests in `codex-client` cover env precedence and PEM
normalization behavior. Real client construction remains in subprocess
tests so the suite can control process env and avoid the macOS seatbelt
panic path that motivated the hermetic test split.

The subprocess coverage verifies:
- `CODEX_CA_CERTIFICATE` precedence over `SSL_CERT_FILE`
- fallback to `SSL_CERT_FILE`
- single-cert and multi-cert bundles
- malformed and empty-file errors
- OpenSSL `TRUSTED CERTIFICATE` handling
- CRL tolerance for well-formed CRL sections

The websocket side is covered by the existing `codex-api` / `codex-core`
websocket test suites plus the manual mitmproxy validation above.

---------

Co-authored-by: Ivan Zakharchanka <3axap4eHko@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
2026-03-13 00:59:26 +00:00
Eric Traut 7f2ca502f5 Updated out-of-date tip about availability on free and go plans (#14471)
This addresses #14464
2026-03-12 09:12:38 -06:00
Matthew Zeng 23e55d7668 [elicitation] User-friendly tool call messages. (#14403)
- [x] Add a curated set of tool call messages and human-readable tool
param names.
2026-03-12 00:35:21 -07:00