## Why
Login already honors `respect_system_proxy`, but several login-owned
auth flows still construct and pass around raw `reqwest::Client` values.
That keeps those request paths coupled to the underlying transport and
leaves `codex-login` on the temporary direct-`reqwest` allowlist
introduced by #31431.
Auth endpoints also have a stricter logging boundary than ordinary API
requests: custom issuer URLs and response headers may contain
credentials. Moving these requests behind the shared HTTP abstraction
must preserve that boundary while retaining route-aware proxy and
custom-CA behavior.
This is a bounded login migration. The separate Agent Identity and
shared default-client compatibility migrations remain follow-up work.
## What changed
- Add `HttpClientFactory::build_client` to construct the shared
`HttpClient` abstraction for a resolved destination and route class.
- Add a route-aware construction path that suppresses request URL,
response-header, and transport-error diagnostics for sensitive auth
endpoints.
- Route device-code user-code/polling requests, OAuth authorization-code
exchange, and API-key token exchange through `HttpClient`.
- Build the revoke timeout test client through the same factory API.
- Use the transport-neutral `http::StatusCode` in the migrated
device-code flow.
- Add an end-to-end log-capture regression test covering successful
responses and transport failures after `RequestBuilder` transformations.
## Review guidance
The request behavior is intended to be unchanged: each issuer/token
endpoint selects the same auth route, including the existing system/PAC
proxy and custom-CA handling, and raw auth clients still omit Codex
default headers. The intentional logging change is limited to raw auth
requests, whose URL userinfo, query credentials, response headers, and
transport errors must not cross the auth redaction boundary.
This PR deliberately does **not** remove `codex-login` from #31431's
allowlist. The remaining direct `reqwest` surface belongs primarily to:
- Agent Identity APIs that still accept `reqwest::Client`.
- Exported default-client compatibility helpers used by other workspace
crates.
- A small number of tests and concrete error/header types.
## Testing
- `cargo check -p codex-http-client -p codex-login --tests`
- `just test -p codex-http-client` (41 tests)
- `just test -p codex-login` (155 tests)
- `just bazel-lock-check`
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/31637).
* #31837
* #31828
* #31825
* #31821
* __->__ #31637
## Why
#31335 lets HTTP callers obtain proxy-aware clients from
`HttpClientFactory`, but a non-HTTP transport such as WebSockets also
needs two pieces of policy owned by `codex-http-client`: a concrete
route decision for its destination and the same custom-CA-aware rustls
trust configuration used by HTTPS.
Keeping these prerequisites in the shared abstraction means the
dependent Responses WebSocket change (#31441) cannot independently
reinterpret `features.respect_system_proxy`, PAC results, or enterprise
CA settings.
## What changed
- Add a redaction-safe `OutboundProxyRoute` with explicit
transport-default, direct, and concrete-proxy outcomes.
- Add `HttpClientFactory::resolve_proxy_route()` so transports can
resolve a destination through the already-selected outbound proxy
policy.
- Resolve `ws://` and `wss://` URLs through their HTTP equivalents so
system and PAC rules apply consistently.
- Add an always-returned rustls config builder that starts from native
roots and layers in any configured Codex custom CA bundle. The existing
optional builder remains available to callers that can delegate the
default configuration to their transport.
- Continue redacting proxy URLs from `Debug` output because they may
contain credentials.
## Review guide
1. `http-client/src/outbound_proxy.rs` defines the transport-neutral
route result and WebSocket URL normalization.
2. `http-client/src/custom_ca.rs` factors the native-root/custom-CA
construction so callers that perform TLS themselves can always obtain a
config.
3. `http-client/src/outbound_proxy_tests.rs` verifies WebSocket
normalization and legacy transport-default behavior.
## Test plan
- `just test -p codex-http-client outbound_proxy`
- `just test -p codex-http-client custom_ca`
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/31342).
* #31431
* #31363
* #31362
* #31361
* #31442
* #31441
* __->__ #31342
## Why
`features.respect_system_proxy` already routes authentication traffic
through the OS proxy APIs, but it does not affect the primary inference
path. That leaves users behind OS-managed proxies unable to send normal
Responses API requests even after login succeeds.
This PR is the first product-path migration onto the route-aware
transport introduced in #31323 and refined in #31331. It also
establishes the construction pattern for later migrations: the effective
feature state is resolved once into a required HTTP client factory
rather than represented by an optional per-call setting.
The scope remains limited to the two HTTP Responses endpoints;
WebSockets, model discovery, memories, realtime, and file uploads remain
follow-up migrations.
## What changed
- Replace the optional proxy marker with an explicit
`OutboundProxyPolicy::{ReqwestDefault, RespectSystemProxy}` and a
required `HttpClientFactory`. The policy has no default, and the
lower-level route-aware reqwest builder is now private.
- Have `Config` construct the factory from the effective feature state
and require every `ModelClient` constructor to receive it. There is no
optional setter or implicit `None` fallback.
- Build HTTP clients for `/responses` and `/responses/compact` with
`ClientRouteClass::Api`, using the complete destination URL so PAC rules
can make URL-specific decisions.
- Layer route-aware selection onto Codex's existing default headers,
Cloudflare cookie store, custom CA handling, and sandbox no-proxy
behavior.
- Add an integration test that loads `features.respect_system_proxy`
through `config.toml`, creates a real Codex session, and verifies that
both a normal Responses turn and remote compaction reach an isolated
local proxy.
## Review guide
1. `http-client/src/outbound_proxy.rs` defines the mandatory
policy/factory boundary and keeps route resolution private.
2. `core/src/config/mod.rs`, `core/src/session/session.rs`, and
`core/src/client.rs` show the compile-time invariant: effective config
creates the factory, and `ModelClient` cannot be constructed without
one.
3. `login/src/auth/default_client.rs` preserves existing default-client
behavior while accepting the required factory for migrated routes.
4. `core/src/client.rs` switches only streaming Responses and remote
compaction HTTP transports to the API route class.
5. `core/tests/suite/responses_api_system_proxy.rs` is the behavioral
regression boundary. Its Linux subprocess deliberately sets the CGI
marker that disables reqwest's implicit environment-proxy handling, so
the test fails if session wiring or either Responses call site falls
back to the default client.
## Test plan
- `cargo check --tests -p codex-http-client -p codex-login -p
codex-core`
- `just test -p codex-login`
- `just test -p codex-core
respect_system_proxy_feature_resolves_enabled`
- Existing `compact_uses_bearer_after_agent_identity_session_fallback`
coverage passes with the new transport construction.
- New Linux integration coverage:
`responses_and_compact_use_enabled_system_proxy`
- `just bazel-lock-check`
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/31335).
* #31342
* __->__ #31335
## Why
Codex-owned HTTP construction currently lives in `codex-client`
alongside higher-level retry, SSE, and request-telemetry policy. That
makes it difficult to apply shared network behavior consistently across
crates, particularly system proxy/PAC resolution, custom CA handling,
and the ChatGPT Cloudflare cookie policy. It also leaves no clear crate
boundary for migrating direct `reqwest` usage behind a single Codex
abstraction.
This change establishes that low-level ownership boundary without
changing request behavior. It builds on the system proxy support
introduced in #26706, #26707, #26708, and #26709.
## What changed
- Added `codex-rs/http-client` as the `codex-http-client` crate.
- Moved request/response types, the concrete `reqwest` transport, custom
CA handling, Cloudflare cookie policy, and macOS/Windows proxy
resolution into the new crate.
- Kept retry, SSE, and request-telemetry policy in `codex-client`.
- Re-exported the moved API from `codex-client`, including compatibility
aliases for `CodexHttpClient` and `CodexRequestBuilder`, so existing
consumers do not change in this PR.
- Moved the existing proxy and custom-CA tests with their
implementation.
## Scope boundary
This PR deliberately stops at the crate extraction. Stacked follow-up
#31331 migrates downstream imports from `codex-client` to
`codex-http-client`, keeping this change focused on ownership and
compatibility rather than mixing in repository-wide call-site churn.
## Review guide
GitHub reports 30 changed files, of which 17 are detected renames. A
useful review order is:
1. Review the new boundary in `codex-rs/http-client/Cargo.toml` and
`codex-rs/http-client/src/lib.rs`.
2. Review `codex-rs/codex-client/Cargo.toml` and
`codex-rs/codex-client/src/lib.rs` for what remains in the higher-level
crate and how compatibility is preserved.
3. Treat the renamed implementation and test files as moves. Their
meaningful edits are limited to crate paths and normalizing the new
crate's type names to `HttpClient` and `RequestBuilder`.
4. Review `codex-rs/Cargo.toml`, `codex-rs/Cargo.lock`, and the two
`BUILD.bazel` files as mechanical workspace integration.
## Test plan
- `just test -p codex-http-client -p codex-client` (38 tests)
- Compile-checked the unchanged `codex-api`, `codex-backend-client`,
`codex-cloud-tasks`, `codex-exec-server`, `codex-login`, and
`codex-model-provider` consumers against the compatibility re-exports.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/31323).
* #31331
* __->__ #31323