Clarify config loader APIs and share interactive login setup (#57169)

## What changed

- Rename ChatGPT-specific bundle loaders to `chatgpt_config_bundle_loader*` and use managed-config terminology for shared loader plumbing.
- Pass `Config` directly when updating the app-server's managed configuration loader.
- Share configuration loading, logging setup, and result handling between browser and device-code login.
- Expose the CLI cloud-config helpers and `provider_uses_first_party_auth_path` through their library APIs.

## Testing

Extend CLI login coverage to verify that `forced_login_method="api"` rejects both `login` and `login --device-auth` while preserving saved API-key credentials.

GitOrigin-RevId: 9e8fa6110dc80882ba365e550b48ac77da604940
This commit is contained in:
smurching-oai
2026-10-26 18:05:05 +00:00
committed by copyberry
parent f627672c49
commit 6e319d2ca7
26 changed files with 152 additions and 161 deletions
@@ -75,7 +75,7 @@ impl ConfigManager {
.map_err(io::Error::other)?;
let revision = self.network_policy.policy().revision();
let local_sources = self.load_local_network_policy(revision).await?;
let cloud_config = self.current_cloud_config_bundle();
let cloud_config = self.current_managed_config_loader();
let result = async {
let cloud_snapshot = cloud_config.get_snapshot().await;
let cloud = cloud_snapshot.bundle.clone().map_err(io::Error::other)?;
+10 -13
View File
@@ -1,5 +1,5 @@
use codex_arg0::Arg0DispatchPaths;
use codex_cloud_config::cloud_config_bundle_loader;
use codex_cloud_config::chatgpt_config_bundle_loader;
use codex_config::CloudConfigBundleLoader;
use codex_config::ConfigLayerStack;
use codex_config::LoaderOverrides;
@@ -174,7 +174,7 @@ impl ConfigManager {
.unwrap_or_default()
}
pub(crate) fn current_cloud_config_bundle(&self) -> CloudConfigBundleLoader {
pub(crate) fn current_managed_config_loader(&self) -> CloudConfigBundleLoader {
self.cloud_config_bundle
.read()
.map(|guard| guard.clone())
@@ -191,12 +191,13 @@ impl ConfigManager {
Ok(())
}
pub(crate) fn replace_cloud_config_bundle_loader(
pub(crate) fn update_managed_config_loader(
&self,
auth_manager: Arc<AuthManager>,
chatgpt_base_url: String,
http_client_factory: codex_http_client::HttpClientFactory,
config: &Config,
) {
let chatgpt_base_url = config.chatgpt_base_url.clone();
let http_client_factory = config.http_client_factory();
let endpoint = codex_backend_client::Client::new(
chatgpt_base_url.clone(),
http_client_factory.clone(),
@@ -207,7 +208,7 @@ impl ConfigManager {
.policy()
.restrict_to_endpoints(endpoint.parse().into_iter().collect()),
);
let loader = cloud_config_bundle_loader(
let loader = chatgpt_config_bundle_loader(
auth_manager,
chatgpt_base_url,
self.codex_home.clone(),
@@ -222,7 +223,7 @@ impl ConfigManager {
self.revoke_mcp_ema();
}
pub(crate) fn clear_cloud_config_bundle_loader(&self) {
pub(crate) fn clear_chatgpt_config_loader(&self) {
if let Ok(mut guard) = self.cloud_config_bundle.write() {
guard.retire_ema_policy();
*guard = CloudConfigBundleLoader::default();
@@ -409,7 +410,7 @@ impl ConfigManager {
/// Load local policy before auth, then fetch the account's cloud configuration.
/// Callers choose their error/recovery policy before initializing any runtimes.
pub(crate) async fn load_cloud_startup_config(
pub(crate) async fn load_managed_startup_config(
&self,
cwd: Option<PathBuf>,
) -> std::io::Result<CloudStartupConfig> {
@@ -418,11 +419,7 @@ impl ConfigManager {
AuthManager::shared_from_config(&bootstrap, /*enable_codex_api_key_env*/ false)
.await
.map_err(std::io::Error::other)?;
self.replace_cloud_config_bundle_loader(
auth,
bootstrap.chatgpt_base_url.clone(),
bootstrap.http_client_factory(),
);
self.update_managed_config_loader(auth, &bootstrap);
let config = self.load_latest_config(cwd).await;
Ok(CloudStartupConfig { bootstrap, config })
}
@@ -236,7 +236,7 @@ async fn catalog_reload_uses_latest_model_provider() -> Result<()> {
);
let startup = manager.load_non_project_config().await?;
assert_eq!(startup.model_provider_id, "gateway");
manager.clear_cloud_config_bundle_loader();
manager.clear_chatgpt_config_loader();
let refreshed = manager
.load_startup_config(/*fallback_cwd*/ None)
.await?
@@ -126,11 +126,7 @@ pub(super) async fn configure(
)
.await
.map_err(IoError::other)?;
config_manager.replace_cloud_config_bundle_loader(
bootstrap_auth_manager,
bootstrap_config.chatgpt_base_url.clone(),
bootstrap_config.http_client_factory(),
);
config_manager.update_managed_config_loader(bootstrap_auth_manager, &bootstrap_config);
let policy_config = config_manager
.load_startup_config(Some(config.cwd.to_path_buf()))
.await?
@@ -168,11 +164,7 @@ pub(super) async fn configure(
config.application_auth_route_config = policy_config.application_auth_route_config;
config.forced_login_method = policy_config.forced_login_method;
config.forced_chatgpt_workspace_id = policy_config.forced_chatgpt_workspace_id;
config_manager.replace_cloud_config_bundle_loader(
policy_auth_manager,
config.chatgpt_base_url.clone(),
config.http_client_factory(),
);
config_manager.update_managed_config_loader(policy_auth_manager, config);
codex_login::default_client::set_default_client_residency_requirement(
config.enforce_residency.value(),
);
+2 -6
View File
@@ -569,7 +569,7 @@ pub async fn run_main_with_transport_options(
Arc::new(NoopThreadConfigLoader),
);
let startup = config_manager
.load_cloud_startup_config(startup_cwd.clone())
.load_managed_startup_config(startup_cwd.clone())
.await?;
let mut config_warnings = Vec::new();
let mut plugin_startup_config = PluginStartupConfig::Current;
@@ -600,11 +600,7 @@ pub async fn run_main_with_transport_options(
AuthManager::shared_from_config(&config, /*enable_codex_api_key_env*/ false)
.await
.map_err(std::io::Error::other)?;
config_manager.replace_cloud_config_bundle_loader(
auth_manager.clone(),
config.chatgpt_base_url.clone(),
config.http_client_factory(),
);
config_manager.update_managed_config_loader(auth_manager.clone(), &config);
config_manager
.sync_default_client_residency_requirement()
.await;
@@ -476,7 +476,7 @@ impl AccountRequestProcessor {
) {
Ok(()) => {
self.auth_manager.reload().await;
self.config_manager.clear_cloud_config_bundle_loader();
self.config_manager.clear_chatgpt_config_loader();
Ok(())
}
Err(err) => Err(internal_error(format!("failed to save api key: {err}"))),
@@ -575,7 +575,7 @@ impl AccountRequestProcessor {
}
.map_err(|err| internal_error(format!("failed to save Amazon Bedrock auth: {err}")))?;
self.auth_manager.reload().await;
self.config_manager.clear_cloud_config_bundle_loader();
self.config_manager.clear_chatgpt_config_loader();
Ok(LoginAccountResponse::AmazonBedrock {})
}
.await;
@@ -910,11 +910,8 @@ impl AccountRequestProcessor {
)))
.await
.map_err(|err| internal_error(format!("failed to set external auth: {err}")))?;
self.config_manager.replace_cloud_config_bundle_loader(
self.auth_manager.clone(),
self.config.chatgpt_base_url.clone(),
self.config.http_client_factory(),
);
self.config_manager
.update_managed_config_loader(self.auth_manager.clone(), &self.config);
self.config_manager
.sync_default_client_residency_requirement()
.await;
@@ -986,11 +983,8 @@ impl AccountRequestProcessor {
let auth_changes = self.auth_manager.auth_change_state_receiver();
let owner_generation = auth_changes.borrow().owner_generation;
self.thread_manager.invalidate_mcp_runtimes().await;
self.config_manager.replace_cloud_config_bundle_loader(
self.auth_manager.clone(),
self.config.chatgpt_base_url.clone(),
self.config.http_client_factory(),
);
self.config_manager
.update_managed_config_loader(self.auth_manager.clone(), &self.config);
self.config_manager
.sync_default_client_residency_requirement()
.await;
@@ -1542,11 +1536,7 @@ pub(crate) async fn logout_configured_account(
// Another process may have changed the persisted workspace. Reload both
// account authority and its policy before selecting a grant to remove.
auth_manager.reload().await;
config_manager.replace_cloud_config_bundle_loader(
Arc::clone(auth_manager),
fallback_config.chatgpt_base_url.clone(),
fallback_config.http_client_factory(),
);
config_manager.update_managed_config_loader(Arc::clone(auth_manager), fallback_config);
let config = config_manager
.load_latest_config(/*fallback_cwd*/ None)
.await;
@@ -1602,7 +1592,7 @@ pub(crate) async fn clear_account_configuration(
config_manager: &ConfigManager,
config: &Config,
) -> Result<(), JSONRPCErrorError> {
config_manager.clear_cloud_config_bundle_loader();
config_manager.clear_chatgpt_config_loader();
if config.model_provider.is_amazon_bedrock() {
clear_user_model_provider_if_bedrock(config_manager, config).await?;
}
+2 -6
View File
@@ -120,7 +120,7 @@ async fn read_startup_config(
);
let cwd = std::env::current_dir().ok();
let loaded = manager
.load_cloud_startup_config(cwd.clone())
.load_managed_startup_config(cwd.clone())
.await
.map_err(startup_error)?;
let config = match loaded.config {
@@ -143,11 +143,7 @@ async fn read_startup_config(
set_default_client_residency_requirement(config.enforce_residency.value());
let config = logout_configured_account(&manager, &auth, &config).await?;
clear_account_configuration(&manager, &config).await?;
manager.replace_cloud_config_bundle_loader(
Arc::clone(&auth),
config.chatgpt_base_url.clone(),
config.http_client_factory(),
);
manager.update_managed_config_loader(Arc::clone(&auth), &config);
manager
.load_latest_config(cwd)
.await
+4 -4
View File
@@ -1,7 +1,7 @@
use anyhow::Context;
use anyhow::Result;
use codex_app_server::in_process::EmbeddedNetworkPolicy;
use codex_cloud_config::cloud_config_bundle_loader_for_storage;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage;
use codex_config::CloudConfigBundleLoader;
use codex_config::ConfigLoadOptions;
use codex_core::config::Config;
@@ -14,7 +14,7 @@ use codex_core::config::load_config_toml_with_layer_stack;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_cli::CliConfigOverrides;
pub(crate) async fn load_config(
pub async fn load_config(
config_overrides: &CliConfigOverrides,
loader_overrides: LoaderOverrides,
) -> Result<Config> {
@@ -31,7 +31,7 @@ pub(crate) async fn load_config(
Ok(config)
}
pub(crate) async fn config_builder(
pub async fn config_builder(
config_overrides: &CliConfigOverrides,
loader_overrides: LoaderOverrides,
harness_overrides: ConfigOverrides,
@@ -58,7 +58,7 @@ pub(crate) async fn config_builder(
)
.await
.context("failed to load bootstrap configuration")?;
let cloud_config_bundle = cloud_config_bundle_loader_for_storage(
let cloud_config_bundle = chatgpt_config_bundle_loader_for_storage(
network_policy.bind_bootstrap_auth(
bootstrap_auth_config(codex_home.as_path(), &bootstrap_config)
.context("failed to resolve cloud configuration authentication")?,
@@ -1,4 +1,4 @@
use codex_cloud_config::cloud_config_bundle_loader_for_storage;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage;
use codex_config::CloudConfigBundleLoader;
use codex_config::ConfigLoadOptions;
use codex_core::config::bootstrap_auth_config;
@@ -40,7 +40,7 @@ pub(super) async fn bootstrap_cloud_config_bundle(
},
)
.await?;
Ok(cloud_config_bundle_loader_for_storage(
Ok(chatgpt_config_bundle_loader_for_storage(
bootstrap_auth_config(codex_home.as_path(), &bootstrap_config)?,
/*enable_codex_api_key_env*/ false,
)
+2 -2
View File
@@ -6,7 +6,7 @@ use std::sync::Arc;
use clap::Parser;
use codex_arg0::Arg0DispatchPaths;
use codex_cloud_config::cloud_config_bundle_loader_for_storage;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage;
use codex_config::LoaderOverrides;
use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
@@ -506,7 +506,7 @@ async fn load_exec_server_config(
)
.await?;
let bootstrap_auth_config = bootstrap_auth_config(&codex_home, &bootstrap_config)?;
let cloud_config_bundle = cloud_config_bundle_loader_for_storage(
let cloud_config_bundle = chatgpt_config_bundle_loader_for_storage(
bootstrap_auth_config,
/*enable_codex_api_key_env*/ false,
)
+1
View File
@@ -1,3 +1,4 @@
pub mod cloud_config;
pub(crate) mod debug_sandbox;
mod exit_status;
pub(crate) mod login;
+69 -61
View File
@@ -172,29 +172,8 @@ pub async fn login_with_chatgpt(
server.block_until_done().await
}
pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) -> ! {
let config = load_config_or_exit(cli_config_overrides).await;
let _login_log_guard = init_login_file_logging(&config);
tracing::info!("starting browser login flow");
if !config
.auth_config()
.is_login_method_allowed(ForcedLoginMethod::Chatgpt)
{
eprintln!("{CHATGPT_LOGIN_DISABLED_MESSAGE}");
std::process::exit(1);
}
let effective_chatgpt_workspaces = config.auth_config().effective_chatgpt_workspaces();
match login_with_chatgpt(
config.codex_home.to_path_buf(),
effective_chatgpt_workspaces,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
config.auth_route_config(),
)
.await
{
fn finish_login(result: std::io::Result<()>) -> ! {
match result {
Ok(_) => {
eprintln!("{LOGIN_SUCCESS_MESSAGE}");
std::process::exit(0);
@@ -206,6 +185,43 @@ pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) ->
}
}
async fn run_interactive_login<F>(
cli_config_overrides: CliConfigOverrides,
login: impl FnOnce(Config) -> F,
) -> !
where
F: std::future::Future<Output = std::io::Result<()>>,
{
let config = load_config_or_exit(cli_config_overrides).await;
let _login_log_guard = init_login_file_logging(&config);
finish_login(login(config).await)
}
pub async fn run_login_with_chatgpt(cli_config_overrides: CliConfigOverrides) -> ! {
run_interactive_login(cli_config_overrides, |config| async move {
tracing::info!("starting browser login flow");
if !config
.auth_config()
.is_login_method_allowed(ForcedLoginMethod::Chatgpt)
{
eprintln!("{CHATGPT_LOGIN_DISABLED_MESSAGE}");
std::process::exit(1);
}
let effective_chatgpt_workspaces = config.auth_config().effective_chatgpt_workspaces();
login_with_chatgpt(
config.codex_home.to_path_buf(),
effective_chatgpt_workspaces,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
config.auth_route_config(),
)
.await
})
.await
}
pub async fn run_login_with_api_key(
cli_config_overrides: CliConfigOverrides,
api_key: String,
@@ -326,46 +342,38 @@ pub async fn run_login_with_device_code(
issuer_base_url: Option<String>,
client_id: Option<String>,
) -> ! {
let config = load_config_or_exit(cli_config_overrides).await;
let _login_log_guard = init_login_file_logging(&config);
tracing::info!("starting device code login flow");
if !config
.auth_config()
.is_login_method_allowed(ForcedLoginMethod::Chatgpt)
{
eprintln!("{CHATGPT_LOGIN_DISABLED_MESSAGE}");
std::process::exit(1);
}
let auth_route_config = config.auth_route_config();
clear_existing_auth_before_login(
&config.codex_home,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
&auth_route_config,
)
.await;
let effective_chatgpt_workspaces = config.auth_config().effective_chatgpt_workspaces();
let mut opts = ServerOptions::new(
config.codex_home.to_path_buf(),
client_id.unwrap_or(CLIENT_ID.to_string()),
effective_chatgpt_workspaces,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
auth_route_config,
);
if let Some(iss) = issuer_base_url {
opts.issuer = iss;
}
match run_device_code_login(opts).await {
Ok(()) => {
eprintln!("{LOGIN_SUCCESS_MESSAGE}");
std::process::exit(0);
}
Err(e) => {
eprintln!("Error logging in with device code: {e}");
run_interactive_login(cli_config_overrides, |config| async move {
tracing::info!("starting device code login flow");
if !config
.auth_config()
.is_login_method_allowed(ForcedLoginMethod::Chatgpt)
{
eprintln!("{CHATGPT_LOGIN_DISABLED_MESSAGE}");
std::process::exit(1);
}
}
let auth_route_config = config.auth_route_config();
clear_existing_auth_before_login(
&config.codex_home,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
&auth_route_config,
)
.await;
let effective_chatgpt_workspaces = config.auth_config().effective_chatgpt_workspaces();
let mut opts = ServerOptions::new(
config.codex_home.to_path_buf(),
client_id.unwrap_or(CLIENT_ID.to_string()),
effective_chatgpt_workspaces,
config.cli_auth_credentials_store_mode,
config.auth_keyring_backend_kind(),
auth_route_config,
);
if let Some(iss) = issuer_base_url {
opts.issuer = iss;
}
run_device_code_login(opts).await
})
.await
}
/// Prefers device-code login (with `open_browser = false`) when headless environment is detected, but keeps
+1 -1
View File
@@ -10,6 +10,7 @@ use codex_arg0::Arg0DispatchPaths;
use codex_arg0::arg0_dispatch_or_else;
use codex_chatgpt::apply_command::ApplyCommand;
use codex_chatgpt::apply_command::run_apply_command;
use codex_cli::cloud_config;
use codex_cli::read_access_token_from_stdin;
use codex_cli::read_api_key_from_stdin;
use codex_cli::run_login_status;
@@ -52,7 +53,6 @@ static ALLOCATOR: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
#[cfg(any(target_os = "macos", target_os = "windows"))]
mod app_cmd;
mod cloud_config;
mod config_override_args;
mod daemon_install;
mod daemon_telemetry;
+10
View File
@@ -84,6 +84,16 @@ fn login_with_api_key_reads_stdin_and_writes_auth_json() -> Result<()> {
Authentication is checked when you send a request.
");
for args in [vec!["login"], vec!["login", "--device-auth"]] {
codex_command(codex_home.path())?
.args(["-c", "forced_login_method=\"api\""])
.args(args)
.assert()
.failure()
.stderr(contains("ChatGPT login is disabled"));
assert_eq!(read_auth_json(codex_home.path())?, auth);
}
Ok(())
}
+12 -12
View File
@@ -45,7 +45,7 @@ pub fn managed_config_bundle_loader(
.network_policy()
.clone()
.restrict_to_endpoints(endpoint.parse().into_iter().collect());
cloud_config_bundle_loader(
chatgpt_config_bundle_loader(
auth_manager,
chatgpt_base_url,
codex_home,
@@ -68,8 +68,8 @@ pub async fn managed_config_bundle_loader_for_storage(
));
}
let service =
cloud_config_bundle_service_for_storage(auth_config, enable_codex_api_key_env).await?;
Ok(cloud_config_bundle_loader_for_service(service).0)
chatgpt_config_bundle_service_for_storage(auth_config, enable_codex_api_key_env).await?;
Ok(managed_config_bundle_loader_for_service(service).0)
}
struct CloudConfigBundleLoaderLifetime<C: BundleSource> {
@@ -83,7 +83,7 @@ impl<C: BundleSource> Drop for CloudConfigBundleLoaderLifetime<C> {
}
}
pub fn cloud_config_bundle_loader(
pub fn chatgpt_config_bundle_loader(
auth_manager: Arc<AuthManager>,
chatgpt_base_url: String,
codex_home: PathBuf,
@@ -98,11 +98,11 @@ pub fn cloud_config_bundle_loader(
codex_home,
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (loader, _) = cloud_config_bundle_loader_for_service(service);
let (loader, _) = managed_config_bundle_loader_for_service(service);
loader
}
pub(crate) fn cloud_config_bundle_loader_for_service<C>(
pub(crate) fn managed_config_bundle_loader_for_service<C>(
service: CloudConfigBundleService<C>,
) -> (CloudConfigBundleLoader, JoinHandle<()>)
where
@@ -133,24 +133,24 @@ where
(loader, refresh_task)
}
pub async fn cloud_config_bundle_loader_for_storage(
pub async fn chatgpt_config_bundle_loader_for_storage(
auth_config: AuthConfig,
enable_codex_api_key_env: bool,
) -> std::io::Result<CloudConfigBundleLoader> {
let service =
cloud_config_bundle_service_for_storage(auth_config, enable_codex_api_key_env).await?;
let (loader, _) = cloud_config_bundle_loader_for_service(service);
chatgpt_config_bundle_service_for_storage(auth_config, enable_codex_api_key_env).await?;
let (loader, _) = managed_config_bundle_loader_for_service(service);
Ok(loader)
}
/// Fetches directly from the network on each load, without reading or writing
/// the disk cache or starting a background refresher.
pub async fn cloud_config_bundle_loader_for_storage_without_cache(
pub async fn chatgpt_config_bundle_loader_for_storage_without_cache(
auth_config: AuthConfig,
enable_codex_api_key_env: bool,
) -> std::io::Result<CloudConfigBundleLoader> {
let service = Arc::new(
cloud_config_bundle_service_for_storage(auth_config, enable_codex_api_key_env)
chatgpt_config_bundle_service_for_storage(auth_config, enable_codex_api_key_env)
.await?
.without_cache(),
);
@@ -160,7 +160,7 @@ pub async fn cloud_config_bundle_loader_for_storage_without_cache(
}))
}
async fn cloud_config_bundle_service_for_storage(
async fn chatgpt_config_bundle_service_for_storage(
auth_config: AuthConfig,
enable_codex_api_key_env: bool,
) -> std::io::Result<CloudConfigBundleService<ChatGptSource<BackendBundleClient>>> {
+1 -1
View File
@@ -37,7 +37,7 @@ pub fn config_server_bundle_loader(
codex_home,
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
crate::bundle_loader::cloud_config_bundle_loader_for_service(service).0
crate::bundle_loader::managed_config_bundle_loader_for_service(service).0
}
Err(error) => CloudConfigBundleLoader::new(std::future::ready(Err(error))),
}
@@ -1,7 +1,7 @@
#![cfg(test)]
use super::*;
use crate::bundle_loader::cloud_config_bundle_loader_for_service;
use crate::bundle_loader::managed_config_bundle_loader_for_service;
use crate::service::CLOUD_CONFIG_BUNDLE_TIMEOUT;
use crate::service::CloudConfigBundleService;
use codex_config::CloudConfigBundleLoader;
@@ -27,7 +27,7 @@ fn remote_loader(url: String, codex_home: PathBuf) -> CloudConfigBundleLoader {
.http_client_factory()
.clone();
let source = ConfigServerSource::new(url, /*oauth*/ None, codex_home.clone(), factory).unwrap();
cloud_config_bundle_loader_for_service(CloudConfigBundleService::from_source(
managed_config_bundle_loader_for_service(CloudConfigBundleService::from_source(
source,
codex_home,
CLOUD_CONFIG_BUNDLE_TIMEOUT,
+3 -3
View File
@@ -13,9 +13,9 @@ mod metrics;
mod service;
mod validation;
pub use bundle_loader::cloud_config_bundle_loader;
pub use bundle_loader::cloud_config_bundle_loader_for_storage;
pub use bundle_loader::cloud_config_bundle_loader_for_storage_without_cache;
pub use bundle_loader::chatgpt_config_bundle_loader;
pub use bundle_loader::chatgpt_config_bundle_loader_for_storage;
pub use bundle_loader::chatgpt_config_bundle_loader_for_storage_without_cache;
pub use bundle_loader::managed_config_auth_manager;
pub use bundle_loader::managed_config_bundle_loader;
pub use bundle_loader::managed_config_bundle_loader_for_storage;
+6 -6
View File
@@ -1347,7 +1347,7 @@ async fn production_loader_recovers_startup_timeouts_in_background() {
codex_home.path().to_path_buf(),
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (loader, _) = crate::bundle_loader::cloud_config_bundle_loader_for_service(service);
let (loader, _) = crate::bundle_loader::managed_config_bundle_loader_for_service(service);
let (initial, ()) = tokio::join!(loader.get(), async {
fetcher.request_started.notified().await;
tokio::time::advance(CLOUD_CONFIG_BUNDLE_TIMEOUT + Duration::from_millis(1)).await;
@@ -1427,7 +1427,7 @@ async fn production_loader_restores_normal_refresh_interval_after_non_timeout_er
codex_home.path().to_path_buf(),
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (loader, _) = crate::bundle_loader::cloud_config_bundle_loader_for_service(service);
let (loader, _) = crate::bundle_loader::managed_config_bundle_loader_for_service(service);
let (initial, ()) = tokio::join!(loader.get(), async {
fetcher.request_started.notified().await;
tokio::time::advance(CLOUD_CONFIG_BUNDLE_TIMEOUT + Duration::from_millis(1)).await;
@@ -1499,7 +1499,7 @@ async fn production_loader_refreshes_later_configs_and_preserves_failed_refreshe
codex_home.path().to_path_buf(),
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (loader, _) = crate::bundle_loader::cloud_config_bundle_loader_for_service(service);
let (loader, _) = crate::bundle_loader::managed_config_bundle_loader_for_service(service);
let (first, second) = tokio::join!(loader.get(), loader.get());
assert_eq!(first, Ok(Some(initial_bundle.clone())));
@@ -1556,7 +1556,7 @@ async fn each_loader_owns_refresh_until_its_last_clone_is_dropped() {
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (loader, original_task) =
crate::bundle_loader::cloud_config_bundle_loader_for_service(service);
crate::bundle_loader::managed_config_bundle_loader_for_service(service);
let cloned_loader = loader.clone();
assert_eq!(loader.get().await, Ok(Some(test_bundle())));
fetcher.request_started.notified().await;
@@ -1582,7 +1582,7 @@ async fn each_loader_owns_refresh_until_its_last_clone_is_dropped() {
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (replacement_loader, replacement_task) =
crate::bundle_loader::cloud_config_bundle_loader_for_service(replacement_service);
crate::bundle_loader::managed_config_bundle_loader_for_service(replacement_service);
assert_eq!(replacement_loader.get().await, Ok(Some(test_bundle())));
replacement_fetcher.request_started.notified().await;
@@ -1629,7 +1629,7 @@ async fn dropping_loader_cancels_in_flight_startup_and_refresh() {
codex_home.path().to_path_buf(),
CLOUD_CONFIG_BUNDLE_TIMEOUT,
);
let (loader, _) = crate::bundle_loader::cloud_config_bundle_loader_for_service(service);
let (loader, _) = crate::bundle_loader::managed_config_bundle_loader_for_service(service);
if starts_from_cache {
assert_eq!(loader.get().await, Ok(Some(test_bundle())));
tokio::task::yield_now().await;
+3 -3
View File
@@ -59,7 +59,7 @@ use codex_app_server_protocol::TurnStartParams;
use codex_app_server_protocol::TurnStartResponse;
use codex_app_server_protocol::TurnStartedNotification;
use codex_arg0::Arg0DispatchPaths;
use codex_cloud_config::cloud_config_bundle_loader_for_storage;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage;
use codex_config::CloudConfigBundleLoader;
use codex_config::ConfigLoadError;
use codex_config::ConfigLoadOptions;
@@ -408,7 +408,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
CloudConfigBundleLoader::default(),
)
.await;
let gate_cloud_config = cloud_config_bundle_loader_for_storage(
let gate_cloud_config = chatgpt_config_bundle_loader_for_storage(
embedded_network_policy
.bind_bootstrap_auth(bootstrap_auth_config(&codex_home, &gate_bootstrap)?),
/*enable_codex_api_key_env*/ false,
@@ -508,7 +508,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
// API keys cannot fetch workspace-managed configuration. Preserve the
// existing ChatGPT bootstrap identity even when model requests allow
// CODEX_API_KEY.
let cloud_config_bundle = cloud_config_bundle_loader_for_storage(
let cloud_config_bundle = chatgpt_config_bundle_loader_for_storage(
bootstrap_auth_config,
/*enable_codex_api_key_env*/ false,
)
+1
View File
@@ -42,6 +42,7 @@ pub use provider::ProviderAuthRecoveryMessages;
pub use provider::ProviderUnauthorizedRecovery;
pub use provider::SharedModelProvider;
pub use provider::create_model_provider;
pub use provider::provider_uses_first_party_auth_path;
#[cfg(test)]
#[path = "workspace_routing_tests.rs"]
+1 -1
View File
@@ -333,7 +333,7 @@ pub type ModelProviderFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a
/// Shared runtime model provider handle.
pub type SharedModelProvider = Arc<dyn ModelProvider>;
fn provider_uses_first_party_auth_path(provider: &ModelProviderInfo) -> bool {
pub fn provider_uses_first_party_auth_path(provider: &ModelProviderInfo) -> bool {
provider.requires_openai_auth
&& provider.env_key.is_none()
&& provider.experimental_bearer_token.is_none()
+3 -3
View File
@@ -47,7 +47,7 @@ use codex_app_server_protocol::ThreadListCwdFilter;
use codex_app_server_protocol::ThreadListParams;
use codex_app_server_protocol::ThreadSortKey as AppServerThreadSortKey;
use codex_app_server_protocol::ThreadSourceKind;
use codex_cloud_config::cloud_config_bundle_loader_for_storage;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage;
use codex_config::CloudConfigBundleLoader;
use codex_config::ConfigLoadError;
use codex_config::LoaderOverrides;
@@ -1098,7 +1098,7 @@ async fn cloud_config_bundle_for_app_server_target(
codex_home: &Path,
embedded_network_policy: &codex_app_server_client::EmbeddedNetworkPolicy,
) -> std::io::Result<CloudConfigBundleLoader> {
cloud_config_bundle_loader_for_storage(
chatgpt_config_bundle_loader_for_storage(
embedded_network_policy
.bind_bootstrap_auth(app_server_target.auth_config_for_cloud_loader(
bootstrap_auth_config(codex_home, bootstrap_config)?,
@@ -1415,7 +1415,7 @@ async fn run_ratatui_app(
// bundle and rebuild config. This avoids missing newly available cloud-managed
// policy due to login status detection edge cases.
if show_login_screen && !uses_remote_workspace && !workload_identity_selected {
cloud_config_bundle = cloud_config_bundle_loader_for_storage(
cloud_config_bundle = chatgpt_config_bundle_loader_for_storage(
embedded_network_policy.bind_bootstrap_auth(initial_config.auth_config()),
/*enable_codex_api_key_env*/ false,
)
+2 -2
View File
@@ -1126,7 +1126,7 @@ mod tests {
use codex_app_server_client::InProcessClientStartArgs;
use codex_app_server_client::RemoteAppServerEndpoint;
use codex_arg0::Arg0DispatchPaths;
use codex_cloud_config::cloud_config_bundle_loader_for_storage;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage;
use codex_utils_absolute_path::AbsolutePathBuf;
use pretty_assertions::assert_eq;
use std::sync::Arc;
@@ -1234,7 +1234,7 @@ mod tests {
cli_overrides: Vec::new(),
loader_overrides: Default::default(),
strict_config: false,
cloud_config_bundle: cloud_config_bundle_loader_for_storage(
cloud_config_bundle: chatgpt_config_bundle_loader_for_storage(
auth_config.clone(),
/*enable_codex_api_key_env*/ false,
)
+1 -1
View File
@@ -508,7 +508,7 @@ pub(super) async fn run_main_inner(
cloud_config_bundle
} else {
startup_draft
.run_until(cloud_config_bundle_loader_for_storage(
.run_until(chatgpt_config_bundle_loader_for_storage(
embedded_network_policy.bind_bootstrap_auth(
app_server_target.auth_config_for_cloud_loader(config.auth_config()),
),
@@ -4,7 +4,7 @@
use anyhow::Context;
use anyhow::Result;
use anyhow::bail;
use codex_cloud_config::cloud_config_bundle_loader_for_storage_without_cache;
use codex_cloud_config::chatgpt_config_bundle_loader_for_storage_without_cache;
use codex_config::ConfigLoadOptions;
use codex_config::ConfigRequirementsToml;
use codex_config::WindowsSandboxImplementationToml;
@@ -75,7 +75,7 @@ pub(crate) fn validate_provisioning_request(
.context("load bootstrap configuration")?;
// Use the default cloud-policy endpoint unless managed requirements override it.
bootstrap_config.config_toml.chatgpt_base_url = None;
let cloud_config_bundle = cloud_config_bundle_loader_for_storage_without_cache(
let cloud_config_bundle = chatgpt_config_bundle_loader_for_storage_without_cache(
bootstrap_auth_config(codex_home, &bootstrap_config)
.context("resolve cloud configuration authentication")?,
/*enable_codex_api_key_env*/ false,