Compare commits

...

1 Commits

Author SHA1 Message Date
pakrym-oai
90cd4f3557 Pass filesystem abstraction into config loading 2026-04-16 13:08:32 -07:00
10 changed files with 114 additions and 47 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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()))],

View File

@@ -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<ConfigToml> {
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<AbsolutePathBuf> = None;
let config_layer_stack = load_config_layers_state(
LOCAL_FS.as_ref(),
codex_home,
cwd,
&cli_overrides,

View File

@@ -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<ConfigLayerStack> {
let cwd: Option<AbsolutePathBuf> = None;
load_config_layers_state(
LOCAL_FS.as_ref(),
&self.codex_home,
cwd,
&self.cli_overrides,

View File

@@ -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<String, ConfigLayerMetadata>`
@@ -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();

View File

@@ -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<LoadedConfigLayers> {
@@ -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<Path>,
fs: &dyn ExecutorFileSystem,
path: &AbsolutePathBuf,
log_missing_as_info: bool,
) -> io::Result<Option<TomlValue>> {
match fs::read_to_string(path.as_ref()).await {
match fs.read_file_text(path, /*sandbox*/ None).await {
Ok(contents) => match toml::from_str::<TomlValue>(&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)
}
}

View File

@@ -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<AbsolutePathBuf>,
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<Path>,
fs: &dyn ExecutorFileSystem,
toml_file: &AbsolutePathBuf,
create_entry: impl FnOnce(TomlValue) -> ConfigLayerEntry,
) -> io::Result<ConfigLayerEntry> {
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<Path>,
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<AbsolutePathBuf> {
@@ -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,
));

View File

@@ -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)],

View File

@@ -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<LayerMtime
let cli_overrides = Vec::new();
let overrides = LoaderOverrides::default();
let config_layer_stack = load_config_layers_state(
LOCAL_FS.as_ref(),
&codex_home,
/*cwd*/ None,
&cli_overrides,