mirror of
https://github.com/openai/codex.git
synced 2026-10-20 00:18:49 +00:00
Propagate resolved proxy policy through auth routing (#34649)
## Why Auth routing represented the default proxy policy as an absent configuration, leaving consumers to reconstruct the fallback HTTP client independently. Carry the application's resolved policy explicitly so auth and related requests use the same client configuration. ## What changed - Build `AuthRouteConfig` from the resolved `HttpClientFactory` for both `ReqwestDefault` and `RespectSystemProxy` policies. - Pass that route configuration through login, auth, cloud task, and cloud configuration flows, and reuse its factory when loading cloud configuration. - Log cloud-task configuration load failures before falling back to the transport-default proxy policy. ## Testing Extended configuration tests to verify that effective and bootstrap auth routes select the expected proxy policy when system-proxy support is enabled or disabled by feature requirements. GitOrigin-RevId: d03802e2660f5cf6d940e8e718ec5c82ede7eab1
This commit is contained in:
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -610,7 +610,7 @@ pub(crate) async fn load_cli_auth_mode(config: &Config) -> Option<AuthMode> {
|
||||
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()
|
||||
|
||||
@@ -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<AuthRouteConfig>,
|
||||
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(
|
||||
|
||||
@@ -58,11 +58,12 @@ async fn init_backend(user_agent_suffix: &str) -> anyhow::Result<BackendContext>
|
||||
|
||||
#[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,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -47,11 +47,15 @@ pub async fn load_auth_manager(
|
||||
chatgpt_base_url: Option<String>,
|
||||
) -> (Option<AuthManager>, 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)
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1251,7 +1251,7 @@ impl AuthManagerConfig for Config {
|
||||
}
|
||||
|
||||
fn auth_route_config(&self) -> Option<AuthRouteConfig> {
|
||||
Config::auth_route_config(self)
|
||||
Some(Config::auth_route_config(self))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,9 +1514,9 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auth_route_config(&self) -> Option<AuthRouteConfig> {
|
||||
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<FeatureRequirementsToml>>,
|
||||
) -> std::io::Result<Option<AuthRouteConfig>> {
|
||||
resolve_bootstrap_respect_system_proxy(cfg, feature_requirements)
|
||||
.map(|enabled| enabled.then(AuthRouteConfig::respect_system_proxy))
|
||||
) -> std::io::Result<AuthRouteConfig> {
|
||||
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(
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user