Add an override to skip project configuration (#38647)

## What changed

- Add `LoaderOverrides::ignore_project_config` to bypass project-root discovery and all project configuration layers.
- Keep other configuration sources, including session overrides and cloud configuration, active when the override is set.

## Testing

- Add a config loader test that verifies project configuration is not loaded or parsed while session and cloud values remain effective.

GitOrigin-RevId: b9aa44de526354fad6b900d6ae8d9b5fb8f700bb
This commit is contained in:
Michael Zeng
2026-08-14 20:53:22 +00:00
committed by copyberry
parent cce33123a1
commit b8aa9e9a01
3 changed files with 67 additions and 1 deletions
+2 -1
View File
@@ -182,6 +182,7 @@ pub async fn load_config_layers_state(
let active_user_profile = overrides.user_config_profile.clone();
let ignore_managed_requirements = overrides.ignore_managed_requirements;
let ignore_user_config = overrides.ignore_user_config;
let ignore_project_config = overrides.ignore_project_config;
let ignore_user_and_project_exec_policy_rules =
overrides.ignore_user_and_project_exec_policy_rules;
let mut requirements_layers = Vec::new();
@@ -353,7 +354,7 @@ pub async fn load_config_layers_state(
}
let mut startup_warnings = None;
if let Some(cwd) = cwd {
if !ignore_project_config && let Some(cwd) = cwd {
let mut merged_so_far = TomlValue::Table(toml::map::Map::new());
for layer in &layers {
merge_toml_values(&mut merged_so_far, &layer.config);
+3
View File
@@ -52,6 +52,8 @@ pub struct LoaderOverrides {
/// Remote app servers own their authentication policy independently.
pub ignore_login_requirements: bool,
pub ignore_user_config: bool,
/// Skip project-root discovery and all project configuration layers.
pub ignore_project_config: bool,
pub ignore_user_and_project_exec_policy_rules: bool,
//TODO(gt): Add a macos_ prefix to this field and remove the target_os check.
#[cfg(target_os = "macos")]
@@ -75,6 +77,7 @@ impl LoaderOverrides {
ignore_managed_requirements: false,
ignore_login_requirements: false,
ignore_user_config: false,
ignore_project_config: false,
ignore_user_and_project_exec_policy_rules: false,
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
@@ -218,6 +218,68 @@ invalid = ["#,
Ok(())
}
#[tokio::test]
async fn ignore_project_config_skips_project_discovery() -> std::io::Result<()> {
let tmp = tempdir().expect("tempdir");
let codex_home = tmp.path().join("home");
let workspace = tmp.path().join("workspace");
tokio::fs::create_dir_all(codex_home.as_path()).await?;
tokio::fs::create_dir_all(workspace.join(".git")).await?;
make_config_for_test(
&codex_home,
&workspace,
TrustLevel::Trusted,
/*project_root_markers*/ None,
)
.await?;
let project_config_dir = workspace.join(".codex");
tokio::fs::create_dir_all(&project_config_dir).await?;
tokio::fs::write(
project_config_dir.join(CONFIG_TOML_FILE),
r#"model = "from-project"
invalid = ["#,
)
.await?;
let cwd = AbsolutePathBuf::from_absolute_path(&workspace)?;
let layers = load_config_layers_state(
LOCAL_FS.as_ref(),
&codex_home,
Some(cwd),
&[(
"model".to_string(),
TomlValue::String("from-session".to_string()),
)],
ConfigLoadOptions {
loader_overrides: LoaderOverrides {
ignore_project_config: true,
..LoaderOverrides::without_managed_config_for_tests()
},
cloud_config_bundle: CloudConfigBundleFixture::loader_with_enterprise_config(
r#"review_model = "from-cloud""#,
),
..Default::default()
},
&codex_config::NoopThreadConfigLoader,
)
.await?;
assert!(
layers
.layers_low_to_high()
.all(|layer| !matches!(layer.name, ConfigLayerSource::Project { .. }))
);
assert_eq!(
layers.effective_config().get("model"),
Some(&TomlValue::String("from-session".to_string()))
);
assert_eq!(
layers.effective_config().get("review_model"),
Some(&TomlValue::String("from-cloud".to_string()))
);
Ok(())
}
#[tokio::test]
async fn ignore_rules_marks_config_stack_for_exec_policy_rule_skip() -> std::io::Result<()> {
let tmp = tempdir().expect("tempdir");