chore: migrate from Config::load_from_base_config_with_overrides to ConfigBuilder

This commit is contained in:
Michael Bolin
2025-12-18 11:44:44 -08:00
parent b903285746
commit 948a720e9d
16 changed files with 524 additions and 185 deletions
+22 -14
View File
@@ -636,8 +636,8 @@ mod tests {
use crate::auth::storage::FileAuthStorage;
use crate::auth::storage::get_auth_file;
use crate::config::Config;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
use crate::config::ConfigBuilder;
use crate::config_loader::LoaderOverrides;
use crate::token_data::IdTokenInfo;
use crate::token_data::KnownPlan as InternalKnownPlan;
use crate::token_data::PlanType as InternalPlanType;
@@ -862,22 +862,30 @@ mod tests {
Ok(fake_jwt)
}
fn build_config(
async fn build_config(
codex_home: &Path,
forced_login_method: Option<ForcedLoginMethod>,
forced_chatgpt_workspace_id: Option<String>,
) -> Config {
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.to_path_buf(),
)
.expect("config should load");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.to_path_buf())
.loader_overrides(test_loader_overrides(codex_home))
.build()
.await
.expect("config should load");
config.forced_login_method = forced_login_method;
config.forced_chatgpt_workspace_id = forced_chatgpt_workspace_id;
config
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
/// Use sparingly.
/// TODO (gpeal): replace this with an injectable env var provider.
#[cfg(test)]
@@ -915,7 +923,7 @@ mod tests {
login_with_api_key(codex_home.path(), "sk-test", AuthCredentialsStoreMode::File)
.expect("seed api key");
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::Chatgpt), None);
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::Chatgpt), None).await;
let err = super::enforce_login_restrictions(&config)
.await
@@ -941,7 +949,7 @@ mod tests {
)
.expect("failed to write auth file");
let config = build_config(codex_home.path(), None, Some("org_mine".to_string()));
let config = build_config(codex_home.path(), None, Some("org_mine".to_string())).await;
let err = super::enforce_login_restrictions(&config)
.await
@@ -967,7 +975,7 @@ mod tests {
)
.expect("failed to write auth file");
let config = build_config(codex_home.path(), None, Some("org_mine".to_string()));
let config = build_config(codex_home.path(), None, Some("org_mine".to_string())).await;
super::enforce_login_restrictions(&config)
.await
@@ -985,7 +993,7 @@ mod tests {
login_with_api_key(codex_home.path(), "sk-test", AuthCredentialsStoreMode::File)
.expect("seed api key");
let config = build_config(codex_home.path(), None, Some("org_mine".to_string()));
let config = build_config(codex_home.path(), None, Some("org_mine".to_string())).await;
super::enforce_login_restrictions(&config)
.await
@@ -1002,7 +1010,7 @@ mod tests {
let _guard = EnvVarGuard::set(CODEX_API_KEY_ENV_VAR, "sk-env");
let codex_home = tempdir().unwrap();
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::Chatgpt), None);
let config = build_config(codex_home.path(), Some(ForcedLoginMethod::Chatgpt), None).await;
let err = super::enforce_login_restrictions(&config)
.await
+61 -26
View File
@@ -2749,8 +2749,8 @@ pub(crate) use tests::make_session_and_context_with_rx;
mod tests {
use super::*;
use crate::CodexAuth;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
use crate::config::ConfigBuilder;
use crate::config_loader::LoaderOverrides;
use crate::exec::ExecToolCallOutput;
use crate::function_tool::FunctionCallError;
use crate::shell::default_user_shell;
@@ -2777,6 +2777,8 @@ mod tests {
use codex_app_server_protocol::AuthMode;
use codex_protocol::models::ContentItem;
use codex_protocol::models::ResponseItem;
use std::future::Future;
use std::path::Path;
use std::time::Duration;
use tokio::time::sleep;
@@ -2834,12 +2836,7 @@ mod tests {
#[test]
fn set_rate_limits_retains_previous_credits() {
let codex_home = tempfile::tempdir().expect("create temp dir");
let config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let config = build_test_config(codex_home.path());
let config = Arc::new(config);
let model = ModelsManager::get_model_offline(config.model.as_deref());
let session_configuration = SessionConfiguration {
@@ -2906,12 +2903,7 @@ mod tests {
#[test]
fn set_rate_limits_updates_plan_type_when_present() {
let codex_home = tempfile::tempdir().expect("create temp dir");
let config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let config = build_test_config(codex_home.path());
let config = Arc::new(config);
let model = ModelsManager::get_model_offline(config.model.as_deref());
let session_configuration = SessionConfiguration {
@@ -3084,6 +3076,59 @@ mod tests {
})
}
fn build_test_config(codex_home: &Path) -> Config {
block_on(
ConfigBuilder::default()
.codex_home(codex_home.to_path_buf())
.loader_overrides(test_loader_overrides(codex_home))
.build(),
)
.expect("load default test config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn block_on<F>(future: F) -> F::Output
where
F: Future + Send,
F::Output: Send,
{
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
if matches!(
handle.runtime_flavor(),
tokio::runtime::RuntimeFlavor::CurrentThread
) {
std::thread::scope(|scope| {
scope
.spawn(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future)
})
.join()
.expect("join tokio thread")
})
} else {
tokio::task::block_in_place(|| handle.block_on(future))
}
}
Err(_) => tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future),
}
}
fn otel_manager(
conversation_id: ConversationId,
config: &Config,
@@ -3106,12 +3151,7 @@ mod tests {
pub(crate) fn make_session_and_context() -> (Session, TurnContext) {
let (tx_event, _rx_event) = async_channel::unbounded();
let codex_home = tempfile::tempdir().expect("create temp dir");
let config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let config = build_test_config(codex_home.path());
let config = Arc::new(config);
let conversation_id = ConversationId::default();
let auth_manager =
@@ -3197,12 +3237,7 @@ mod tests {
) {
let (tx_event, rx_event) = async_channel::unbounded();
let codex_home = tempfile::tempdir().expect("create temp dir");
let config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let config = build_test_config(codex_home.path());
let config = Arc::new(config);
let conversation_id = ConversationId::default();
let auth_manager =
+3 -4
View File
@@ -992,14 +992,13 @@ pub fn resolve_oss_provider(
}
impl Config {
/// Meant to be used exclusively for tests. For new tests, prefer using
/// [ConfigBuilder::build()], if possible, so ultimately we can make this
/// method private to this file.
pub fn load_from_base_config_with_overrides(
#[cfg(test)]
fn load_from_base_config_with_overrides(
cfg: ConfigToml,
overrides: ConfigOverrides,
codex_home: PathBuf,
) -> std::io::Result<Self> {
// Note this ignores requirements.toml enforcement for tests.
let requirements = ConfigRequirements::default();
Self::load_config_with_requirements(cfg, overrides, codex_home, requirements)
}
+24 -15
View File
@@ -401,13 +401,14 @@ fn history_log_id(_metadata: &std::fs::Metadata) -> Option<u64> {
#[cfg(test)]
mod tests {
use super::*;
use crate::config::Config;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
use crate::config::ConfigBuilder;
use crate::config_loader::LoaderOverrides;
use codex_protocol::ConversationId;
use pretty_assertions::assert_eq;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use tempfile::TempDir;
#[tokio::test]
@@ -493,12 +494,12 @@ mod tests {
async fn append_entry_trims_history_when_beyond_max_bytes() {
let codex_home = TempDir::new().expect("create temp dir");
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load config");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build()
.await
.expect("load config");
let conversation_id = ConversationId::new();
@@ -541,12 +542,12 @@ mod tests {
async fn append_entry_trims_history_to_soft_cap() {
let codex_home = TempDir::new().expect("create temp dir");
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load config");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build()
.await
.expect("load config");
let conversation_id = ConversationId::new();
@@ -615,4 +616,12 @@ mod tests {
assert_eq!(pruned_len, long_entry_len);
assert!(pruned_len <= soft_cap_bytes.max(long_entry_len));
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
}
@@ -314,15 +314,16 @@ mod tests {
use super::*;
use crate::CodexAuth;
use crate::auth::AuthCredentialsStoreMode;
use crate::config::Config;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
use crate::config::ConfigBuilder;
use crate::config_loader::LoaderOverrides;
use crate::features::Feature;
use crate::model_provider_info::WireApi;
use codex_protocol::openai_models::ModelsResponse;
use core_test_support::responses::mount_models_once;
use pretty_assertions::assert_eq;
use serde_json::json;
use std::path::Path;
use tempfile::tempdir;
use wiremock::MockServer;
@@ -380,6 +381,14 @@ mod tests {
}
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
#[tokio::test]
async fn refresh_available_models_sorts_and_marks_default() {
let server = MockServer::start().await;
@@ -397,12 +406,12 @@ mod tests {
.await;
let codex_home = tempdir().expect("temp dir");
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build()
.await
.expect("load default test config");
config.features.enable(Feature::RemoteModels);
let auth_manager =
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
@@ -455,12 +464,12 @@ mod tests {
.await;
let codex_home = tempdir().expect("temp dir");
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build()
.await
.expect("load default test config");
config.features.enable(Feature::RemoteModels);
let auth_manager = Arc::new(AuthManager::new(
codex_home.path().to_path_buf(),
@@ -511,12 +520,12 @@ mod tests {
.await;
let codex_home = tempdir().expect("temp dir");
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build()
.await
.expect("load default test config");
config.features.enable(Feature::RemoteModels);
let auth_manager = Arc::new(AuthManager::new(
codex_home.path().to_path_buf(),
@@ -587,12 +596,12 @@ mod tests {
.await;
let codex_home = tempdir().expect("temp dir");
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("load default test config");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build()
.await
.expect("load default test config");
config.features.enable(Feature::RemoteModels);
let auth_manager =
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
+52 -6
View File
@@ -232,10 +232,12 @@ fn merge_project_docs_with_skills(
#[cfg(test)]
mod tests {
use super::*;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
use crate::config::ConfigBuilder;
use crate::config_loader::LoaderOverrides;
use crate::skills::load_skills;
use std::fs;
use std::future::Future;
use std::path::Path;
use std::path::PathBuf;
use tempfile::TempDir;
@@ -246,10 +248,11 @@ mod tests {
/// been configured.
fn make_config(root: &TempDir, limit: usize, instructions: Option<&str>) -> Config {
let codex_home = TempDir::new().unwrap();
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
let mut config = block_on(
ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build(),
)
.expect("defaults for test should always succeed");
@@ -551,4 +554,47 @@ mod tests {
let content = format!("---\nname: {name}\ndescription: {description}\n---\n\n# Body\n");
fs::write(skill_dir.join("SKILL.md"), content).unwrap();
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn block_on<F>(future: F) -> F::Output
where
F: Future + Send,
F::Output: Send,
{
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
if matches!(
handle.runtime_flavor(),
tokio::runtime::RuntimeFlavor::CurrentThread
) {
std::thread::scope(|scope| {
scope
.spawn(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future)
})
.join()
.expect("join tokio thread")
})
} else {
tokio::task::block_in_place(|| handle.block_on(future))
}
}
Err(_) => tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future),
}
}
}
+22 -8
View File
@@ -279,8 +279,8 @@ fn extract_frontmatter(contents: &str) -> Option<String> {
#[cfg(test)]
mod tests {
use super::*;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
use crate::config::ConfigBuilder;
use crate::config_loader::LoaderOverrides;
use codex_protocol::protocol::SkillScope;
use pretty_assertions::assert_eq;
use std::path::Path;
@@ -288,12 +288,18 @@ mod tests {
use tempfile::TempDir;
fn make_config(codex_home: &TempDir) -> Config {
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
codex_home.path().to_path_buf(),
)
.expect("defaults for test should always succeed");
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime");
let mut config = runtime
.block_on(
ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(codex_home.path()))
.build(),
)
.expect("defaults for test should always succeed");
config.cwd = codex_home.path().to_path_buf();
config
@@ -329,6 +335,14 @@ mod tests {
path
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
#[test]
fn loads_valid_skill() {
let codex_home = tempfile::tempdir().expect("tempdir");
+52 -5
View File
@@ -4,10 +4,12 @@ use tempfile::TempDir;
use codex_core::CodexConversation;
use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config_loader::LoaderOverrides;
use codex_utils_absolute_path::AbsolutePathBuf;
use regex_lite::Regex;
use std::future::Future;
use std::path::PathBuf;
#[cfg(target_os = "linux")]
@@ -76,14 +78,59 @@ pub fn test_tmp_path_buf() -> PathBuf {
/// temporary directory. Using a per-test directory keeps tests hermetic and
/// avoids clobbering a developer’s real `~/.codex`.
pub fn load_default_config_for_test(codex_home: &TempDir) -> Config {
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
default_test_overrides(),
codex_home.path().to_path_buf(),
block_on(
ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.harness_overrides(default_test_overrides())
.loader_overrides(test_loader_overrides(codex_home))
.build(),
)
.expect("defaults for test should always succeed")
}
fn test_loader_overrides(codex_home: &TempDir) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.path().join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn block_on<F>(future: F) -> F::Output
where
F: Future + Send,
F::Output: Send,
{
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
if matches!(
handle.runtime_flavor(),
tokio::runtime::RuntimeFlavor::CurrentThread
) {
std::thread::scope(|scope| {
scope
.spawn(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future)
})
.join()
.expect("join tokio thread")
})
} else {
tokio::task::block_in_place(|| handle.block_on(future))
}
}
Err(_) => tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future),
}
}
#[cfg(target_os = "linux")]
fn default_test_overrides() -> ConfigOverrides {
ConfigOverrides {
+53 -7
View File
@@ -8,10 +8,10 @@ use codex_common::approval_presets::builtin_approval_presets;
use codex_core::AuthManager;
use codex_core::CodexAuth;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config::Constrained;
use codex_core::config::ConstraintError;
use codex_core::config_loader::LoaderOverrides;
use codex_core::openai_models::models_manager::ModelsManager;
use codex_core::protocol::AgentMessageDeltaEvent;
use codex_core::protocol::AgentMessageEvent;
@@ -63,6 +63,8 @@ use crossterm::event::KeyModifiers;
use insta::assert_snapshot;
use pretty_assertions::assert_eq;
use std::collections::HashSet;
use std::future::Future;
use std::path::Path;
use std::path::PathBuf;
use tempfile::NamedTempFile;
use tempfile::tempdir;
@@ -76,15 +78,59 @@ fn set_windows_sandbox_enabled(enabled: bool) {
fn test_config() -> Config {
// Use base defaults to avoid depending on host state.
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
std::env::temp_dir(),
let codex_home = std::env::temp_dir();
block_on(
ConfigBuilder::default()
.codex_home(codex_home.clone())
.loader_overrides(test_loader_overrides(codex_home.as_path()))
.build(),
)
.expect("config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn block_on<F>(future: F) -> F::Output
where
F: Future + Send,
F::Output: Send,
{
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
if matches!(
handle.runtime_flavor(),
tokio::runtime::RuntimeFlavor::CurrentThread
) {
std::thread::scope(|scope| {
scope
.spawn(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future)
})
.join()
.expect("join tokio thread")
})
} else {
tokio::task::block_in_place(|| handle.block_on(future))
}
}
Err(_) => tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future),
}
}
fn snapshot(percent: f64) -> RateLimitSnapshot {
RateLimitSnapshot {
primary: Some(RateLimitWindow {
+24 -8
View File
@@ -1580,10 +1580,10 @@ mod tests {
use crate::exec_cell::ExecCall;
use crate::exec_cell::ExecCell;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_core::config_loader::LoaderOverrides;
use codex_core::openai_models::models_manager::ModelsManager;
use codex_core::protocol::McpAuthStatus;
use codex_protocol::parse_command::ParsedCommand;
@@ -1598,14 +1598,30 @@ mod tests {
use mcp_types::TextContent;
use mcp_types::Tool;
use mcp_types::ToolInputSchema;
use std::path::Path;
fn test_config() -> Config {
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
std::env::temp_dir(),
)
.expect("config")
let codex_home = std::env::temp_dir();
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime");
runtime
.block_on(
ConfigBuilder::default()
.codex_home(codex_home.clone())
.loader_overrides(test_loader_overrides(codex_home.as_path()))
.build(),
)
.expect("config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn render_lines(lines: &[Line<'static>]) -> Vec<String> {
+26 -17
View File
@@ -596,21 +596,38 @@ fn should_show_login_screen(login_status: LoginStatus, config: &Config) -> bool
#[cfg(test)]
mod tests {
use super::*;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config::ProjectConfig;
use codex_core::config_loader::LoaderOverrides;
use serial_test::serial;
use std::path::Path;
use tempfile::TempDir;
fn build_config(temp_dir: &TempDir) -> std::io::Result<Config> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
runtime.block_on(
ConfigBuilder::default()
.codex_home(temp_dir.path().to_path_buf())
.loader_overrides(test_loader_overrides(temp_dir.path()))
.build(),
)
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
#[test]
#[serial]
fn windows_skips_trust_prompt_without_sandbox() -> std::io::Result<()> {
let temp_dir = TempDir::new()?;
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_dir.path().to_path_buf(),
)?;
let mut config = build_config(&temp_dir)?;
config.did_user_set_custom_approval_policy_or_sandbox_mode = false;
config.active_project = ProjectConfig { trust_level: None };
config.set_windows_sandbox_globally(false);
@@ -633,11 +650,7 @@ mod tests {
#[serial]
fn windows_shows_trust_prompt_with_sandbox() -> std::io::Result<()> {
let temp_dir = TempDir::new()?;
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_dir.path().to_path_buf(),
)?;
let mut config = build_config(&temp_dir)?;
config.did_user_set_custom_approval_policy_or_sandbox_mode = false;
config.active_project = ProjectConfig { trust_level: None };
config.set_windows_sandbox_globally(true);
@@ -660,11 +673,7 @@ mod tests {
fn untrusted_project_skips_trust_prompt() -> std::io::Result<()> {
use codex_protocol::config_types::TrustLevel;
let temp_dir = TempDir::new()?;
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_dir.path().to_path_buf(),
)?;
let mut config = build_config(&temp_dir)?;
config.did_user_set_custom_approval_policy_or_sandbox_mode = false;
config.active_project = ProjectConfig {
trust_level: Some(TrustLevel::Untrusted),
+23 -8
View File
@@ -6,8 +6,8 @@ use chrono::TimeZone;
use chrono::Utc;
use codex_core::AuthManager;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config_loader::LoaderOverrides;
use codex_core::openai_models::model_family::ModelFamily;
use codex_core::openai_models::models_manager::ModelsManager;
use codex_core::protocol::CreditsSnapshot;
@@ -19,16 +19,31 @@ use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::openai_models::ReasoningEffort;
use insta::assert_snapshot;
use ratatui::prelude::*;
use std::path::Path;
use std::path::PathBuf;
use tempfile::TempDir;
fn test_config(temp_home: &TempDir) -> Config {
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_home.path().to_path_buf(),
)
.expect("load config")
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime");
runtime
.block_on(
ConfigBuilder::default()
.codex_home(temp_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(temp_home.path()))
.build(),
)
.expect("load config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn test_auth_manager(config: &Config) -> AuthManager {
+53 -7
View File
@@ -8,9 +8,9 @@ use codex_common::approval_presets::builtin_approval_presets;
use codex_core::AuthManager;
use codex_core::CodexAuth;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config::Constrained;
use codex_core::config_loader::LoaderOverrides;
use codex_core::openai_models::models_manager::ModelsManager;
use codex_core::protocol::AgentMessageDeltaEvent;
use codex_core::protocol::AgentMessageEvent;
@@ -62,6 +62,8 @@ use crossterm::event::KeyModifiers;
use insta::assert_snapshot;
use pretty_assertions::assert_eq;
use std::collections::HashSet;
use std::future::Future;
use std::path::Path;
use std::path::PathBuf;
use tempfile::NamedTempFile;
use tempfile::tempdir;
@@ -75,15 +77,59 @@ fn set_windows_sandbox_enabled(enabled: bool) {
fn test_config() -> Config {
// Use base defaults to avoid depending on host state.
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
std::env::temp_dir(),
let codex_home = std::env::temp_dir();
block_on(
ConfigBuilder::default()
.codex_home(codex_home.clone())
.loader_overrides(test_loader_overrides(codex_home.as_path()))
.build(),
)
.expect("config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn block_on<F>(future: F) -> F::Output
where
F: Future + Send,
F::Output: Send,
{
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
if matches!(
handle.runtime_flavor(),
tokio::runtime::RuntimeFlavor::CurrentThread
) {
std::thread::scope(|scope| {
scope
.spawn(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future)
})
.join()
.expect("join tokio thread")
})
} else {
tokio::task::block_in_place(|| handle.block_on(future))
}
}
Err(_) => tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime")
.block_on(future),
}
}
fn snapshot(percent: f64) -> RateLimitSnapshot {
RateLimitSnapshot {
primary: Some(RateLimitWindow {
+24 -8
View File
@@ -1514,10 +1514,10 @@ mod tests {
use crate::exec_cell::ExecCall;
use crate::exec_cell::ExecCell;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_core::config_loader::LoaderOverrides;
use codex_core::openai_models::models_manager::ModelsManager;
use codex_core::protocol::McpAuthStatus;
use codex_protocol::parse_command::ParsedCommand;
@@ -1532,14 +1532,30 @@ mod tests {
use mcp_types::TextContent;
use mcp_types::Tool;
use mcp_types::ToolInputSchema;
use std::path::Path;
fn test_config() -> Config {
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
std::env::temp_dir(),
)
.expect("config")
let codex_home = std::env::temp_dir();
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime");
runtime
.block_on(
ConfigBuilder::default()
.codex_home(codex_home.clone())
.loader_overrides(test_loader_overrides(codex_home.as_path()))
.build(),
)
.expect("config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn render_lines(lines: &[Line<'static>]) -> Vec<String> {
+26 -17
View File
@@ -622,21 +622,38 @@ fn should_show_login_screen(login_status: LoginStatus, config: &Config) -> bool
#[cfg(test)]
mod tests {
use super::*;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config::ProjectConfig;
use codex_core::config_loader::LoaderOverrides;
use serial_test::serial;
use std::path::Path;
use tempfile::TempDir;
fn build_config(temp_dir: &TempDir) -> std::io::Result<Config> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
runtime.block_on(
ConfigBuilder::default()
.codex_home(temp_dir.path().to_path_buf())
.loader_overrides(test_loader_overrides(temp_dir.path()))
.build(),
)
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
#[test]
#[serial]
fn windows_skips_trust_prompt_without_sandbox() -> std::io::Result<()> {
let temp_dir = TempDir::new()?;
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_dir.path().to_path_buf(),
)?;
let mut config = build_config(&temp_dir)?;
config.did_user_set_custom_approval_policy_or_sandbox_mode = false;
config.active_project = ProjectConfig { trust_level: None };
config.set_windows_sandbox_globally(false);
@@ -659,11 +676,7 @@ mod tests {
#[serial]
fn windows_shows_trust_prompt_with_sandbox() -> std::io::Result<()> {
let temp_dir = TempDir::new()?;
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_dir.path().to_path_buf(),
)?;
let mut config = build_config(&temp_dir)?;
config.did_user_set_custom_approval_policy_or_sandbox_mode = false;
config.active_project = ProjectConfig { trust_level: None };
config.set_windows_sandbox_globally(true);
@@ -686,11 +699,7 @@ mod tests {
fn untrusted_project_skips_trust_prompt() -> std::io::Result<()> {
use codex_protocol::config_types::TrustLevel;
let temp_dir = TempDir::new()?;
let mut config = Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_dir.path().to_path_buf(),
)?;
let mut config = build_config(&temp_dir)?;
config.did_user_set_custom_approval_policy_or_sandbox_mode = false;
config.active_project = ProjectConfig {
trust_level: Some(TrustLevel::Untrusted),
+23 -8
View File
@@ -6,8 +6,8 @@ use chrono::TimeZone;
use chrono::Utc;
use codex_core::AuthManager;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
use codex_core::config::ConfigBuilder;
use codex_core::config_loader::LoaderOverrides;
use codex_core::openai_models::model_family::ModelFamily;
use codex_core::openai_models::models_manager::ModelsManager;
use codex_core::protocol::CreditsSnapshot;
@@ -19,16 +19,31 @@ use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::openai_models::ReasoningEffort;
use insta::assert_snapshot;
use ratatui::prelude::*;
use std::path::Path;
use std::path::PathBuf;
use tempfile::TempDir;
fn test_config(temp_home: &TempDir) -> Config {
Config::load_from_base_config_with_overrides(
ConfigToml::default(),
ConfigOverrides::default(),
temp_home.path().to_path_buf(),
)
.expect("load config")
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime");
runtime
.block_on(
ConfigBuilder::default()
.codex_home(temp_home.path().to_path_buf())
.loader_overrides(test_loader_overrides(temp_home.path()))
.build(),
)
.expect("load config")
}
fn test_loader_overrides(codex_home: &Path) -> LoaderOverrides {
LoaderOverrides {
managed_config_path: Some(codex_home.join("managed_config.toml")),
#[cfg(target_os = "macos")]
managed_preferences_base64: Some(String::new()),
}
}
fn test_auth_manager(config: &Config) -> AuthManager {