Support gRPC code-mode hosts in app server (#38288)

## What changed

- Accept root `http://` and `https://` URLs in `--code-mode-host` and use the
  shared gRPC session provider for those endpoints.
- Keep `ws://` and `wss://` URLs on the existing WebSocket transport.
- Reject paths, queries, fragments, and credentials where unsupported, without
  exposing gRPC URL credentials in command-line validation errors.

## Testing

- Cover argument parsing and transport selection for both remote protocols.
- Exercise a gRPC host shared across app-server threads and verify credential
  rejection does not disclose usernames or passwords.

GitOrigin-RevId: b6516a85cf76db5c4cea620f89ef866d8af30cf0
This commit is contained in:
Channing Conger authored and copyberry committed 2026-08-13 01:32:42 +00:00
1 parent e766f75989
commit 5104cb649e
9 files changed
+216 -26

No files matched your search

@@ -26,24 +26,33 @@ const DEFAULT_READ_TIMEOUT: Duration = Duration::from_secs(/*secs*/ 10);
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn app_server_shares_flag_selected_code_mode_host_across_threads() -> Result<()> {
assert_shared_remote_code_mode_host("ws://127.0.0.1:0").await
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn app_server_shares_flag_selected_grpc_code_mode_host_across_threads() -> Result<()> {
assert_shared_remote_code_mode_host("grpc://127.0.0.1:0").await
}
async fn assert_shared_remote_code_mode_host(listen_url: &str) -> Result<()> {
let host_program = codex_utils_cargo_bin::cargo_bin("codex-code-mode-host")?;
let mut websocket_host = Command::new(host_program)
.args(["--listen", "ws://127.0.0.1:0"])
let mut code_mode_host = Command::new(host_program)
.args(["--listen", listen_url])
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.kill_on_drop(true)
.spawn()
.context("failed to start websocket code-mode host")?;
let stdout = websocket_host
.context("failed to start remote code-mode host")?;
let stdout = code_mode_host
.stdout
.take()
.context("websocket code-mode host stdout was not captured")?;
.context("remote code-mode host stdout was not captured")?;
let mut lines = BufReader::new(stdout).lines();
let websocket_url = timeout(DEFAULT_READ_TIMEOUT, lines.next_line())
let host_url = timeout(DEFAULT_READ_TIMEOUT, lines.next_line())
.await
.context("timed out waiting for websocket code-mode host URL")??
.context("websocket code-mode host exited before publishing its URL")?;
.context("timed out waiting for remote code-mode host URL")??
.context("remote code-mode host exited before publishing its URL")?;
let model_server = responses::start_mock_server().await;
let response_mock = responses::mount_sse_sequence(
@@ -86,7 +95,7 @@ async fn app_server_shares_flag_selected_code_mode_host_across_threads() -> Resu
let original_config = std::fs::read_to_string(codex_home.path().join("config.toml"))?;
let mut app_server = TestAppServer::builder()
.with_codex_home(codex_home.path())
.with_args(&["--code-mode-host", &websocket_url])
.with_args(&["--code-mode-host", &host_url])
.build_initialized_with_timeout(DEFAULT_READ_TIMEOUT)
.await?;