Reload cloud requirements after user login (#10725)

Reload cloud requirements after user login so it could take effect
immediately.
This commit is contained in:
xl-openai
2026-02-05 00:27:16 -08:00
committed by GitHub
Unverified
parent dc7007beaa
commit 1e1146cd29
2 changed files with 114 additions and 14 deletions
@@ -140,6 +140,7 @@ use codex_app_server_protocol::UserSavedConfig;
use codex_app_server_protocol::build_turns_from_event_msgs;
use codex_backend_client::Client as BackendClient;
use codex_chatgpt::connectors;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_core::AuthManager;
use codex_core::CodexAuth;
use codex_core::CodexThread;
@@ -162,6 +163,7 @@ use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::config::types::McpServerTransportConfig;
use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::default_client::get_codex_user_agent;
use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::error::CodexErr;
use codex_core::exec::ExecParams;
use codex_core::exec_env::create_env;
@@ -218,6 +220,7 @@ use std::io::Error as IoError;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::time::Duration;
@@ -277,7 +280,7 @@ pub(crate) struct CodexMessageProcessor {
codex_linux_sandbox_exe: Option<PathBuf>,
config: Arc<Config>,
cli_overrides: Vec<(String, TomlValue)>,
cloud_requirements: CloudRequirementsLoader,
cloud_requirements: Arc<RwLock<CloudRequirementsLoader>>,
conversation_listeners: HashMap<Uuid, oneshot::Sender<()>>,
listener_thread_ids_by_subscription: HashMap<Uuid, ThreadId>,
active_login: Arc<Mutex<Option<ActiveLogin>>>,
@@ -349,7 +352,7 @@ impl CodexMessageProcessor {
codex_linux_sandbox_exe,
config,
cli_overrides,
cloud_requirements,
cloud_requirements: Arc::new(RwLock::new(cloud_requirements)),
conversation_listeners: HashMap::new(),
listener_thread_ids_by_subscription: HashMap::new(),
active_login: Arc::new(Mutex::new(None)),
@@ -362,9 +365,10 @@ impl CodexMessageProcessor {
}
async fn load_latest_config(&self) -> Result<Config, JSONRPCErrorError> {
let cloud_requirements = self.current_cloud_requirements();
codex_core::config::ConfigBuilder::default()
.cli_overrides(self.cli_overrides.clone())
.cloud_requirements(self.cloud_requirements.clone())
.cloud_requirements(cloud_requirements)
.build()
.await
.map_err(|err| JSONRPCErrorError {
@@ -374,6 +378,13 @@ impl CodexMessageProcessor {
})
}
fn current_cloud_requirements(&self) -> CloudRequirementsLoader {
self.cloud_requirements
.read()
.map(|guard| guard.clone())
.unwrap_or_default()
}
fn review_request_from_target(
target: ApiReviewTarget,
) -> Result<(ReviewRequest, String), JSONRPCErrorError> {
@@ -834,6 +845,9 @@ impl CodexMessageProcessor {
let outgoing_clone = self.outgoing.clone();
let active_login = self.active_login.clone();
let auth_manager = self.auth_manager.clone();
let cloud_requirements = self.cloud_requirements.clone();
let chatgpt_base_url = self.config.chatgpt_base_url.clone();
let cli_overrides = self.cli_overrides.clone();
let auth_url = server.auth_url.clone();
tokio::spawn(async move {
let (success, error_msg) = match tokio::time::timeout(
@@ -863,6 +877,16 @@ impl CodexMessageProcessor {
if success {
auth_manager.reload();
replace_cloud_requirements_loader(
cloud_requirements.as_ref(),
auth_manager.clone(),
chatgpt_base_url,
);
sync_default_client_residency_requirement(
&cli_overrides,
cloud_requirements.as_ref(),
)
.await;
// Notify clients with the actual current auth mode.
let current_auth_method = auth_manager
@@ -927,6 +951,9 @@ impl CodexMessageProcessor {
let outgoing_clone = self.outgoing.clone();
let active_login = self.active_login.clone();
let auth_manager = self.auth_manager.clone();
let cloud_requirements = self.cloud_requirements.clone();
let chatgpt_base_url = self.config.chatgpt_base_url.clone();
let cli_overrides = self.cli_overrides.clone();
let auth_url = server.auth_url.clone();
tokio::spawn(async move {
let (success, error_msg) = match tokio::time::timeout(
@@ -956,6 +983,16 @@ impl CodexMessageProcessor {
if success {
auth_manager.reload();
replace_cloud_requirements_loader(
cloud_requirements.as_ref(),
auth_manager.clone(),
chatgpt_base_url,
);
sync_default_client_residency_requirement(
&cli_overrides,
cloud_requirements.as_ref(),
)
.await;
// Notify clients with the actual current auth mode.
let current_auth_method = auth_manager
@@ -1123,6 +1160,16 @@ impl CodexMessageProcessor {
return;
}
self.auth_manager.reload();
replace_cloud_requirements_loader(
self.cloud_requirements.as_ref(),
self.auth_manager.clone(),
self.config.chatgpt_base_url.clone(),
);
sync_default_client_residency_requirement(
&self.cli_overrides,
self.cloud_requirements.as_ref(),
)
.await;
self.outgoing
.send_response(request_id, LoginAccountResponse::ChatgptAuthTokens {})
@@ -1561,11 +1608,12 @@ impl CodexMessageProcessor {
);
}
let cloud_requirements = self.current_cloud_requirements();
let config = match derive_config_from_params(
&self.cli_overrides,
Some(request_overrides),
typesafe_overrides,
&self.cloud_requirements,
&cloud_requirements,
)
.await
{
@@ -1647,11 +1695,12 @@ impl CodexMessageProcessor {
);
typesafe_overrides.ephemeral = ephemeral;
let cloud_requirements = self.current_cloud_requirements();
let config = match derive_config_from_params(
&self.cli_overrides,
config,
typesafe_overrides,
&self.cloud_requirements,
&cloud_requirements,
)
.await
{
@@ -2440,12 +2489,13 @@ impl CodexMessageProcessor {
);
// Derive a Config using the same logic as new conversation, honoring overrides if provided.
let cloud_requirements = self.current_cloud_requirements();
let config = match derive_config_for_cwd(
&self.cli_overrides,
request_overrides,
typesafe_overrides,
history_cwd,
&self.cloud_requirements,
&cloud_requirements,
)
.await
{
@@ -2633,12 +2683,13 @@ impl CodexMessageProcessor {
None,
);
// Derive a Config using the same logic as new conversation, honoring overrides if provided.
let cloud_requirements = self.current_cloud_requirements();
let config = match derive_config_for_cwd(
&self.cli_overrides,
request_overrides,
typesafe_overrides,
history_cwd,
&self.cloud_requirements,
&cloud_requirements,
)
.await
{
@@ -3438,12 +3489,13 @@ impl CodexMessageProcessor {
),
};
let cloud_requirements = self.current_cloud_requirements();
let config = match derive_config_for_cwd(
&self.cli_overrides,
request_overrides,
typesafe_overrides,
history_cwd,
&self.cloud_requirements,
&cloud_requirements,
)
.await
{
@@ -3627,12 +3679,13 @@ impl CodexMessageProcessor {
),
};
let cloud_requirements = self.current_cloud_requirements();
let config = match derive_config_for_cwd(
&self.cli_overrides,
request_overrides,
typesafe_overrides,
history_cwd,
&self.cloud_requirements,
&cloud_requirements,
)
.await
{
@@ -4944,6 +4997,41 @@ fn validate_dynamic_tools(
Ok(())
}
fn replace_cloud_requirements_loader(
cloud_requirements: &RwLock<CloudRequirementsLoader>,
auth_manager: Arc<AuthManager>,
chatgpt_base_url: String,
) {
let loader = cloud_requirements_loader(auth_manager, chatgpt_base_url);
if let Ok(mut guard) = cloud_requirements.write() {
*guard = loader;
} else {
warn!("failed to update cloud requirements loader");
}
}
async fn sync_default_client_residency_requirement(
cli_overrides: &[(String, TomlValue)],
cloud_requirements: &RwLock<CloudRequirementsLoader>,
) {
let loader = cloud_requirements
.read()
.map(|guard| guard.clone())
.unwrap_or_default();
match codex_core::config::ConfigBuilder::default()
.cli_overrides(cli_overrides.to_vec())
.cloud_requirements(loader)
.build()
.await
{
Ok(config) => set_default_client_residency_requirement(config.enforce_residency.value()),
Err(err) => warn!(
error = %err,
"failed to sync default client residency requirement after auth refresh"
),
}
}
/// Derive the effective [`Config`] by layering three override sources.
///
/// Precedence (lowest to highest):
+17 -5
View File
@@ -413,7 +413,7 @@ async fn run_ratatui_app(
initial_config: Config,
overrides: ConfigOverrides,
cli_kv_overrides: Vec<(String, toml::Value)>,
cloud_requirements: CloudRequirementsLoader,
mut cloud_requirements: CloudRequirementsLoader,
feedback: codex_feedback::CodexFeedback,
) -> color_eyre::Result<AppExitInfo> {
color_eyre::install()?;
@@ -470,9 +470,10 @@ async fn run_ratatui_app(
should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag);
let config = if should_show_onboarding {
let show_login_screen = should_show_login_screen(login_status, &initial_config);
let onboarding_result = run_onboarding_app(
OnboardingScreenArgs {
show_login_screen: should_show_login_screen(login_status, &initial_config),
show_login_screen,
show_trust_screen: should_show_trust_screen_flag,
login_status,
auth_manager: auth_manager.clone(),
@@ -493,9 +494,19 @@ async fn run_ratatui_app(
exit_reason: ExitReason::UserRequested,
});
}
// If the user made an explicit trust decision, reload config so current
// process state reflects what was persisted to config.toml.
if onboarding_result.directory_trust_decision.is_some() {
// If this onboarding run included the login step, always refresh cloud requirements and
// rebuild config. This avoids missing newly available cloud requirements due to login
// status detection edge cases.
if show_login_screen {
cloud_requirements = cloud_requirements_loader(
auth_manager.clone(),
initial_config.chatgpt_base_url.clone(),
);
}
// If the user made an explicit trust decision, or we showed the login flow, reload config
// so current process state reflects persisted trust/auth changes.
if onboarding_result.directory_trust_decision.is_some() || show_login_screen {
load_config_or_exit(
cli_kv_overrides.clone(),
overrides.clone(),
@@ -668,6 +679,7 @@ async fn run_ratatui_app(
}
_ => config,
};
set_default_client_residency_requirement(config.enforce_residency.value());
let active_profile = config.active_profile.clone();
let should_show_trust_screen = should_show_trust_screen(&config);