diff --git a/codex-rs/app-server/src/request_processors/account_processor.rs b/codex-rs/app-server/src/request_processors/account_processor.rs index e22cfc4c10..eb1ce2b9ba 100644 --- a/codex-rs/app-server/src/request_processors/account_processor.rs +++ b/codex-rs/app-server/src/request_processors/account_processor.rs @@ -464,7 +464,7 @@ impl AccountRequestProcessor { config.forced_chatgpt_workspace_id.clone(), config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - config.auth_route_config(), + Some(config.auth_route_config()), ) }; #[cfg(debug_assertions)] diff --git a/codex-rs/cli/src/login.rs b/codex-rs/cli/src/login.rs index 98d56bec12..33640dcb95 100644 --- a/codex-rs/cli/src/login.rs +++ b/codex-rs/cli/src/login.rs @@ -180,7 +180,7 @@ pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) -> forced_chatgpt_workspace_id, config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - config.auth_route_config(), + Some(config.auth_route_config()), ) .await { @@ -246,7 +246,7 @@ pub async fn run_login_with_access_token( config.forced_chatgpt_workspace_id.as_deref(), Some(&config.chatgpt_base_url), config.auth_keyring_backend_kind(), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await { @@ -320,7 +320,7 @@ pub async fn run_login_with_device_code( &config.codex_home, config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await; let forced_chatgpt_workspace_id = config.forced_chatgpt_workspace_id.clone(); @@ -330,7 +330,7 @@ pub async fn run_login_with_device_code( forced_chatgpt_workspace_id, config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - auth_route_config, + Some(auth_route_config), ); if let Some(iss) = issuer_base_url { opts.issuer = iss; @@ -368,7 +368,7 @@ pub async fn run_login_with_device_code_fallback_to_browser( &config.codex_home, config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await; @@ -379,7 +379,7 @@ pub async fn run_login_with_device_code_fallback_to_browser( forced_chatgpt_workspace_id, config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - auth_route_config, + Some(auth_route_config), ); if let Some(iss) = issuer_base_url { opts.issuer = iss; @@ -430,7 +430,7 @@ pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! { config.cli_auth_credentials_store_mode, Some(&config.chatgpt_base_url), config.auth_keyring_backend_kind(), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await { @@ -484,7 +484,7 @@ pub async fn run_logout(cli_config_overrides: CliConfigOverrides) -> ! { &config.codex_home, config.cli_auth_credentials_store_mode, config.auth_keyring_backend_kind(), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await { diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 20244f896e..f59c3b1041 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -1756,7 +1756,7 @@ async fn load_exec_server_remote_auth_provider( let auth = CodexAuth::from_agent_identity_jwt( &agent_identity_jwt, Some(&config.chatgpt_base_url), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await?; return Ok(codex_model_provider::auth_provider_from_auth(&auth)); diff --git a/codex-rs/cli/src/plugin_cmd.rs b/codex-rs/cli/src/plugin_cmd.rs index 056c256b39..6fec1f67ed 100644 --- a/codex-rs/cli/src/plugin_cmd.rs +++ b/codex-rs/cli/src/plugin_cmd.rs @@ -610,7 +610,7 @@ pub(crate) async fn load_cli_auth_mode(config: &Config) -> Option { config.cli_auth_credentials_store_mode, Some(&config.chatgpt_base_url), config.auth_keyring_backend_kind(), - auth_route_config.as_ref(), + Some(&auth_route_config), ) .await .ok() diff --git a/codex-rs/cloud-config/src/bundle_loader.rs b/codex-rs/cloud-config/src/bundle_loader.rs index 8201630669..43870f2bd6 100644 --- a/codex-rs/cloud-config/src/bundle_loader.rs +++ b/codex-rs/cloud-config/src/bundle_loader.rs @@ -6,7 +6,6 @@ use codex_config::CloudConfigBundleLoadErrorCode; use codex_config::CloudConfigBundleLoader; use codex_config::types::AuthCredentialsStoreMode; use codex_http_client::HttpClientFactory; -use codex_http_client::OutboundProxyPolicy; use codex_login::AuthKeyringBackendKind; use codex_login::AuthManager; use codex_login::AuthRouteConfig; @@ -65,12 +64,9 @@ pub async fn cloud_config_bundle_loader_for_storage( credentials_store_mode: AuthCredentialsStoreMode, keyring_backend_kind: AuthKeyringBackendKind, chatgpt_base_url: String, - auth_route_config: Option, + auth_route_config: AuthRouteConfig, ) -> CloudConfigBundleLoader { - let http_client_factory = match auth_route_config.as_ref() { - Some(config) => config.http_client_factory().clone(), - None => HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), - }; + let http_client_factory = auth_route_config.http_client_factory().clone(); let auth_manager = AuthManager::shared( codex_home.clone(), enable_codex_api_key_env, @@ -78,7 +74,7 @@ pub async fn cloud_config_bundle_loader_for_storage( /*forced_chatgpt_workspace_id*/ None, Some(chatgpt_base_url.clone()), keyring_backend_kind, - auth_route_config, + Some(auth_route_config), ) .await; cloud_config_bundle_loader( diff --git a/codex-rs/cloud-tasks/src/lib.rs b/codex-rs/cloud-tasks/src/lib.rs index 0697506702..fa3fde91f0 100644 --- a/codex-rs/cloud-tasks/src/lib.rs +++ b/codex-rs/cloud-tasks/src/lib.rs @@ -58,11 +58,12 @@ async fn init_backend(user_agent_suffix: &str) -> anyhow::Result #[cfg(debug_assertions)] if use_mock { + let http_client_factory = HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault); return Ok(BackendContext { backend: Arc::new(codex_cloud_tasks_mock_client::MockClient), base_url, environment_http: RouteAwareClientPool::new_without_request_logging( - HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), + http_client_factory, ClientRouteClass::Api, ), }); diff --git a/codex-rs/cloud-tasks/src/util.rs b/codex-rs/cloud-tasks/src/util.rs index aff4cfe552..f2c676ab16 100644 --- a/codex-rs/cloud-tasks/src/util.rs +++ b/codex-rs/cloud-tasks/src/util.rs @@ -47,11 +47,15 @@ pub async fn load_auth_manager( chatgpt_base_url: Option, ) -> (Option, HttpClientFactory) { // TODO: pass in cli overrides once cloud tasks properly support them. - let Some(config) = Config::load_with_cli_overrides(Vec::new()).await.ok() else { - return ( - None, - HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), - ); + let config = match Config::load_with_cli_overrides(Vec::new()).await { + Ok(config) => config, + Err(error) => { + append_error_log(format!( + "failed to load auth config; using transport-default proxy handling: {error}" + )); + let http_client_factory = HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault); + return (None, http_client_factory); + } }; let http_client_factory = config.http_client_factory(); let auth_manager = AuthManager::new( @@ -61,7 +65,7 @@ pub async fn load_auth_manager( config.forced_chatgpt_workspace_id.clone(), chatgpt_base_url.or(Some(config.chatgpt_base_url.clone())), config.auth_keyring_backend_kind(), - config.auth_route_config(), + Some(config.auth_route_config()), ) .await; (Some(auth_manager), http_client_factory) diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index b4a2d1b30f..78a4a71ef5 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -1712,6 +1712,13 @@ respect_system_proxy = true config.http_client_factory().outbound_proxy_policy(), codex_http_client::OutboundProxyPolicy::RespectSystemProxy ); + assert_eq!( + config + .auth_route_config() + .http_client_factory() + .outbound_proxy_policy(), + codex_http_client::OutboundProxyPolicy::RespectSystemProxy + ); assert_eq!( config.plugins_config_input().remote_plugin_service_config(), codex_core_plugins::remote::RemotePluginServiceConfig::new( @@ -1747,6 +1754,12 @@ respect_system_proxy = true &configured, Some(&disabled) )?); + assert_eq!( + resolve_bootstrap_auth_route_config(&configured, Some(&disabled))? + .http_client_factory() + .outbound_proxy_policy(), + codex_http_client::OutboundProxyPolicy::ReqwestDefault + ); let configured = ConfigToml::default(); let enabled = Sourced::new( @@ -1759,6 +1772,12 @@ respect_system_proxy = true &configured, Some(&enabled) )?); + assert_eq!( + resolve_bootstrap_auth_route_config(&configured, Some(&enabled))? + .http_client_factory() + .outbound_proxy_policy(), + codex_http_client::OutboundProxyPolicy::RespectSystemProxy + ); Ok(()) } diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 715a52fb11..23234a23b5 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -1251,7 +1251,7 @@ impl AuthManagerConfig for Config { } fn auth_route_config(&self) -> Option { - Config::auth_route_config(self) + Some(Config::auth_route_config(self)) } } @@ -1514,9 +1514,9 @@ impl Config { } } - pub fn auth_route_config(&self) -> Option { - self.respect_system_proxy - .then(AuthRouteConfig::respect_system_proxy) + /// Returns auth routing resolved from the effective feature configuration. + pub fn auth_route_config(&self) -> AuthRouteConfig { + AuthRouteConfig::from_http_client_factory(self.http_client_factory()) } /// Creates the HTTP client factory resolved from the effective feature configuration. @@ -2899,9 +2899,15 @@ pub fn resolve_bootstrap_respect_system_proxy( pub fn resolve_bootstrap_auth_route_config( cfg: &ConfigToml, feature_requirements: Option<&Sourced>, -) -> std::io::Result> { - resolve_bootstrap_respect_system_proxy(cfg, feature_requirements) - .map(|enabled| enabled.then(AuthRouteConfig::respect_system_proxy)) +) -> std::io::Result { + resolve_bootstrap_respect_system_proxy(cfg, feature_requirements).map(|respect_system_proxy| { + let outbound_proxy_policy = if respect_system_proxy { + OutboundProxyPolicy::RespectSystemProxy + } else { + OutboundProxyPolicy::ReqwestDefault + }; + AuthRouteConfig::from_http_client_factory(HttpClientFactory::new(outbound_proxy_policy)) + }) } pub(crate) fn resolve_web_search_mode_for_turn( diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 368bcf64a4..2d277b45e8 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -491,7 +491,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result forced_login_method: config.forced_login_method, forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(), chatgpt_base_url: Some(config.chatgpt_base_url.clone()), - auth_route_config, + auth_route_config: Some(auth_route_config), }) .await { diff --git a/codex-rs/login/src/outbound_proxy.rs b/codex-rs/login/src/outbound_proxy.rs index c1fd6f9465..84dfccf989 100644 --- a/codex-rs/login/src/outbound_proxy.rs +++ b/codex-rs/login/src/outbound_proxy.rs @@ -1,5 +1,4 @@ use codex_http_client::HttpClientFactory; -use codex_http_client::OutboundProxyPolicy; /// Auth-layer adapter around client-owned proxy policy. /// @@ -11,9 +10,10 @@ pub struct AuthRouteConfig { } impl AuthRouteConfig { - pub fn respect_system_proxy() -> Self { + /// Adapts an application-resolved HTTP client factory for auth requests. + pub fn from_http_client_factory(http_client_factory: HttpClientFactory) -> Self { Self { - http_client_factory: HttpClientFactory::new(OutboundProxyPolicy::RespectSystemProxy), + http_client_factory, } } diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index c22a38fc9a..f2e770e4d4 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -1197,7 +1197,7 @@ pub async fn run_main( forced_login_method: config.forced_login_method, forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(), chatgpt_base_url: Some(config.chatgpt_base_url.clone()), - auth_route_config, + auth_route_config: Some(auth_route_config), }) .await { diff --git a/codex-rs/tui/src/onboarding/auth.rs b/codex-rs/tui/src/onboarding/auth.rs index 619163bc66..609b52b260 100644 --- a/codex-rs/tui/src/onboarding/auth.rs +++ b/codex-rs/tui/src/onboarding/auth.rs @@ -1040,6 +1040,7 @@ mod tests { .build() .await .unwrap(); + let auth_route_config = config.auth_route_config(); let client = InProcessAppServerClient::start(InProcessClientStartArgs { arg0_paths: Arg0DispatchPaths::default(), config: Arc::new(config), @@ -1052,7 +1053,7 @@ mod tests { AuthCredentialsStoreMode::File, AuthKeyringBackendKind::default(), "https://chatgpt.com/backend-api/".to_string(), - /*auth_route_config*/ None, + auth_route_config, ) .await, feedback: codex_feedback::CodexFeedback::new(),