From c93a7ca6db5c0d2710e23cdcaa958b2d4ac4b42a Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Thu, 9 Jul 2026 10:50:01 -0700 Subject: [PATCH] app-server-daemon: route updater download through HTTP client factory --- codex-rs/Cargo.lock | 2 +- codex-rs/app-server-daemon/Cargo.toml | 2 +- codex-rs/app-server-daemon/src/lib.rs | 6 +++-- codex-rs/app-server-daemon/src/update_loop.rs | 26 ++++++++++++++----- codex-rs/cli/src/main.rs | 10 ++++++- codex-rs/deny.toml | 1 - 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 01b99bc363..620cdcc075 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2092,12 +2092,12 @@ dependencies = [ "anyhow", "codex-app-server-protocol", "codex-app-server-transport", + "codex-http-client", "codex-uds", "codex-utils-home-dir", "futures", "libc", "pretty_assertions", - "reqwest 0.12.28", "serde", "serde_json", "sha2 0.10.9", diff --git a/codex-rs/app-server-daemon/Cargo.toml b/codex-rs/app-server-daemon/Cargo.toml index 24531b4c74..fee5732197 100644 --- a/codex-rs/app-server-daemon/Cargo.toml +++ b/codex-rs/app-server-daemon/Cargo.toml @@ -16,11 +16,11 @@ workspace = true anyhow = { workspace = true } codex-app-server-protocol = { workspace = true } codex-app-server-transport = { workspace = true } +codex-http-client = { workspace = true } codex-utils-home-dir = { workspace = true } codex-uds = { workspace = true } futures = { workspace = true } libc = { workspace = true } -reqwest = { workspace = true, features = ["rustls-tls"] } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } sha2 = { workspace = true } diff --git a/codex-rs/app-server-daemon/src/lib.rs b/codex-rs/app-server-daemon/src/lib.rs index 5870075fea..92e69c7b61 100644 --- a/codex-rs/app-server-daemon/src/lib.rs +++ b/codex-rs/app-server-daemon/src/lib.rs @@ -238,9 +238,11 @@ pub async fn set_remote_control(mode: RemoteControlMode) -> Result Result<()> { +pub async fn run_pid_update_loop( + http_client_factory: codex_http_client::HttpClientFactory, +) -> Result<()> { ensure_supported_platform()?; - update_loop::run().await + update_loop::run(http_client_factory).await } #[cfg(unix)] diff --git a/codex-rs/app-server-daemon/src/update_loop.rs b/codex-rs/app-server-daemon/src/update_loop.rs index 0fe21e0a6d..4bac4713d1 100644 --- a/codex-rs/app-server-daemon/src/update_loop.rs +++ b/codex-rs/app-server-daemon/src/update_loop.rs @@ -11,6 +11,11 @@ use anyhow::Result; #[cfg(not(unix))] use anyhow::bail; #[cfg(unix)] +use codex_http_client::ClientRouteClass; +use codex_http_client::HttpClientFactory; +#[cfg(unix)] +use codex_http_client::RouteAwareClientPool; +#[cfg(unix)] use futures::FutureExt; #[cfg(unix)] use std::os::unix::process::CommandExt; @@ -48,17 +53,20 @@ const INITIAL_UPDATE_DELAY: Duration = Duration::from_secs(5 * 60); const RESTART_RETRY_INTERVAL: Duration = Duration::from_millis(50); #[cfg(unix)] const UPDATE_INTERVAL: Duration = Duration::from_secs(60 * 60); +#[cfg(unix)] +const INSTALL_URL: &str = "https://chatgpt.com/codex/install.sh"; #[cfg(unix)] -pub(crate) async fn run() -> Result<()> { +pub(crate) async fn run(http_client_factory: HttpClientFactory) -> Result<()> { let mut terminate = signal(SignalKind::terminate()).context("failed to install updater shutdown handler")?; let running_updater_identity = current_updater_identity().await?; + let http = RouteAwareClientPool::new(http_client_factory, ClientRouteClass::Other); if sleep_or_terminate(INITIAL_UPDATE_DELAY, &mut terminate).await { return Ok(()); } loop { - match update_once(&running_updater_identity, &mut terminate).await { + match update_once(&http, &running_updater_identity, &mut terminate).await { Ok(UpdateLoopControl::Continue) | Err(_) => {} Ok(UpdateLoopControl::Stop) => return Ok(()), } @@ -69,7 +77,7 @@ pub(crate) async fn run() -> Result<()> { } #[cfg(not(unix))] -pub(crate) async fn run() -> Result<()> { +pub(crate) async fn run(_http_client_factory: HttpClientFactory) -> Result<()> { bail!("pid-managed updater loop is unsupported on this platform") } @@ -89,10 +97,11 @@ enum UpdateLoopControl { #[cfg(unix)] async fn update_once( + http: &RouteAwareClientPool, running_updater_identity: &ExecutableIdentity, terminate: &mut Signal, ) -> Result { - install_latest_standalone().await?; + install_latest_standalone(http).await?; let daemon = Daemon::from_environment()?; let managed_codex_bin = resolved_managed_codex_bin(&daemon.managed_codex_bin).await?; @@ -154,8 +163,13 @@ pub(crate) fn reexec_managed_updater(managed_codex_bin: &std::path::Path) -> Res } #[cfg(unix)] -async fn install_latest_standalone() -> Result<()> { - let script = reqwest::get("https://chatgpt.com/codex/install.sh") +async fn install_latest_standalone(http: &RouteAwareClientPool) -> Result<()> { + let script = http + .client_for_url(INSTALL_URL) + .await + .context("failed to configure standalone Codex updater client")? + .get(INSTALL_URL) + .send() .await .context("failed to fetch standalone Codex updater")? .error_for_status() diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 04d59c24ab..9b9bd22c62 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -1182,7 +1182,15 @@ async fn cli_main( print_app_server_daemon_output(AppServerLifecycleCommand::Version).await?; } AppServerDaemonSubcommand::PidUpdateLoop => { - codex_app_server_daemon::run_pid_update_loop().await?; + let cli_overrides = root_config_overrides + .parse_overrides() + .map_err(anyhow::Error::msg)?; + let config = ConfigBuilder::default() + .cli_overrides(cli_overrides) + .build() + .await?; + codex_app_server_daemon::run_pid_update_loop(config.http_client_factory()) + .await?; } }, Some(AppServerSubcommand::Proxy(proxy_cli)) => { diff --git a/codex-rs/deny.toml b/codex-rs/deny.toml index 293960d4ec..f4f60f0a83 100644 --- a/codex-rs/deny.toml +++ b/codex-rs/deny.toml @@ -242,7 +242,6 @@ deny = [ "codex-agent-identity", "codex-api", "codex-app-server", - "codex-app-server-daemon", "codex-core", "codex-core-plugins", "codex-exec-server",