mirror of
https://github.com/openai/codex.git
synced 2026-05-03 19:06:58 +00:00
## 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.
206 lines
6.8 KiB
Rust
206 lines
6.8 KiB
Rust
#![cfg(not(target_os = "windows"))]
|
|
|
|
use anyhow::Ok;
|
|
use codex_app_server_protocol::ConfigLayerSource;
|
|
use codex_config::ConfigLayerEntry;
|
|
use codex_config::ConfigLayerStack;
|
|
use codex_config::ConfigRequirements;
|
|
use codex_config::ConfigRequirementsToml;
|
|
use codex_features::Feature;
|
|
use codex_protocol::protocol::DeprecationNoticeEvent;
|
|
use codex_protocol::protocol::EventMsg;
|
|
use core_test_support::responses::start_mock_server;
|
|
use core_test_support::skip_if_no_network;
|
|
use core_test_support::test_absolute_path;
|
|
use core_test_support::test_codex::TestCodex;
|
|
use core_test_support::test_codex::test_codex;
|
|
use core_test_support::wait_for_event_match;
|
|
use pretty_assertions::assert_eq;
|
|
use std::collections::BTreeMap;
|
|
use toml::Value as TomlValue;
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn emits_deprecation_notice_for_legacy_feature_flag() -> anyhow::Result<()> {
|
|
skip_if_no_network!(Ok(()));
|
|
|
|
let server = start_mock_server().await;
|
|
|
|
let mut builder = test_codex().with_config(|config| {
|
|
let mut features = config.features.get().clone();
|
|
features.enable(Feature::UnifiedExec);
|
|
features
|
|
.record_legacy_usage_force("use_experimental_unified_exec_tool", Feature::UnifiedExec);
|
|
config
|
|
.features
|
|
.set(features)
|
|
.expect("test config should allow managed feature metadata updates");
|
|
config.use_experimental_unified_exec_tool = true;
|
|
});
|
|
|
|
let TestCodex { codex, .. } = builder.build(&server).await?;
|
|
|
|
let notice = wait_for_event_match(&codex, |event| match event {
|
|
EventMsg::DeprecationNotice(ev) => Some(ev.clone()),
|
|
_ => None,
|
|
})
|
|
.await;
|
|
|
|
let DeprecationNoticeEvent { summary, details } = notice;
|
|
assert_eq!(
|
|
summary,
|
|
"`[features].use_experimental_unified_exec_tool` is deprecated. Use `[features].unified_exec` instead.".to_string(),
|
|
);
|
|
assert_eq!(
|
|
details.as_deref(),
|
|
Some(
|
|
"Enable it with `--enable unified_exec` or `[features].unified_exec` in config.toml. See https://developers.openai.com/codex/config-basic#feature-flags for details."
|
|
),
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn emits_deprecation_notice_for_experimental_instructions_file() -> anyhow::Result<()> {
|
|
skip_if_no_network!(Ok(()));
|
|
|
|
let server = start_mock_server().await;
|
|
|
|
let mut builder = test_codex().with_config(|config| {
|
|
let mut table = toml::map::Map::new();
|
|
table.insert(
|
|
"experimental_instructions_file".to_string(),
|
|
TomlValue::String("legacy.md".to_string()),
|
|
);
|
|
let config_layer = ConfigLayerEntry::new(
|
|
ConfigLayerSource::User {
|
|
file: test_absolute_path("/tmp/config.toml"),
|
|
},
|
|
TomlValue::Table(table),
|
|
);
|
|
let config_layer_stack = ConfigLayerStack::new(
|
|
vec![config_layer],
|
|
ConfigRequirements::default(),
|
|
ConfigRequirementsToml::default(),
|
|
)
|
|
.expect("build config layer stack");
|
|
config.config_layer_stack = config_layer_stack;
|
|
});
|
|
|
|
let TestCodex { codex, .. } = builder.build(&server).await?;
|
|
|
|
let notice = wait_for_event_match(&codex, |event| match event {
|
|
EventMsg::DeprecationNotice(ev)
|
|
if ev.summary.contains("experimental_instructions_file") =>
|
|
{
|
|
Some(ev.clone())
|
|
}
|
|
_ => None,
|
|
})
|
|
.await;
|
|
|
|
let DeprecationNoticeEvent { summary, details } = notice;
|
|
assert_eq!(
|
|
summary,
|
|
"`experimental_instructions_file` is deprecated and ignored. Use `model_instructions_file` instead."
|
|
.to_string(),
|
|
);
|
|
assert_eq!(
|
|
details.as_deref(),
|
|
Some(
|
|
"Move the setting to `model_instructions_file` in config.toml (or under a profile) to load instructions from a file."
|
|
),
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn emits_deprecation_notice_for_web_search_feature_flag_values() -> anyhow::Result<()> {
|
|
skip_if_no_network!(Ok(()));
|
|
|
|
for enabled in [true, false] {
|
|
let server = start_mock_server().await;
|
|
|
|
let mut builder = test_codex().with_config(move |config| {
|
|
let mut entries = BTreeMap::new();
|
|
entries.insert("web_search_request".to_string(), enabled);
|
|
let mut features = config.features.get().clone();
|
|
features.apply_map(&entries);
|
|
config
|
|
.features
|
|
.set(features)
|
|
.expect("test config should allow managed feature map updates");
|
|
});
|
|
|
|
let TestCodex { codex, .. } = builder.build(&server).await?;
|
|
|
|
let notice = wait_for_event_match(&codex, |event| match event {
|
|
EventMsg::DeprecationNotice(ev)
|
|
if ev.summary.contains("[features].web_search_request") =>
|
|
{
|
|
Some(ev.clone())
|
|
}
|
|
_ => None,
|
|
})
|
|
.await;
|
|
|
|
let DeprecationNoticeEvent { summary, details } = notice;
|
|
assert_eq!(
|
|
summary,
|
|
"`[features].web_search_request` is deprecated because web search is enabled by default."
|
|
.to_string(),
|
|
);
|
|
assert_eq!(
|
|
details.as_deref(),
|
|
Some(
|
|
"Set `web_search` to `\"live\"`, `\"cached\"`, or `\"disabled\"` at the top level (or under a profile) in config.toml if you want to override it."
|
|
),
|
|
);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn emits_deprecation_notice_for_use_legacy_landlock() -> anyhow::Result<()> {
|
|
skip_if_no_network!(Ok(()));
|
|
|
|
let server = start_mock_server().await;
|
|
|
|
let mut builder = test_codex().with_config(|config| {
|
|
let mut entries = BTreeMap::new();
|
|
entries.insert("use_legacy_landlock".to_string(), true);
|
|
let mut features = config.features.get().clone();
|
|
features.apply_map(&entries);
|
|
config
|
|
.features
|
|
.set(features)
|
|
.expect("test config should allow managed feature map updates");
|
|
});
|
|
|
|
let TestCodex { codex, .. } = builder.build(&server).await?;
|
|
|
|
let notice = wait_for_event_match(&codex, |event| match event {
|
|
EventMsg::DeprecationNotice(ev)
|
|
if ev.summary.contains("[features].use_legacy_landlock") =>
|
|
{
|
|
Some(ev.clone())
|
|
}
|
|
_ => None,
|
|
})
|
|
.await;
|
|
|
|
let DeprecationNoticeEvent { summary, details } = notice;
|
|
assert_eq!(
|
|
summary,
|
|
"`[features].use_legacy_landlock` is deprecated and will be removed soon.".to_string(),
|
|
);
|
|
assert_eq!(
|
|
details.as_deref(),
|
|
Some("Remove this setting to stop opting into the legacy Linux sandbox behavior."),
|
|
);
|
|
|
|
Ok(())
|
|
}
|