Preserve managed requirements during proxy bootstrap

This commit is contained in:
canvrno-oai
2026-06-11 12:41:19 -07:00
parent 9a9be5d074
commit 691b9fa3ce
3 changed files with 50 additions and 15 deletions

View File

@@ -1639,6 +1639,26 @@ pub async fn load_config_as_toml_with_cli_and_load_options(
cli_overrides: Vec<(String, TomlValue)>,
options: impl Into<ConfigLoadOptions>,
) -> std::io::Result<ConfigToml> {
let (config_toml, _) = load_config_toml_and_requirements_with_cli_and_load_options(
codex_home,
cwd,
cli_overrides,
options,
)
.await?;
Ok(config_toml)
}
/// Loads merged config TOML and its normalized managed requirements from one layer stack.
///
/// Bootstrap callers use this before cloud config is available so early
/// decisions can still enforce local managed requirements.
pub async fn load_config_toml_and_requirements_with_cli_and_load_options(
codex_home: &Path,
cwd: Option<&AbsolutePathBuf>,
cli_overrides: Vec<(String, TomlValue)>,
options: impl Into<ConfigLoadOptions>,
) -> std::io::Result<(ConfigToml, ConfigRequirements)> {
let config_layer_stack = load_config_layers_state(
LOCAL_FS.as_ref(),
codex_home,
@@ -1649,13 +1669,14 @@ pub async fn load_config_as_toml_with_cli_and_load_options(
)
.await?;
let requirements = config_layer_stack.requirements().clone();
let merged_toml = config_layer_stack.effective_config();
let cfg = deserialize_config_toml_with_base(merged_toml, codex_home).map_err(|e| {
tracing::error!("Failed to deserialize overridden config: {e}");
e
})?;
Ok(cfg)
Ok((cfg, requirements))
}
pub fn deserialize_config_toml_with_base(

View File

@@ -63,7 +63,7 @@ use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config::ConfigOverrides;
use codex_core::config::find_codex_home;
use codex_core::config::load_config_as_toml_with_cli_and_load_options;
use codex_core::config::load_config_toml_and_requirements_with_cli_and_load_options;
use codex_core::config::resolve_bootstrap_system_proxy_config;
use codex_core::config::resolve_oss_provider;
use codex_core::config::resolve_profile_v2_config_path;
@@ -334,7 +334,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
..Default::default()
};
let bootstrap_config_toml = load_config_toml_or_exit(
let (bootstrap_config_toml, bootstrap_requirements) = load_config_toml_or_exit(
&codex_home,
Some(&config_cwd),
cli_kv_overrides.clone(),
@@ -348,7 +348,10 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
.chatgpt_base_url
.clone()
.unwrap_or_else(|| "https://chatgpt.com/backend-api/".to_string());
let system_proxy_config = resolve_bootstrap_system_proxy_config(&bootstrap_config_toml);
let system_proxy_config = resolve_bootstrap_system_proxy_config(
&bootstrap_config_toml,
bootstrap_requirements.feature_requirements.as_ref(),
)?;
let auth_route_config =
bootstrap_auth_route_config_from_system_proxy_config(system_proxy_config.as_ref());
let cloud_config_bundle = cloud_config_bundle_loader_for_storage_with_auth_route_config(
@@ -371,7 +374,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
// The first load intentionally skips cloud config so we can read
// auth/base-url settings needed to fetch the bundle. If OSS mode
// needs a default provider from config, reload with the bundle.
config_toml_with_cloud_config = load_config_toml_or_exit(
let (reloaded_config_toml, _) = load_config_toml_or_exit(
&codex_home,
Some(&config_cwd),
cli_kv_overrides.clone(),
@@ -380,6 +383,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
cloud_config_bundle.clone(),
)
.await;
config_toml_with_cloud_config = reloaded_config_toml;
&config_toml_with_cloud_config
} else {
&bootstrap_config_toml
@@ -630,8 +634,11 @@ async fn load_config_toml_or_exit(
loader_overrides: LoaderOverrides,
strict_config: bool,
cloud_config_bundle: CloudConfigBundleLoader,
) -> codex_config::config_toml::ConfigToml {
match load_config_as_toml_with_cli_and_load_options(
) -> (
codex_config::config_toml::ConfigToml,
codex_config::ConfigRequirements,
) {
match load_config_toml_and_requirements_with_cli_and_load_options(
codex_home,
cwd,
cli_kv_overrides,
@@ -643,7 +650,7 @@ async fn load_config_toml_or_exit(
)
.await
{
Ok(config_toml) => config_toml,
Ok(config_toml_and_requirements) => config_toml_and_requirements,
Err(err) => {
let config_error = err
.get_ref()

View File

@@ -7,7 +7,7 @@ use crate::legacy_core::check_execpolicy_for_warnings;
use crate::legacy_core::config::Config;
use crate::legacy_core::config::ConfigBuilder;
use crate::legacy_core::config::ConfigOverrides;
use crate::legacy_core::config::load_config_as_toml_with_cli_and_load_options;
use crate::legacy_core::config::load_config_toml_and_requirements_with_cli_and_load_options;
use crate::legacy_core::config::resolve_bootstrap_system_proxy_config;
use crate::legacy_core::config::resolve_oss_provider;
use crate::legacy_core::config::resolve_profile_v2_config_path;
@@ -1008,7 +1008,7 @@ pub async fn run_main(
loader_overrides.user_config_profile = Some(profile_v2.clone());
}
let bootstrap_config_toml = load_config_toml_or_exit(
let (bootstrap_config_toml, bootstrap_requirements) = load_config_toml_or_exit(
&codex_home,
config_cwd.as_ref(),
cli_kv_overrides.clone(),
@@ -1022,7 +1022,10 @@ pub async fn run_main(
.chatgpt_base_url
.clone()
.unwrap_or_else(|| "https://chatgpt.com/backend-api/".to_string());
let system_proxy_config = resolve_bootstrap_system_proxy_config(&bootstrap_config_toml);
let system_proxy_config = resolve_bootstrap_system_proxy_config(
&bootstrap_config_toml,
bootstrap_requirements.feature_requirements.as_ref(),
)?;
let auth_route_config =
bootstrap_auth_route_config_from_system_proxy_config(system_proxy_config.as_ref());
let cloud_config_bundle = cloud_config_bundle_loader_for_storage_with_auth_route_config(
@@ -1049,7 +1052,7 @@ pub async fn run_main(
// The first load intentionally skips cloud config so we can read
// auth/base-url settings needed to fetch the bundle. If OSS mode
// needs a default provider from config, reload with the bundle.
config_toml_with_cloud_config = load_config_toml_or_exit(
let (reloaded_config_toml, _) = load_config_toml_or_exit(
&codex_home,
config_cwd.as_ref(),
cli_kv_overrides.clone(),
@@ -1058,6 +1061,7 @@ pub async fn run_main(
cloud_config_bundle.clone(),
)
.await;
config_toml_with_cloud_config = reloaded_config_toml;
&config_toml_with_cloud_config
} else {
&bootstrap_config_toml
@@ -2030,8 +2034,11 @@ async fn load_config_toml_or_exit(
loader_overrides: LoaderOverrides,
strict_config: bool,
cloud_config_bundle: CloudConfigBundleLoader,
) -> codex_config::config_toml::ConfigToml {
match load_config_as_toml_with_cli_and_load_options(
) -> (
codex_config::config_toml::ConfigToml,
codex_config::ConfigRequirements,
) {
match load_config_toml_and_requirements_with_cli_and_load_options(
codex_home,
cwd,
cli_kv_overrides,
@@ -2043,7 +2050,7 @@ async fn load_config_toml_or_exit(
)
.await
{
Ok(config_toml) => config_toml,
Ok(config_toml_and_requirements) => config_toml_and_requirements,
Err(err) => {
let config_error = err
.get_ref()