diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 410f22ece8..612ef2f6f0 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -6108,6 +6108,7 @@ impl CodexMessageProcessor { } }; let config_layer_stack = match load_config_layers_state( + LOCAL_FS.as_ref(), &self.config.codex_home, Some(cwd_abs.clone()), &cli_overrides, diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 5274d88664..43673de6a8 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -4987,6 +4987,7 @@ mod handlers { use crate::realtime_context::truncate_realtime_text_to_token_budget; use crate::realtime_conversation::REALTIME_USER_TEXT_PREFIX; use crate::realtime_conversation::prefix_realtime_v2_text; + use codex_exec_server::LOCAL_FS; use codex_features::Feature; use codex_utils_absolute_path::AbsolutePathBuf; @@ -5505,6 +5506,7 @@ mod handlers { } }; let config_layer_stack = match load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd_abs.clone()), empty_cli_overrides, diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 34002b129a..5b178ed476 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -44,6 +44,7 @@ use codex_config::types::SkillsConfig; use codex_config::types::ToolSuggestDiscoverableType; use codex_config::types::Tui; use codex_config::types::TuiNotificationSettings; +use codex_exec_server::LOCAL_FS; use codex_features::Feature; use codex_features::FeaturesToml; use codex_model_provider_info::LMSTUDIO_OSS_PROVIDER_ID; @@ -2065,6 +2066,7 @@ async fn managed_config_overrides_oauth_store_mode() -> anyhow::Result<()> { let cwd = codex_home.path().abs(); let config_layer_stack = load_config_layers_state( + LOCAL_FS.as_ref(), codex_home.path(), Some(cwd), &Vec::new(), @@ -2198,6 +2200,7 @@ async fn managed_config_wins_over_cli_overrides() -> anyhow::Result<()> { let cwd = codex_home.path().abs(); let config_layer_stack = load_config_layers_state( + LOCAL_FS.as_ref(), codex_home.path(), Some(cwd), &[("model".to_string(), TomlValue::String("cli".to_string()))], diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index c4217bdf2a..c953dfecfb 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -47,6 +47,7 @@ use codex_config::types::ToolSuggestDiscoverable; use codex_config::types::TuiNotificationSettings; use codex_config::types::UriBasedFileOpener; use codex_config::types::WindowsSandboxModeToml; +use codex_exec_server::LOCAL_FS; use codex_features::Feature; use codex_features::FeatureConfigSource; use codex_features::FeatureOverrides; @@ -689,6 +690,7 @@ impl ConfigBuilder { }; harness_overrides.cwd = Some(cwd.to_path_buf()); let config_layer_stack = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &cli_overrides, @@ -849,6 +851,7 @@ pub async fn load_config_as_toml_with_cli_overrides( cli_overrides: Vec<(String, TomlValue)>, ) -> std::io::Result { let config_layer_stack = load_config_layers_state( + LOCAL_FS.as_ref(), codex_home, cwd.cloned(), &cli_overrides, @@ -1019,6 +1022,7 @@ pub async fn load_global_mcp_servers( // MCP servers defined in in-repo .codex/ folders. let cwd: Option = None; let config_layer_stack = load_config_layers_state( + LOCAL_FS.as_ref(), codex_home, cwd, &cli_overrides, diff --git a/codex-rs/core/src/config/service.rs b/codex-rs/core/src/config/service.rs index 6c7f071f2b..51288e60b9 100644 --- a/codex-rs/core/src/config/service.rs +++ b/codex-rs/core/src/config/service.rs @@ -29,6 +29,7 @@ use codex_app_server_protocol::OverriddenMetadata; use codex_app_server_protocol::WriteStatus; use codex_config::CONFIG_TOML_FILE; use codex_config::config_toml::ConfigToml; +use codex_exec_server::LOCAL_FS; use codex_utils_absolute_path::AbsolutePathBuf; use serde_json::Value as JsonValue; use std::borrow::Cow; @@ -424,6 +425,7 @@ impl ConfigService { async fn load_thread_agnostic_config(&self) -> std::io::Result { let cwd: Option = None; load_config_layers_state( + LOCAL_FS.as_ref(), &self.codex_home, cwd, &self.cli_overrides, diff --git a/codex-rs/core/src/config_loader/README.md b/codex-rs/core/src/config_loader/README.md index 04b72e4ca1..44a514a10a 100644 --- a/codex-rs/core/src/config_loader/README.md +++ b/codex-rs/core/src/config_loader/README.md @@ -10,7 +10,7 @@ This module is the canonical place to **load and describe Codex configuration la Exported from `codex_core::config_loader`: -- `load_config_layers_state(codex_home, cwd_opt, cli_overrides, overrides, cloud_requirements) -> ConfigLayerStack` +- `load_config_layers_state(fs, codex_home, cwd_opt, cli_overrides, overrides, cloud_requirements) -> ConfigLayerStack` - `ConfigLayerStack` - `effective_config() -> toml::Value` - `origins() -> HashMap` @@ -38,18 +38,22 @@ computing the effective config and origins metadata. This is what Most callers want the effective config plus metadata: ```rust -use codex_core::config_loader::{load_config_layers_state, LoaderOverrides}; +use codex_core::config_loader::{ + CloudRequirementsLoader, LoaderOverrides, load_config_layers_state, +}; +use codex_exec_server::LOCAL_FS; use codex_utils_absolute_path::AbsolutePathBuf; use toml::Value as TomlValue; let cli_overrides: Vec<(String, TomlValue)> = Vec::new(); let cwd = AbsolutePathBuf::current_dir()?; let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &cli_overrides, LoaderOverrides::default(), - None, + CloudRequirementsLoader::default(), ).await?; let effective = layers.effective_config(); diff --git a/codex-rs/core/src/config_loader/layer_io.rs b/codex-rs/core/src/config_loader/layer_io.rs index af77bdafa5..6bd9a9130f 100644 --- a/codex-rs/core/src/config_loader/layer_io.rs +++ b/codex-rs/core/src/config_loader/layer_io.rs @@ -5,11 +5,11 @@ use super::macos::ManagedAdminConfigLayer; use super::macos::load_managed_admin_config_layer; use codex_config::config_error_from_toml; use codex_config::io_error_from_config_error; +use codex_exec_server::ExecutorFileSystem; use codex_utils_absolute_path::AbsolutePathBuf; use std::io; use std::path::Path; use std::path::PathBuf; -use tokio::fs; use toml::Value as TomlValue; #[cfg(unix)] @@ -36,6 +36,7 @@ pub(super) struct LoadedConfigLayers { } pub(super) async fn load_config_layers_internal( + fs: &dyn ExecutorFileSystem, codex_home: &Path, overrides: LoaderOverrides, ) -> io::Result { @@ -57,7 +58,7 @@ pub(super) async fn load_config_layers_internal( )?; let managed_config = - read_config_from_path(&managed_config_path, /*log_missing_as_info*/ false) + read_config_from_path(fs, &managed_config_path, /*log_missing_as_info*/ false) .await? .map(|managed_config| MangedConfigFromFile { managed_config, @@ -89,15 +90,16 @@ fn map_managed_admin_layer(layer: ManagedAdminConfigLayer) -> ManagedConfigFromM } pub(super) async fn read_config_from_path( - path: impl AsRef, + fs: &dyn ExecutorFileSystem, + path: &AbsolutePathBuf, log_missing_as_info: bool, ) -> io::Result> { - match fs::read_to_string(path.as_ref()).await { + match fs.read_file_text(path, /*sandbox*/ None).await { Ok(contents) => match toml::from_str::(&contents) { Ok(value) => Ok(Some(value)), Err(err) => { - tracing::error!("Failed to parse {}: {err}", path.as_ref().display()); - let config_error = config_error_from_toml(path.as_ref(), &contents, err.clone()); + tracing::error!("Failed to parse {}: {err}", path.as_path().display()); + let config_error = config_error_from_toml(path.as_path(), &contents, err.clone()); Err(io_error_from_config_error( io::ErrorKind::InvalidData, config_error, @@ -107,14 +109,14 @@ pub(super) async fn read_config_from_path( }, Err(err) if err.kind() == io::ErrorKind::NotFound => { if log_missing_as_info { - tracing::info!("{} not found, using defaults", path.as_ref().display()); + tracing::info!("{} not found, using defaults", path.as_path().display()); } else { - tracing::debug!("{} not found", path.as_ref().display()); + tracing::debug!("{} not found", path.as_path().display()); } Ok(None) } Err(err) => { - tracing::error!("Failed to read {}: {err}", path.as_ref().display()); + tracing::error!("Failed to read {}: {err}", path.as_path().display()); Err(err) } } diff --git a/codex-rs/core/src/config_loader/mod.rs b/codex-rs/core/src/config_loader/mod.rs index f7830b7089..9f30595a89 100644 --- a/codex-rs/core/src/config_loader/mod.rs +++ b/codex-rs/core/src/config_loader/mod.rs @@ -11,6 +11,7 @@ use codex_config::CONFIG_TOML_FILE; use codex_config::ConfigRequirementsWithSources; use codex_config::config_toml::ConfigToml; use codex_config::config_toml::ProjectConfig; +use codex_exec_server::ExecutorFileSystem; use codex_git_utils::resolve_root_git_project_for_trust; use codex_protocol::config_types::ApprovalsReviewer; use codex_protocol::config_types::SandboxMode; @@ -118,6 +119,7 @@ pub(crate) async fn first_layer_config_error_from_entries( /// thread-agnostic config loading (e.g., for the app server's `/config` /// endpoint) should `cwd` be `None`. pub async fn load_config_layers_state( + fs: &dyn ExecutorFileSystem, codex_home: &Path, cwd: Option, cli_overrides: &[(String, TomlValue)], @@ -142,11 +144,12 @@ pub async fn load_config_layers_state( // Honor the system requirements.toml location. let requirements_toml_file = system_requirements_toml_file()?; - load_requirements_toml(&mut config_requirements_toml, requirements_toml_file).await?; + load_requirements_toml(fs, &mut config_requirements_toml, &requirements_toml_file).await?; // Make a best-effort to support the legacy `managed_config.toml` as a // requirements specification. - let loaded_config_layers = layer_io::load_config_layers_internal(codex_home, overrides).await?; + let loaded_config_layers = + layer_io::load_config_layers_internal(fs, codex_home, overrides).await?; load_requirements_from_legacy_scheme( &mut config_requirements_toml, loaded_config_layers.clone(), @@ -173,7 +176,7 @@ pub async fn load_config_layers_state( // if it exists. let system_config_toml_file = system_config_toml_file()?; let system_layer = - load_config_toml_for_required_layer(&system_config_toml_file, |config_toml| { + load_config_toml_for_required_layer(fs, &system_config_toml_file, |config_toml| { ConfigLayerEntry::new( ConfigLayerSource::System { file: system_config_toml_file.clone(), @@ -188,7 +191,7 @@ pub async fn load_config_layers_state( // exists, but is malformed, then this error should be propagated to the // user. let user_file = AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, codex_home); - let user_layer = load_config_toml_for_required_layer(&user_file, |config_toml| { + let user_layer = load_config_toml_for_required_layer(fs, &user_file, |config_toml| { ConfigLayerEntry::new( ConfigLayerSource::User { file: user_file.clone(), @@ -222,6 +225,7 @@ pub async fn load_config_layers_state( } }; let project_trust_context = match project_trust_context( + fs, &merged_so_far, &cwd, &project_root_markers, @@ -247,6 +251,7 @@ pub async fn load_config_layers_state( } }; let project_layers = load_project_layers( + fs, &cwd, &project_trust_context.project_root, &project_trust_context, @@ -320,22 +325,23 @@ pub async fn load_config_layers_state( /// - If there is an error reading the file or parsing the TOML, returns an /// error. async fn load_config_toml_for_required_layer( - config_toml: impl AsRef, + fs: &dyn ExecutorFileSystem, + toml_file: &AbsolutePathBuf, create_entry: impl FnOnce(TomlValue) -> ConfigLayerEntry, ) -> io::Result { - let toml_file = config_toml.as_ref(); - let toml_value = match tokio::fs::read_to_string(toml_file).await { + let toml_value = match fs.read_file_text(toml_file, /*sandbox*/ None).await { Ok(contents) => { let config: TomlValue = toml::from_str(&contents).map_err(|err| { - let config_error = config_error_from_toml(toml_file, &contents, err.clone()); + let config_error = + config_error_from_toml(toml_file.as_path(), &contents, err.clone()); io_error_from_config_error(io::ErrorKind::InvalidData, config_error, Some(err)) })?; - let config_parent = toml_file.parent().ok_or_else(|| { + let config_parent = toml_file.as_path().parent().ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidData, format!( "Config file {} has no parent directory", - toml_file.display() + toml_file.as_path().display() ), ) })?; @@ -347,7 +353,10 @@ async fn load_config_toml_for_required_layer( } else { Err(io::Error::new( e.kind(), - format!("Failed to read config file {}: {e}", toml_file.display()), + format!( + "Failed to read config file {}: {e}", + toml_file.as_path().display() + ), )) } } @@ -360,12 +369,14 @@ async fn load_config_toml_for_required_layer( /// `requirements.toml` location to `config_requirements_toml` by filling in /// any unset fields. async fn load_requirements_toml( + fs: &dyn ExecutorFileSystem, config_requirements_toml: &mut ConfigRequirementsWithSources, - requirements_toml_file: impl AsRef, + requirements_toml_file: &AbsolutePathBuf, ) -> io::Result<()> { - let requirements_toml_file = - AbsolutePathBuf::from_absolute_path(requirements_toml_file.as_ref())?; - match tokio::fs::read_to_string(&requirements_toml_file).await { + match fs + .read_file_text(requirements_toml_file, /*sandbox*/ None) + .await + { Ok(contents) => { let requirements_config: ConfigRequirementsToml = toml::from_str(&contents).map_err(|e| { @@ -373,7 +384,7 @@ async fn load_requirements_toml( io::ErrorKind::InvalidData, format!( "Error parsing requirements file {}: {e}", - requirements_toml_file.as_ref().display(), + requirements_toml_file.as_path().display(), ), ) })?; @@ -390,7 +401,7 @@ async fn load_requirements_toml( e.kind(), format!( "Failed to read requirements file {}: {e}", - requirements_toml_file.as_ref().display(), + requirements_toml_file.as_path().display(), ), )); } @@ -632,6 +643,7 @@ fn project_layer_entry( } async fn project_trust_context( + fs: &dyn ExecutorFileSystem, merged_config: &TomlValue, cwd: &AbsolutePathBuf, project_root_markers: &[String], @@ -646,7 +658,7 @@ async fn project_trust_context( .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))? }; - let project_root = find_project_root(cwd, project_root_markers).await?; + let project_root = find_project_root(fs, cwd, project_root_markers).await?; let projects = project_trust_config.projects.unwrap_or_default(); let project_root_key = project_trust_key(project_root.as_path()); @@ -742,6 +754,7 @@ fn copy_shape_from_original(original: &TomlValue, resolved: &TomlValue) -> TomlV } async fn find_project_root( + fs: &dyn ExecutorFileSystem, cwd: &AbsolutePathBuf, project_root_markers: &[String], ) -> io::Result { @@ -749,11 +762,15 @@ async fn find_project_root( return Ok(cwd.clone()); } - for ancestor in cwd.as_path().ancestors() { + for ancestor in cwd.ancestors() { for marker in project_root_markers { let marker_path = ancestor.join(marker); - if tokio::fs::metadata(&marker_path).await.is_ok() { - return AbsolutePathBuf::from_absolute_path(ancestor); + if fs + .get_metadata(&marker_path, /*sandbox*/ None) + .await + .is_ok() + { + return Ok(ancestor); } } } @@ -766,6 +783,7 @@ async fn find_project_root( /// starting from folders closest to `project_root` (which is the lowest /// precedence) to those closest to `cwd` (which is the highest precedence). async fn load_project_layers( + fs: &dyn ExecutorFileSystem, cwd: &AbsolutePathBuf, project_root: &AbsolutePathBuf, trust_context: &ProjectTrustContext, @@ -775,13 +793,12 @@ async fn load_project_layers( let codex_home_normalized = normalize_path(codex_home_abs.as_path()).unwrap_or_else(|_| codex_home_abs.to_path_buf()); let mut dirs = cwd - .as_path() .ancestors() .scan(false, |done, a| { if *done { None } else { - if a == project_root.as_path() { + if &a == project_root { *done = true; } Some(a) @@ -792,25 +809,24 @@ async fn load_project_layers( let mut layers = Vec::new(); for dir in dirs { - let dot_codex = dir.join(".codex"); - if !tokio::fs::metadata(&dot_codex) + let dot_codex_abs = dir.join(".codex"); + if !fs + .get_metadata(&dot_codex_abs, /*sandbox*/ None) .await - .map(|meta| meta.is_dir()) + .map(|metadata| metadata.is_directory) .unwrap_or(false) { continue; } - let layer_dir = AbsolutePathBuf::from_absolute_path(dir)?; - let decision = trust_context.decision_for_dir(&layer_dir); - let dot_codex_abs = AbsolutePathBuf::from_absolute_path(&dot_codex)?; + let decision = trust_context.decision_for_dir(&dir); let dot_codex_normalized = normalize_path(dot_codex_abs.as_path()).unwrap_or_else(|_| dot_codex_abs.to_path_buf()); if dot_codex_abs == codex_home_abs || dot_codex_normalized == codex_home_normalized { continue; } let config_file = dot_codex_abs.join(CONFIG_TOML_FILE); - match tokio::fs::read_to_string(&config_file).await { + match fs.read_file_text(&config_file, /*sandbox*/ None).await { Ok(contents) => { let config: TomlValue = match toml::from_str(&contents) { Ok(config) => config, @@ -827,7 +843,7 @@ async fn load_project_layers( layers.push(project_layer_entry( trust_context, &dot_codex_abs, - &layer_dir, + &dir, TomlValue::Table(toml::map::Map::new()), /*config_toml_exists*/ true, )); @@ -839,7 +855,7 @@ async fn load_project_layers( let entry = project_layer_entry( trust_context, &dot_codex_abs, - &layer_dir, + &dir, config, /*config_toml_exists*/ true, ); @@ -853,7 +869,7 @@ async fn load_project_layers( layers.push(project_layer_entry( trust_context, &dot_codex_abs, - &layer_dir, + &dir, TomlValue::Table(toml::map::Map::new()), /*config_toml_exists*/ false, )); diff --git a/codex-rs/core/src/config_loader/tests.rs b/codex-rs/core/src/config_loader/tests.rs index ed69682e86..c706e91062 100644 --- a/codex-rs/core/src/config_loader/tests.rs +++ b/codex-rs/core/src/config_loader/tests.rs @@ -16,6 +16,7 @@ use crate::config_loader::version_for_toml; use codex_config::CONFIG_TOML_FILE; use codex_config::config_toml::ConfigToml; use codex_config::config_toml::ProjectConfig; +use codex_exec_server::LOCAL_FS; use codex_protocol::config_types::TrustLevel; use codex_protocol::config_types::WebSearchMode; use codex_protocol::protocol::AskForApproval; @@ -92,6 +93,7 @@ async fn returns_config_error_for_invalid_user_config_toml() { let cwd = AbsolutePathBuf::try_from(tmp.path()).expect("cwd"); let err = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(cwd), &[] as &[(String, TomlValue)], @@ -119,6 +121,7 @@ async fn returns_config_error_for_invalid_managed_config_toml() { let cwd = AbsolutePathBuf::try_from(tmp.path()).expect("cwd"); let err = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(cwd), &[] as &[(String, TomlValue)], @@ -203,6 +206,7 @@ extra = true let cwd = AbsolutePathBuf::try_from(tmp.path()).expect("cwd"); let state = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(cwd), &[] as &[(String, TomlValue)], @@ -235,6 +239,7 @@ async fn returns_empty_when_all_layers_missing() { let cwd = AbsolutePathBuf::try_from(tmp.path()).expect("cwd"); let layers = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(cwd), &[] as &[(String, TomlValue)], @@ -327,6 +332,7 @@ flag = false let cwd = AbsolutePathBuf::try_from(tmp.path()).expect("cwd"); let state = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(cwd), &[] as &[(String, TomlValue)], @@ -428,6 +434,7 @@ allowed_sandbox_modes = ["read-only"] ); let state = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(AbsolutePathBuf::try_from(tmp.path())?), &[] as &[(String, TomlValue)], @@ -489,6 +496,7 @@ allowed_approval_policies = ["never"] ); let state = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(AbsolutePathBuf::try_from(tmp.path())?), &[] as &[(String, TomlValue)], @@ -529,8 +537,14 @@ personality = true ) .await?; + let requirements_file = AbsolutePathBuf::try_from(requirements_file)?; let mut config_requirements_toml = ConfigRequirementsWithSources::default(); - load_requirements_toml(&mut config_requirements_toml, &requirements_file).await?; + load_requirements_toml( + LOCAL_FS.as_ref(), + &mut config_requirements_toml, + &requirements_file, + ) + .await?; assert_eq!( config_requirements_toml @@ -620,6 +634,7 @@ allowed_approval_policies = ["on-request"] ), ); let state = load_config_layers_state( + LOCAL_FS.as_ref(), tmp.path(), Some(AbsolutePathBuf::try_from(tmp.path())?), &[] as &[(String, TomlValue)], @@ -691,7 +706,12 @@ allowed_approval_policies = ["on-request"] guardian_policy_config: None, }, ); - load_requirements_toml(&mut config_requirements_toml, &requirements_file).await?; + load_requirements_toml( + LOCAL_FS.as_ref(), + &mut config_requirements_toml, + &AbsolutePathBuf::try_from(requirements_file)?, + ) + .await?; assert_eq!( config_requirements_toml @@ -735,6 +755,7 @@ async fn load_config_layers_includes_cloud_requirements() -> anyhow::Result<()> let cloud_requirements = CloudRequirementsLoader::new(async move { Ok(Some(requirements)) }); let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &[] as &[(String, TomlValue)], @@ -771,6 +792,7 @@ async fn load_config_layers_fails_when_cloud_requirements_loader_fails() -> anyh let cwd = AbsolutePathBuf::from_absolute_path(tmp.path())?; let err = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &[] as &[(String, TomlValue)], @@ -823,6 +845,7 @@ async fn project_layers_prefer_closest_cwd() -> std::io::Result<()> { .await?; let cwd = AbsolutePathBuf::from_absolute_path(&nested)?; let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &[] as &[(String, TomlValue)], @@ -967,6 +990,7 @@ async fn project_layer_is_added_when_dot_codex_exists_without_config_toml() -> s .await?; let cwd = AbsolutePathBuf::from_absolute_path(&nested)?; let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &[] as &[(String, TomlValue)], @@ -1006,6 +1030,7 @@ async fn codex_home_is_not_loaded_as_project_layer_from_home_dir() -> std::io::R let cwd = AbsolutePathBuf::from_absolute_path(&home_dir)?; let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &[] as &[(String, TomlValue)], @@ -1062,6 +1087,7 @@ async fn codex_home_within_project_tree_is_not_double_loaded() -> std::io::Resul let cwd = AbsolutePathBuf::from_absolute_path(&nested)?; let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &project_dot_codex, Some(cwd), &[] as &[(String, TomlValue)], @@ -1132,6 +1158,7 @@ async fn project_layers_disabled_when_untrusted_or_unknown() -> std::io::Result< .await?; let layers_untrusted = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home_untrusted, Some(cwd.clone()), &[] as &[(String, TomlValue)], @@ -1170,6 +1197,7 @@ async fn project_layers_disabled_when_untrusted_or_unknown() -> std::io::Result< .await?; let layers_unknown = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home_unknown, Some(cwd), &[] as &[(String, TomlValue)], @@ -1328,6 +1356,7 @@ async fn invalid_project_config_ignored_when_untrusted_or_unknown() -> std::io:: } let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd.clone()), &[] as &[(String, TomlValue)], @@ -1390,6 +1419,7 @@ async fn cli_overrides_with_relative_paths_do_not_break_trust_check() -> std::io )]; load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &cli_overrides, @@ -1432,6 +1462,7 @@ async fn project_root_markers_supports_alternate_markers() -> std::io::Result<() let cwd = AbsolutePathBuf::from_absolute_path(&nested)?; let layers = load_config_layers_state( + LOCAL_FS.as_ref(), &codex_home, Some(cwd), &[] as &[(String, TomlValue)], diff --git a/codex-rs/core/src/network_proxy_loader.rs b/codex-rs/core/src/network_proxy_loader.rs index b5eaf26b7b..af4280bfb4 100644 --- a/codex-rs/core/src/network_proxy_loader.rs +++ b/codex-rs/core/src/network_proxy_loader.rs @@ -16,6 +16,7 @@ use codex_config::CONFIG_TOML_FILE; use codex_config::permissions_toml::NetworkToml; use codex_config::permissions_toml::PermissionsToml; use codex_config::permissions_toml::overlay_network_domain_permissions; +use codex_exec_server::LOCAL_FS; use codex_network_proxy::ConfigReloader; use codex_network_proxy::ConfigState; use codex_network_proxy::NetworkProxyConfig; @@ -46,6 +47,7 @@ async fn build_config_state_with_mtimes() -> Result<(ConfigState, Vec