From 646f9baf7eb7a0ea9a2fc9c85af1e79eb3751df9 Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Thu, 7 May 2026 00:20:39 +0300 Subject: [PATCH] Resolve config paths during lenient projection --- codex-rs/config/src/loader/mod.rs | 10 ++++-- .../core/src/config/config_loader_tests.rs | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/codex-rs/config/src/loader/mod.rs b/codex-rs/config/src/loader/mod.rs index f5f8ec44e5..42b80328fa 100644 --- a/codex-rs/config/src/loader/mod.rs +++ b/codex-rs/config/src/loader/mod.rs @@ -15,6 +15,7 @@ use crate::diagnostics::ConfigError; use crate::diagnostics::config_error_from_toml; use crate::diagnostics::first_layer_config_error_from_entries as typed_first_layer_config_error_from_entries; use crate::diagnostics::io_error_from_config_error; +use crate::lenient::deserialize_with_enum_warnings; use crate::merge::merge_toml_values; use crate::overrides::build_cli_overrides_layer; use crate::project_root_markers::default_project_root_markers; @@ -870,9 +871,14 @@ pub fn resolve_relative_paths_in_config_toml( base_dir: &Path, ) -> io::Result { // Use the serialize/deserialize round-trip to convert the - // `toml::Value` into a `ConfigToml` with `AbsolutePath + // `toml::Value` into a `ConfigToml` with `AbsolutePathBuf` fields resolved + // by the guard. Invalid enum values are ignored only for this typed + // projection; copy_shape_from_original preserves them in the raw layer so + // the final config load can still surface the startup warning. let _guard = AbsolutePathBufGuard::new(base_dir); - let Ok(resolved) = value_from_config_toml.clone().try_into::() else { + let Ok((_sanitized, resolved, _enum_warnings)) = + deserialize_with_enum_warnings::(value_from_config_toml.clone()) + else { return Ok(value_from_config_toml); }; drop(_guard); diff --git a/codex-rs/core/src/config/config_loader_tests.rs b/codex-rs/core/src/config/config_loader_tests.rs index 3b1bc65854..78649b18b8 100644 --- a/codex-rs/core/src/config/config_loader_tests.rs +++ b/codex-rs/core/src/config/config_loader_tests.rs @@ -175,6 +175,39 @@ theme = "loudly" Ok(()) } +#[tokio::test] +async fn invalid_enum_values_do_not_poison_relative_path_resolution() -> anyhow::Result<()> { + let tmp = tempdir().expect("tempdir"); + std::fs::write( + tmp.path().join(CONFIG_TOML_FILE), + r#" +model_instructions_file = "instructions.md" +sandbox_mode = "make-it-so" +"#, + ) + .expect("write config"); + std::fs::write(tmp.path().join("instructions.md"), "resolved instructions") + .expect("write instructions"); + + let config = ConfigBuilder::default() + .codex_home(tmp.path().to_path_buf()) + .harness_overrides(ConfigOverrides { + cwd: Some(tmp.path().to_path_buf()), + ..Default::default() + }) + .build() + .await?; + + assert_eq!( + (config.base_instructions.as_deref(), config.startup_warnings,), + ( + Some("resolved instructions"), + vec!["Ignoring invalid config value at sandbox_mode: \"make-it-so\"".to_string()], + ) + ); + Ok(()) +} + #[tokio::test] async fn invalid_untagged_notification_value_does_not_delete_tui_table() -> anyhow::Result<()> { let tmp = tempdir().expect("tempdir");