mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
9c3abcd46c
## Why Config loading had become split across crates: `codex-config` owned the config types and merge logic, while `codex-core` still owned the loader that assembled the layer stack. This change consolidates that responsibility in `codex-config`, so the crate that defines config behavior also owns how configs are discovered and loaded. To make that move possible without reintroducing the old dependency cycle, the shell-environment policy types and helpers that `codex-exec-server` needs now live in `codex-protocol` instead of flowing through `codex-config`. This also makes the migrated loader tests more deterministic on machines that already have managed or system Codex config installed by letting tests override the system config and requirements paths instead of reading the host's `/etc/codex`. ## What Changed - moved the config loader implementation from `codex-core` into `codex-config::loader` and deleted the old `core::config_loader` module instead of leaving a compatibility shim - moved shell-environment policy types and helpers into `codex-protocol`, then updated `codex-exec-server` and other downstream crates to import them from their new home - updated downstream callers to use loader/config APIs from `codex-config` - added test-only loader overrides for system config and requirements paths so loader-focused tests do not depend on host-managed config state - cleaned up now-unused dependency entries and platform-specific cfgs that were surfaced by post-push CI ## Testing - `cargo test -p codex-config` - `cargo test -p codex-core config_loader_tests::` - `cargo test -p codex-protocol -p codex-exec-server -p codex-cloud-requirements -p codex-rmcp-client --lib` - `cargo test --lib -p codex-app-server-client -p codex-exec` - `cargo test --no-run --lib -p codex-app-server` - `cargo test -p codex-linux-sandbox --lib` - `cargo shear` - `just bazel-lock-check` ## Notes - I did not chase unrelated full-suite failures outside the migrated loader surface. - `cargo test -p codex-core --lib` still hits unrelated proxy-sensitive failures on this machine, and Windows CI still shows unrelated long-running/timeouting test noise outside the loader migration itself.
123 lines
4.2 KiB
Rust
123 lines
4.2 KiB
Rust
use crate::config_types::EnvironmentVariablePattern;
|
|
use crate::config_types::ShellEnvironmentPolicy;
|
|
use crate::config_types::ShellEnvironmentPolicyInherit;
|
|
use std::collections::HashMap;
|
|
use std::collections::HashSet;
|
|
|
|
pub const CODEX_THREAD_ID_ENV_VAR: &str = "CODEX_THREAD_ID";
|
|
|
|
/// Construct a shell environment from the supplied process environment and
|
|
/// shell-environment policy.
|
|
pub fn create_env(
|
|
policy: &ShellEnvironmentPolicy,
|
|
thread_id: Option<&str>,
|
|
) -> HashMap<String, String> {
|
|
create_env_from_vars(std::env::vars(), policy, thread_id)
|
|
}
|
|
|
|
pub fn create_env_from_vars<I>(
|
|
vars: I,
|
|
policy: &ShellEnvironmentPolicy,
|
|
thread_id: Option<&str>,
|
|
) -> HashMap<String, String>
|
|
where
|
|
I: IntoIterator<Item = (String, String)>,
|
|
{
|
|
let mut env_map = populate_env(vars, policy, thread_id);
|
|
|
|
if cfg!(target_os = "windows") {
|
|
// This is a workaround to address the failures we are seeing in the
|
|
// following tests when run via Bazel on Windows:
|
|
//
|
|
// ```
|
|
// suite::shell_command::unicode_output::with_login
|
|
// suite::shell_command::unicode_output::without_login
|
|
// ```
|
|
//
|
|
// Currently, we can only reproduce these failures in CI, which makes
|
|
// iteration times long, so we include this quick fix for now to unblock
|
|
// getting the Windows Bazel build running.
|
|
if !env_map.keys().any(|k| k.eq_ignore_ascii_case("PATHEXT")) {
|
|
env_map.insert("PATHEXT".to_string(), ".COM;.EXE;.BAT;.CMD".to_string());
|
|
}
|
|
}
|
|
env_map
|
|
}
|
|
|
|
pub fn populate_env<I>(
|
|
vars: I,
|
|
policy: &ShellEnvironmentPolicy,
|
|
thread_id: Option<&str>,
|
|
) -> HashMap<String, String>
|
|
where
|
|
I: IntoIterator<Item = (String, String)>,
|
|
{
|
|
// Step 1 - determine the starting set of variables based on the
|
|
// `inherit` strategy.
|
|
let mut env_map: HashMap<String, String> = match policy.inherit {
|
|
ShellEnvironmentPolicyInherit::All => vars.into_iter().collect(),
|
|
ShellEnvironmentPolicyInherit::None => HashMap::new(),
|
|
ShellEnvironmentPolicyInherit::Core => {
|
|
let core_vars: HashSet<&str> = COMMON_CORE_VARS
|
|
.iter()
|
|
.copied()
|
|
.chain(PLATFORM_CORE_VARS.iter().copied())
|
|
.collect();
|
|
let is_core_var = |name: &str| {
|
|
if cfg!(target_os = "windows") {
|
|
core_vars
|
|
.iter()
|
|
.any(|allowed| allowed.eq_ignore_ascii_case(name))
|
|
} else {
|
|
core_vars.contains(name)
|
|
}
|
|
};
|
|
vars.into_iter().filter(|(k, _)| is_core_var(k)).collect()
|
|
}
|
|
};
|
|
|
|
let matches_any = |name: &str, patterns: &[EnvironmentVariablePattern]| -> bool {
|
|
patterns.iter().any(|pattern| pattern.matches(name))
|
|
};
|
|
|
|
// Step 2 - Apply the default exclude if not disabled.
|
|
if !policy.ignore_default_excludes {
|
|
let default_excludes = vec![
|
|
EnvironmentVariablePattern::new_case_insensitive("*KEY*"),
|
|
EnvironmentVariablePattern::new_case_insensitive("*SECRET*"),
|
|
EnvironmentVariablePattern::new_case_insensitive("*TOKEN*"),
|
|
];
|
|
env_map.retain(|k, _| !matches_any(k, &default_excludes));
|
|
}
|
|
|
|
// Step 3 - Apply custom excludes.
|
|
if !policy.exclude.is_empty() {
|
|
env_map.retain(|k, _| !matches_any(k, &policy.exclude));
|
|
}
|
|
|
|
// Step 4 - Apply user-provided overrides.
|
|
for (key, val) in &policy.r#set {
|
|
env_map.insert(key.clone(), val.clone());
|
|
}
|
|
|
|
// Step 5 - If include_only is non-empty, keep only the matching vars.
|
|
if !policy.include_only.is_empty() {
|
|
env_map.retain(|k, _| matches_any(k, &policy.include_only));
|
|
}
|
|
|
|
// Step 6 - Populate the thread ID environment variable when provided.
|
|
if let Some(thread_id) = thread_id {
|
|
env_map.insert(CODEX_THREAD_ID_ENV_VAR.to_string(), thread_id.to_string());
|
|
}
|
|
|
|
env_map
|
|
}
|
|
|
|
const COMMON_CORE_VARS: &[&str] = &["PATH", "SHELL", "TMPDIR", "TEMP", "TMP"];
|
|
|
|
#[cfg(target_os = "windows")]
|
|
const PLATFORM_CORE_VARS: &[&str] = &["PATHEXT", "USERNAME", "USERPROFILE"];
|
|
|
|
#[cfg(unix)]
|
|
const PLATFORM_CORE_VARS: &[&str] = &["HOME", "LANG", "LC_ALL", "LC_CTYPE", "LOGNAME", "USER"];
|