Skip to content

core: preserve Responses WebSockets with system proxy#31441

Merged
bolinfest merged 1 commit into
mainfrom
pr31441
Jul 8, 2026
Merged

core: preserve Responses WebSockets with system proxy#31441
bolinfest merged 1 commit into
mainfrom
pr31441

Conversation

@bolinfest

@bolinfest bolinfest commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Why

Responses WebSockets are the normal lower-latency transport for WebSocket-capable providers. They must not bypass an OS-selected proxy when features.respect_system_proxy is enabled, but disabling WebSockets whenever the feature is enabled would impose a substantial performance penalty.

Merged PR #31622 introduced the reusable proxy-aware WebSocket transport. This PR makes the Responses API its first consumer so the existing fast path uses the same effective proxy and trust policy as HTTP.

What changed

  • Register codex-websocket-client as a workspace dependency and use it from codex-api.
  • Feed the shared crate’s route-independent WebSocketConnection into the existing Responses message pump.
  • Require a configured HttpClientFactory for normal Responses WebSocket connections and the CLI doctor probe, so neither path can open a connection without consulting the effective proxy policy.
  • Pass the session factory from core and the effective configuration factory from doctor.
  • Add an end-to-end Responses test that enables RespectSystemProxy, asserts the resolved policy, completes a turn over WebSocket, and verifies the connection and request counts.
  • Keep the existing Responses protocol handling, ping/pong pump, and session-scoped HTTP fallback unchanged.

The DNS, proxy, TLS, custom-CA, and Happy Eyeballs implementation and its transport tests live in merged PR #31622. This PR deliberately contains only the Responses integration and does not duplicate that transport code.

Review guide

  1. codex-rs/codex-api/src/endpoint/responses_websocket.rs constructs the shared connector and adapts its uniform stream to the existing pump.
  2. codex-rs/core/src/client.rs supplies the session-scoped factory for production Responses connections.
  3. codex-rs/cli/src/doctor.rs supplies the effective configuration factory to the handshake probe.
  4. codex-rs/core/tests/suite/client_websockets.rs covers the enabled-feature path end to end.

Test plan

  • cargo check --tests -p codex-api -p codex-core -p codex-cli
  • just test -p codex-api
  • just test -p codex-core responses_websocket_streams_with_system_proxy_feature
  • cargo shear
  • just bazel-lock-check

Stack created with Sapling. Best reviewed with ReviewStack.

@bolinfest bolinfest changed the base branch from main to pr31342 July 7, 2026 17:35
bolinfest added a commit that referenced this pull request Jul 7, 2026
## 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
Base automatically changed from pr31342 to main July 7, 2026 22:37
bolinfest added a commit that referenced this pull request Jul 8, 2026
## Why

The route-aware WebSocket connection setup in #31441 is transport
infrastructure rather than Responses API protocol logic. Landing it
first in a dedicated crate keeps `codex-api` focused on request and
response behavior and makes the transport reusable by future WebSocket
clients.

WebSockets must also apply the same effective outbound proxy and
custom-CA policy as HTTP without disabling the lower-latency WebSocket
path. Requiring an `HttpClientFactory` when constructing the connector
makes proxy-policy resolution part of the API instead of an optional
call-site convention.

This PR is an independent prerequisite based directly on `main`. After
it merges, #31441 can rebase onto it and replace its in-crate connector
with this API.

## What changed

- Add a new `codex-websocket-client` workspace crate with a
`WebSocketConnector` constructed from the effective `HttpClientFactory`.
- Resolve every destination through that factory before connecting, then
support direct connections, transport-default routing, HTTP proxies, and
TLS-encrypted HTTPS proxies.
- Preserve custom-CA trust for proxy and target TLS handshakes and
preserve Happy Eyeballs fallback for explicit direct and proxy routes.
- Expose an established `WebSocketConnection` as a uniform `Stream` and
`Sink`, hiding route-specific transport types from protocol clients.
- Add focused integration-style coverage for the public connector and
message stream, real WSS over direct and CONNECT routes, implicit and
explicit HTTPS proxy ports, and stalled-address-family fallback.

## Review guide

1. `codex-rs/websocket-client/src/lib.rs` defines the small public API
and the factory-required policy invariant.
2. `codex-rs/websocket-client/src/dialer.rs` contains DNS, TCP, proxy
tunneling, TLS, and WebSocket handshake setup.
3. `codex-rs/websocket-client/src/dialer_tests.rs` verifies the public
stream, direct and proxied WSS paths, HTTPS port preservation, and Happy
Eyeballs timing.
4. There is intentionally no consumer migration here; #31441 will become
the first consumer after this prerequisite merges.

## Test plan

- `cargo check -p codex-websocket-client --tests`
- `just test -p codex-websocket-client`
- `cargo shear`
- `just bazel-lock-check`
@bolinfest bolinfest marked this pull request as ready for review July 8, 2026 20:15
@bolinfest bolinfest requested a review from a team as a code owner July 8, 2026 20:15
@bolinfest bolinfest requested a review from viyatb-oai July 8, 2026 20:18
@bolinfest bolinfest merged commit e621d7d into main Jul 8, 2026
82 of 111 checks passed
@bolinfest bolinfest deleted the pr31441 branch July 8, 2026 21:06
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants