From 5f1fab0e7c2c2ecbd3a50d2aeb164b3862dd03ff Mon Sep 17 00:00:00 2001 From: kinopeee <119112484+kinopeee@users.noreply.github.com> Date: Mon, 10 Nov 2025 09:35:08 +0900 Subject: [PATCH] fix(cloud-tasks): respect cli_auth_credentials_store config (#5856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem `codex cloud` always instantiated `AuthManager` with `File` mode, ignoring the user's actual `cli_auth_credentials_store` setting. This caused users with `cli_auth_credentials_store = "keyring"` (or `"auto"`) to see "Not signed in" errors even when they had valid credentials stored in the system keyring. ## Root cause The code called `Config::load_from_base_config_with_overrides()` with an empty `ConfigToml::default()`, which always returned `File` as the default store mode instead of loading the actual user configuration. ## Solution - **Added `util::load_cli_auth_manager()` helper** Properly loads user config via `load_config_as_toml_with_cli_overrides()` and extracts the `cli_auth_credentials_store` setting before creating `AuthManager`. - **Updated callers** - `init_backend()` - used when starting cloud tasks UI - `build_chatgpt_headers()` - used for API requests ## Testing - ✅ `just fmt` - ✅ `just fix -p codex-cloud-tasks` - ✅ `cargo test -p codex-cloud-tasks` ## Files changed - `codex-rs/cloud-tasks/src/lib.rs` - `codex-rs/cloud-tasks/src/util.rs` ## Verification Users with keyring-based auth can now run `codex cloud` successfully without "Not signed in" errors. --------- Co-authored-by: Eric Traut Co-authored-by: celia-oai --- codex-rs/cloud-tasks/src/lib.rs | 17 ++-------- codex-rs/cloud-tasks/src/util.rs | 55 ++++++++++++++++++-------------- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/codex-rs/cloud-tasks/src/lib.rs b/codex-rs/cloud-tasks/src/lib.rs index 8f8b3066..7954da5e 100644 --- a/codex-rs/cloud-tasks/src/lib.rs +++ b/codex-rs/cloud-tasks/src/lib.rs @@ -8,6 +8,7 @@ pub mod util; pub use cli::Cli; use anyhow::anyhow; +use codex_login::AuthManager; use std::io::IsTerminal; use std::io::Read; use std::path::PathBuf; @@ -56,20 +57,8 @@ async fn init_backend(user_agent_suffix: &str) -> anyhow::Result }; append_error_log(format!("startup: base_url={base_url} path_style={style}")); - let auth = match codex_core::config::find_codex_home() - .ok() - .map(|home| { - let store_mode = codex_core::config::Config::load_from_base_config_with_overrides( - codex_core::config::ConfigToml::default(), - codex_core::config::ConfigOverrides::default(), - home.clone(), - ) - .map(|cfg| cfg.cli_auth_credentials_store_mode) - .unwrap_or_default(); - codex_login::AuthManager::new(home, false, store_mode) - }) - .and_then(|am| am.auth()) - { + let auth_manager = util::load_auth_manager().await; + let auth = match auth_manager.as_ref().and_then(AuthManager::auth) { Some(auth) => auth, None => { eprintln!( diff --git a/codex-rs/cloud-tasks/src/util.rs b/codex-rs/cloud-tasks/src/util.rs index ff17265f..1c690b26 100644 --- a/codex-rs/cloud-tasks/src/util.rs +++ b/codex-rs/cloud-tasks/src/util.rs @@ -2,6 +2,10 @@ use base64::Engine as _; use chrono::Utc; use reqwest::header::HeaderMap; +use codex_core::config::Config; +use codex_core::config::ConfigOverrides; +use codex_login::AuthManager; + pub fn set_user_agent_suffix(suffix: &str) { if let Ok(mut guard) = codex_core::default_client::USER_AGENT_SUFFIX.lock() { guard.replace(suffix.to_string()); @@ -54,6 +58,18 @@ pub fn extract_chatgpt_account_id(token: &str) -> Option { .map(str::to_string) } +pub async fn load_auth_manager() -> Option { + // TODO: pass in cli overrides once cloud tasks properly support them. + let config = Config::load_with_cli_overrides(Vec::new(), ConfigOverrides::default()) + .await + .ok()?; + Some(AuthManager::new( + config.codex_home, + false, + config.cli_auth_credentials_store_mode, + )) +} + /// Build headers for ChatGPT-backed requests: `User-Agent`, optional `Authorization`, /// and optional `ChatGPT-Account-Id`. pub async fn build_chatgpt_headers() -> HeaderMap { @@ -69,31 +85,22 @@ pub async fn build_chatgpt_headers() -> HeaderMap { USER_AGENT, HeaderValue::from_str(&ua).unwrap_or(HeaderValue::from_static("codex-cli")), ); - if let Ok(home) = codex_core::config::find_codex_home() { - let store_mode = codex_core::config::Config::load_from_base_config_with_overrides( - codex_core::config::ConfigToml::default(), - codex_core::config::ConfigOverrides::default(), - home.clone(), - ) - .map(|cfg| cfg.cli_auth_credentials_store_mode) - .unwrap_or_default(); - let am = codex_login::AuthManager::new(home, false, store_mode); - if let Some(auth) = am.auth() - && let Ok(tok) = auth.get_token().await - && !tok.is_empty() + if let Some(am) = load_auth_manager().await + && let Some(auth) = am.auth() + && let Ok(tok) = auth.get_token().await + && !tok.is_empty() + { + let v = format!("Bearer {tok}"); + if let Ok(hv) = HeaderValue::from_str(&v) { + headers.insert(AUTHORIZATION, hv); + } + if let Some(acc) = auth + .get_account_id() + .or_else(|| extract_chatgpt_account_id(&tok)) + && let Ok(name) = HeaderName::from_bytes(b"ChatGPT-Account-Id") + && let Ok(hv) = HeaderValue::from_str(&acc) { - let v = format!("Bearer {tok}"); - if let Ok(hv) = HeaderValue::from_str(&v) { - headers.insert(AUTHORIZATION, hv); - } - if let Some(acc) = auth - .get_account_id() - .or_else(|| extract_chatgpt_account_id(&tok)) - && let Ok(name) = HeaderName::from_bytes(b"ChatGPT-Account-Id") - && let Ok(hv) = HeaderValue::from_str(&acc) - { - headers.insert(name, hv); - } + headers.insert(name, hv); } } headers