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
2026-08-13 01:32:42 +00:00
committed by copyberry
parent e766f75989
commit 5104cb649e
9 changed files with 216 additions and 26 deletions
+28 -1
View File
@@ -4070,18 +4070,45 @@ mod tests {
);
}
#[test]
fn app_server_grpc_code_mode_host_url_parses_independently_of_listen_transport() {
let app_server = app_server_from_args(
[
"codex",
"app-server",
"--code-mode-host",
"https://example.test",
"--listen",
"ws://127.0.0.1:4500",
]
.as_ref(),
);
assert_eq!(
app_server.code_mode_host.code_mode_host,
Some(url::Url::parse("https://example.test").expect("test endpoint should parse"))
);
}
#[test]
fn app_server_rejects_invalid_code_mode_host_urls() {
for endpoint in [
"http://127.0.0.1:8765",
"ftp://127.0.0.1:8765",
"ws://",
"wss://example.test/code-mode#fragment",
"https://example.test/code-mode",
"http://alice:secret@example.test",
"https://alice:secret@example.test",
"http://example.test/?token=secret",
] {
let error =
MultitoolCli::try_parse_from(["codex", "app-server", "--code-mode-host", endpoint])
.expect_err("invalid code-mode host endpoint should fail argument parsing");
assert_eq!(error.kind(), clap::error::ErrorKind::ValueValidation);
let rendered_error = error.to_string();
assert!(!rendered_error.contains("alice"));
assert!(!rendered_error.contains("secret"));
}
}