diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index fd4ed6d8d..fbab962cb 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2286,15 +2286,20 @@ version = "0.0.0" dependencies = [ "anyhow", "async-trait", + "base64 0.22.1", "codex-app-server-protocol", + "codex-exec-server", "codex-execpolicy", "codex-features", + "codex-git-utils", "codex-model-provider-info", "codex-network-proxy", "codex-protocol", "codex-utils-absolute-path", "codex-utils-path", + "core-foundation 0.9.4", "dns-lookup", + "dunce", "futures", "gethostname", "libc", @@ -2318,6 +2323,7 @@ dependencies = [ "tracing", "wildmatch", "winapi-util", + "windows-sys 0.52.0", ] [[package]] @@ -2398,7 +2404,6 @@ dependencies = [ "codex-utils-string", "codex-utils-template", "codex-windows-sandbox", - "core-foundation 0.9.4", "core_test_support", "csv", "ctor 0.6.3", @@ -2449,7 +2454,6 @@ dependencies = [ "walkdir", "which 8.0.0", "whoami", - "windows-sys 0.52.0", "wiremock", "zstd 0.13.3", ] @@ -2559,6 +2563,7 @@ dependencies = [ "codex-apply-patch", "codex-arg0", "codex-cloud-requirements", + "codex-config", "codex-core", "codex-feedback", "codex-git-utils", @@ -2602,7 +2607,6 @@ dependencies = [ "bytes", "codex-app-server-protocol", "codex-client", - "codex-config", "codex-protocol", "codex-sandboxing", "codex-test-binary-support", @@ -2780,7 +2784,6 @@ version = "0.0.0" dependencies = [ "cc", "clap", - "codex-config", "codex-core", "codex-protocol", "codex-sandboxing", @@ -3117,6 +3120,7 @@ dependencies = [ "tracing", "ts-rs", "uuid", + "wildmatch", ] [[package]] diff --git a/codex-rs/app-server-client/src/lib.rs b/codex-rs/app-server-client/src/lib.rs index 1429fa26c..e1614c32d 100644 --- a/codex-rs/app-server-client/src/lib.rs +++ b/codex-rs/app-server-client/src/lib.rs @@ -41,12 +41,12 @@ use codex_app_server_protocol::Result as JsonRpcResult; use codex_app_server_protocol::ServerNotification; use codex_app_server_protocol::ServerRequest; use codex_arg0::Arg0DispatchPaths; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; use codex_config::NoopThreadConfigLoader; use codex_config::RemoteThreadConfigLoader; use codex_config::ThreadConfigLoader; use codex_core::config::Config; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::LoaderOverrides; pub use codex_exec_server::EnvironmentManager; pub use codex_exec_server::EnvironmentManagerArgs; pub use codex_exec_server::ExecServerRuntimePaths; diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index d479de353..2c6e172f7 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -230,6 +230,9 @@ use codex_backend_client::AddCreditsNudgeCreditType as BackendAddCreditsNudgeCre use codex_backend_client::Client as BackendClient; use codex_chatgpt::connectors; use codex_chatgpt::workspace_settings; +use codex_config::CloudRequirementsLoadError; +use codex_config::CloudRequirementsLoadErrorCode; +use codex_config::loader::project_trust_key; use codex_config::types::McpServerTransportConfig; use codex_core::CodexThread; use codex_core::CodexThreadTurnContextOverrides; @@ -248,9 +251,6 @@ use codex_core::config::NetworkProxyAuditMetadata; use codex_core::config::ThreadStoreConfig; use codex_core::config::edit::ConfigEdit; use codex_core::config::edit::ConfigEditsBuilder; -use codex_core::config_loader::CloudRequirementsLoadError; -use codex_core::config_loader::CloudRequirementsLoadErrorCode; -use codex_core::config_loader::project_trust_key; use codex_core::exec::ExecCapturePolicy; use codex_core::exec::ExecExpiration; use codex_core::exec::ExecParams; @@ -10453,11 +10453,11 @@ mod tests { use chrono::Utc; use codex_app_server_protocol::ServerRequestPayload; use codex_app_server_protocol::ToolRequestUserInputParams; + use codex_config::CloudRequirementsLoader; + use codex_config::LoaderOverrides; use codex_config::SessionThreadConfig; use codex_config::StaticThreadConfigLoader; use codex_config::ThreadConfigSource; - use codex_core::config_loader::CloudRequirementsLoader; - use codex_core::config_loader::LoaderOverrides; use codex_model_provider_info::ModelProviderInfo; use codex_model_provider_info::WireApi; use codex_protocol::ThreadId; diff --git a/codex-rs/app-server/src/config_api.rs b/codex-rs/app-server/src/config_api.rs index 355b41543..e8bb82777 100644 --- a/codex-rs/app-server/src/config_api.rs +++ b/codex-rs/app-server/src/config_api.rs @@ -23,15 +23,15 @@ use codex_app_server_protocol::NetworkDomainPermission; use codex_app_server_protocol::NetworkRequirements; use codex_app_server_protocol::NetworkUnixSocketPermission; use codex_app_server_protocol::SandboxMode; +use codex_config::ConfigRequirementsToml; +use codex_config::HookEventsToml; +use codex_config::HookHandlerConfig as CoreHookHandlerConfig; +use codex_config::ManagedHooksRequirementsToml; +use codex_config::MatcherGroup as CoreMatcherGroup; +use codex_config::ResidencyRequirement as CoreResidencyRequirement; +use codex_config::SandboxModeRequirement as CoreSandboxModeRequirement; use codex_core::ThreadManager; use codex_core::config::Config; -use codex_core::config_loader::ConfigRequirementsToml; -use codex_core::config_loader::HookEventsToml; -use codex_core::config_loader::HookHandlerConfig as CoreHookHandlerConfig; -use codex_core::config_loader::ManagedHooksRequirementsToml; -use codex_core::config_loader::MatcherGroup as CoreMatcherGroup; -use codex_core::config_loader::ResidencyRequirement as CoreResidencyRequirement; -use codex_core::config_loader::SandboxModeRequirement as CoreSandboxModeRequirement; use codex_core::plugins::PluginId; use codex_core_plugins::loader::installed_plugin_telemetry_metadata; use codex_core_plugins::toggles::collect_plugin_enabled_candidates; @@ -377,20 +377,20 @@ fn map_residency_requirement_to_api( } fn map_network_requirements_to_api( - network: codex_core::config_loader::NetworkRequirementsToml, + network: codex_config::NetworkRequirementsToml, ) -> NetworkRequirements { let allowed_domains = network .domains .as_ref() - .and_then(codex_core::config_loader::NetworkDomainPermissionsToml::allowed_domains); + .and_then(codex_config::NetworkDomainPermissionsToml::allowed_domains); let denied_domains = network .domains .as_ref() - .and_then(codex_core::config_loader::NetworkDomainPermissionsToml::denied_domains); + .and_then(codex_config::NetworkDomainPermissionsToml::denied_domains); let allow_unix_sockets = network .unix_sockets .as_ref() - .map(codex_core::config_loader::NetworkUnixSocketPermissionsToml::allow_unix_sockets) + .map(codex_config::NetworkUnixSocketPermissionsToml::allow_unix_sockets) .filter(|entries| !entries.is_empty()); NetworkRequirements { @@ -427,28 +427,20 @@ fn map_network_requirements_to_api( } fn map_network_domain_permission_to_api( - permission: codex_core::config_loader::NetworkDomainPermissionToml, + permission: codex_config::NetworkDomainPermissionToml, ) -> NetworkDomainPermission { match permission { - codex_core::config_loader::NetworkDomainPermissionToml::Allow => { - NetworkDomainPermission::Allow - } - codex_core::config_loader::NetworkDomainPermissionToml::Deny => { - NetworkDomainPermission::Deny - } + codex_config::NetworkDomainPermissionToml::Allow => NetworkDomainPermission::Allow, + codex_config::NetworkDomainPermissionToml::Deny => NetworkDomainPermission::Deny, } } fn map_network_unix_socket_permission_to_api( - permission: codex_core::config_loader::NetworkUnixSocketPermissionToml, + permission: codex_config::NetworkUnixSocketPermissionToml, ) -> NetworkUnixSocketPermission { match permission { - codex_core::config_loader::NetworkUnixSocketPermissionToml::Allow => { - NetworkUnixSocketPermission::Allow - } - codex_core::config_loader::NetworkUnixSocketPermissionToml::None => { - NetworkUnixSocketPermission::None - } + codex_config::NetworkUnixSocketPermissionToml::Allow => NetworkUnixSocketPermission::Allow, + codex_config::NetworkUnixSocketPermissionToml::None => NetworkUnixSocketPermission::None, } } @@ -476,13 +468,13 @@ mod tests { use crate::config_manager::apply_runtime_feature_enablement; use codex_analytics::AnalyticsEventsClient; use codex_arg0::Arg0DispatchPaths; - use codex_core::config_loader::CloudRequirementsLoader; - use codex_core::config_loader::LoaderOverrides; - use codex_core::config_loader::NetworkDomainPermissionToml as CoreNetworkDomainPermissionToml; - use codex_core::config_loader::NetworkDomainPermissionsToml as CoreNetworkDomainPermissionsToml; - use codex_core::config_loader::NetworkRequirementsToml as CoreNetworkRequirementsToml; - use codex_core::config_loader::NetworkUnixSocketPermissionToml as CoreNetworkUnixSocketPermissionToml; - use codex_core::config_loader::NetworkUnixSocketPermissionsToml as CoreNetworkUnixSocketPermissionsToml; + use codex_config::CloudRequirementsLoader; + use codex_config::LoaderOverrides; + use codex_config::NetworkDomainPermissionToml as CoreNetworkDomainPermissionToml; + use codex_config::NetworkDomainPermissionsToml as CoreNetworkDomainPermissionsToml; + use codex_config::NetworkRequirementsToml as CoreNetworkRequirementsToml; + use codex_config::NetworkUnixSocketPermissionToml as CoreNetworkUnixSocketPermissionToml; + use codex_config::NetworkUnixSocketPermissionsToml as CoreNetworkUnixSocketPermissionsToml; use codex_features::Feature; use codex_login::AuthManager; use codex_login::CodexAuth; @@ -524,11 +516,9 @@ mod tests { CoreSandboxModeRequirement::ExternalSandbox, ]), remote_sandbox_config: None, - allowed_web_search_modes: Some(vec![ - codex_core::config_loader::WebSearchModeRequirement::Cached, - ]), + allowed_web_search_modes: Some(vec![codex_config::WebSearchModeRequirement::Cached]), guardian_policy_config: None, - feature_requirements: Some(codex_core::config_loader::FeatureRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: std::collections::BTreeMap::from([ ("apps".to_string(), false), ("personality".to_string(), true), @@ -794,11 +784,9 @@ mod tests { )]) .cloud_requirements(CloudRequirementsLoader::new(async { Ok(Some(ConfigRequirementsToml { - feature_requirements: Some( - codex_core::config_loader::FeatureRequirementsToml { - entries: BTreeMap::from([("apps".to_string(), false)]), - }, - ), + feature_requirements: Some(codex_config::FeatureRequirementsToml { + entries: BTreeMap::from([("apps".to_string(), false)]), + }), ..Default::default() })) })) diff --git a/codex-rs/app-server/src/config_manager.rs b/codex-rs/app-server/src/config_manager.rs index 43dd19004..399c0c9fa 100644 --- a/codex-rs/app-server/src/config_manager.rs +++ b/codex-rs/app-server/src/config_manager.rs @@ -1,12 +1,12 @@ use codex_arg0::Arg0DispatchPaths; use codex_cloud_requirements::cloud_requirements_loader; +use codex_config::CloudRequirementsLoader; +use codex_config::ConfigLayerStack; +use codex_config::LoaderOverrides; use codex_config::ThreadConfigLoader; +use codex_config::loader::load_config_layers_state; use codex_core::config::Config; use codex_core::config::ConfigOverrides; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::ConfigLayerStack; -use codex_core::config_loader::LoaderOverrides; -use codex_core::config_loader::load_config_layers_state; use codex_exec_server::LOCAL_FS; use codex_features::feature_for_key; use codex_login::AuthManager; diff --git a/codex-rs/app-server/src/config_manager_service.rs b/codex-rs/app-server/src/config_manager_service.rs index 0104429a4..ec4a1a680 100644 --- a/codex-rs/app-server/src/config_manager_service.rs +++ b/codex-rs/app-server/src/config_manager_service.rs @@ -12,16 +12,16 @@ use codex_app_server_protocol::MergeStrategy; use codex_app_server_protocol::OverriddenMetadata; use codex_app_server_protocol::WriteStatus; use codex_config::CONFIG_TOML_FILE; +use codex_config::ConfigLayerEntry; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::ConfigRequirementsToml; use codex_config::config_toml::ConfigToml; +use codex_config::merge_toml_values; use codex_core::config::deserialize_config_toml_with_base; use codex_core::config::edit::ConfigEdit; use codex_core::config::edit::ConfigEditsBuilder; use codex_core::config::validate_feature_requirements_for_config_toml; -use codex_core::config_loader::ConfigLayerEntry; -use codex_core::config_loader::ConfigLayerStack; -use codex_core::config_loader::ConfigLayerStackOrdering; -use codex_core::config_loader::ConfigRequirementsToml; -use codex_core::config_loader::merge_toml_values; use codex_core::path_utils; use codex_core::path_utils::SymlinkWritePaths; use codex_core::path_utils::resolve_symlink_write_paths; diff --git a/codex-rs/app-server/src/config_manager_service_tests.rs b/codex-rs/app-server/src/config_manager_service_tests.rs index a871d8e43..02c76e3b5 100644 --- a/codex-rs/app-server/src/config_manager_service_tests.rs +++ b/codex-rs/app-server/src/config_manager_service_tests.rs @@ -4,9 +4,9 @@ use codex_app_server_protocol::AppConfig; use codex_app_server_protocol::AppToolApproval; use codex_app_server_protocol::AppsConfig; use codex_app_server_protocol::AskForApproval; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::FeatureRequirementsToml; -use codex_core::config_loader::LoaderOverrides; +use codex_config::CloudRequirementsLoader; +use codex_config::FeatureRequirementsToml; +use codex_config::LoaderOverrides; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; use std::collections::BTreeMap; diff --git a/codex-rs/app-server/src/in_process.rs b/codex-rs/app-server/src/in_process.rs index dac25b693..cc4e22e92 100644 --- a/codex-rs/app-server/src/in_process.rs +++ b/codex-rs/app-server/src/in_process.rs @@ -77,10 +77,10 @@ use codex_app_server_protocol::Result; use codex_app_server_protocol::ServerNotification; use codex_app_server_protocol::ServerRequest; use codex_arg0::Arg0DispatchPaths; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; use codex_config::ThreadConfigLoader; use codex_core::config::Config; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::LoaderOverrides; use codex_exec_server::EnvironmentManager; use codex_feedback::CodexFeedback; use codex_login::AuthManager; diff --git a/codex-rs/app-server/src/lib.rs b/codex-rs/app-server/src/lib.rs index 64f487482..59e8cc982 100644 --- a/codex-rs/app-server/src/lib.rs +++ b/codex-rs/app-server/src/lib.rs @@ -1,12 +1,12 @@ #![deny(clippy::print_stdout, clippy::print_stderr)] use codex_arg0::Arg0DispatchPaths; +use codex_config::ConfigLayerStackOrdering; +use codex_config::LoaderOverrides; use codex_config::NoopThreadConfigLoader; use codex_config::RemoteThreadConfigLoader; use codex_config::ThreadConfigLoader; use codex_core::config::Config; -use codex_core::config_loader::ConfigLayerStackOrdering; -use codex_core::config_loader::LoaderOverrides; use codex_exec_server::EnvironmentManagerArgs; use codex_features::Feature; use codex_login::AuthManager; @@ -42,11 +42,11 @@ use codex_app_server_protocol::ConfigWarningNotification; use codex_app_server_protocol::JSONRPCMessage; use codex_app_server_protocol::TextPosition as AppTextPosition; use codex_app_server_protocol::TextRange as AppTextRange; +use codex_config::ConfigLoadError; +use codex_config::TextRange as CoreTextRange; use codex_core::ExecPolicyError; use codex_core::check_execpolicy_for_warnings; use codex_core::config::find_codex_home; -use codex_core::config_loader::ConfigLoadError; -use codex_core::config_loader::TextRange as CoreTextRange; use codex_exec_server::EnvironmentManager; use codex_exec_server::ExecServerRuntimePaths; use codex_feedback::CodexFeedback; diff --git a/codex-rs/app-server/src/main.rs b/codex-rs/app-server/src/main.rs index 67098c2b3..1cb4bd9a8 100644 --- a/codex-rs/app-server/src/main.rs +++ b/codex-rs/app-server/src/main.rs @@ -6,7 +6,7 @@ use codex_app_server::PluginStartupTasks; use codex_app_server::run_main_with_transport_options; use codex_arg0::Arg0DispatchPaths; use codex_arg0::arg0_dispatch_or_else; -use codex_core::config_loader::LoaderOverrides; +use codex_config::LoaderOverrides; use codex_protocol::protocol::SessionSource; use codex_utils_cli::CliConfigOverrides; use std::path::PathBuf; diff --git a/codex-rs/app-server/src/message_processor/tracing_tests.rs b/codex-rs/app-server/src/message_processor/tracing_tests.rs index 7160b57d5..507d7865b 100644 --- a/codex-rs/app-server/src/message_processor/tracing_tests.rs +++ b/codex-rs/app-server/src/message_processor/tracing_tests.rs @@ -27,10 +27,10 @@ use codex_app_server_protocol::TurnStartParams; use codex_app_server_protocol::TurnStartResponse; use codex_app_server_protocol::UserInput; use codex_arg0::Arg0DispatchPaths; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; use codex_core::config::Config; use codex_core::config::ConfigBuilder; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::LoaderOverrides; use codex_exec_server::EnvironmentManager; use codex_feedback::CodexFeedback; use codex_login::AuthManager; diff --git a/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs b/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs index 30b4c0f32..57520a2d6 100644 --- a/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs +++ b/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs @@ -16,9 +16,9 @@ use codex_app_server_protocol::ExperimentalFeatureStage; use codex_app_server_protocol::JSONRPCError; use codex_app_server_protocol::JSONRPCResponse; use codex_app_server_protocol::RequestId; +use codex_config::LoaderOverrides; use codex_config::types::AuthCredentialsStoreMode; use codex_core::config::ConfigBuilder; -use codex_core::config_loader::LoaderOverrides; use codex_features::FEATURES; use codex_features::Stage; use pretty_assertions::assert_eq; diff --git a/codex-rs/app-server/tests/suite/v2/mcp_resource.rs b/codex-rs/app-server/tests/suite/v2/mcp_resource.rs index a347d87fc..3b1a49557 100644 --- a/codex-rs/app-server/tests/suite/v2/mcp_resource.rs +++ b/codex-rs/app-server/tests/suite/v2/mcp_resource.rs @@ -20,10 +20,10 @@ use codex_app_server_protocol::RequestId; use codex_app_server_protocol::ThreadStartParams; use codex_app_server_protocol::ThreadStartResponse; use codex_arg0::Arg0DispatchPaths; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; use codex_config::types::AuthCredentialsStoreMode; use codex_core::config::ConfigBuilder; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::LoaderOverrides; use codex_exec_server::EnvironmentManager; use codex_feedback::CodexFeedback; use codex_protocol::protocol::SessionSource; diff --git a/codex-rs/app-server/tests/suite/v2/remote_thread_store.rs b/codex-rs/app-server/tests/suite/v2/remote_thread_store.rs index 7556f4cd1..27160bd78 100644 --- a/codex-rs/app-server/tests/suite/v2/remote_thread_store.rs +++ b/codex-rs/app-server/tests/suite/v2/remote_thread_store.rs @@ -33,10 +33,10 @@ use codex_app_server_protocol::ThreadStartResponse; use codex_app_server_protocol::TurnStartParams; use codex_app_server_protocol::UserInput as V2UserInput; use codex_arg0::Arg0DispatchPaths; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; use codex_config::NoopThreadConfigLoader; use codex_core::config::ConfigBuilder; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::LoaderOverrides; use codex_exec_server::EnvironmentManager; use codex_feedback::CodexFeedback; use codex_protocol::protocol::SessionSource; diff --git a/codex-rs/app-server/tests/suite/v2/thread_start.rs b/codex-rs/app-server/tests/suite/v2/thread_start.rs index 3177003dd..f521d5509 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_start.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_start.rs @@ -20,9 +20,9 @@ use codex_app_server_protocol::ThreadStartedNotification; use codex_app_server_protocol::ThreadStatus; use codex_app_server_protocol::ThreadStatusChangedNotification; use codex_app_server_protocol::TurnEnvironmentParams; +use codex_config::loader::project_trust_key; use codex_config::types::AuthCredentialsStoreMode; use codex_core::config::set_project_trust_level; -use codex_core::config_loader::project_trust_key; use codex_exec_server::LOCAL_FS; use codex_git_utils::resolve_root_git_project_for_trust; use codex_login::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR; diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 415769e36..9f465521d 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -830,7 +830,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> { codex_app_server::run_main_with_transport( arg0_paths.clone(), root_config_overrides, - codex_core::config_loader::LoaderOverrides::default(), + codex_config::LoaderOverrides::default(), analytics_default_enabled, transport, codex_protocol::protocol::SessionSource::VSCode, @@ -1551,7 +1551,7 @@ async fn run_interactive_tui( codex_tui::run_main( interactive, arg0_paths, - codex_core::config_loader::LoaderOverrides::default(), + codex_config::LoaderOverrides::default(), normalized_remote, remote_auth_token, ) diff --git a/codex-rs/cloud-requirements/src/lib.rs b/codex-rs/cloud-requirements/src/lib.rs index 1d9975f12..86a12e7d1 100644 --- a/codex-rs/cloud-requirements/src/lib.rs +++ b/codex-rs/cloud-requirements/src/lib.rs @@ -15,11 +15,11 @@ use chrono::DateTime; use chrono::Duration as ChronoDuration; use chrono::Utc; use codex_backend_client::Client as BackendClient; +use codex_config::CloudRequirementsLoadError; +use codex_config::CloudRequirementsLoadErrorCode; +use codex_config::CloudRequirementsLoader; +use codex_config::ConfigRequirementsToml; use codex_config::types::AuthCredentialsStoreMode; -use codex_core::config_loader::CloudRequirementsLoadError; -use codex_core::config_loader::CloudRequirementsLoadErrorCode; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::ConfigRequirementsToml; use codex_core::util::backoff; use codex_login::AuthManager; use codex_login::CodexAuth; @@ -1314,10 +1314,10 @@ enabled = false assert_eq!( result, Some(ConfigRequirementsToml { - apps: Some(codex_core::config_loader::AppsRequirementsToml { + apps: Some(codex_config::AppsRequirementsToml { apps: BTreeMap::from([( "connector_5f3c8c41a1e54ad7a76272c89e2554fa".to_string(), - codex_core::config_loader::AppRequirementToml { + codex_config::AppRequirementToml { enabled: Some(false), }, )]), diff --git a/codex-rs/config/Cargo.toml b/codex-rs/config/Cargo.toml index 9df08b115..3c7e5a829 100644 --- a/codex-rs/config/Cargo.toml +++ b/codex-rs/config/Cargo.toml @@ -14,14 +14,18 @@ workspace = true [dependencies] anyhow = { workspace = true } async-trait = { workspace = true } +base64 = { workspace = true } codex-app-server-protocol = { workspace = true } +codex-exec-server = { workspace = true } codex-execpolicy = { workspace = true } codex-features = { workspace = true } +codex-git-utils = { workspace = true } codex-model-provider-info = { workspace = true } codex-network-proxy = { workspace = true } codex-protocol = { workspace = true } codex-utils-absolute-path = { workspace = true } codex-utils-path = { workspace = true } +dunce = { workspace = true } futures = { workspace = true, features = ["alloc", "std"] } gethostname = { workspace = true } multimap = { workspace = true } @@ -44,8 +48,16 @@ wildmatch = { workspace = true } dns-lookup = { workspace = true } libc = { workspace = true } +[target.'cfg(target_os = "macos")'.dependencies] +core-foundation = "0.9" + [target.'cfg(target_os = "windows")'.dependencies] winapi-util = { workspace = true } +windows-sys = { version = "0.52", features = [ + "Win32_Foundation", + "Win32_System_Com", + "Win32_UI_Shell", +] } [dev-dependencies] pretty_assertions = { workspace = true } diff --git a/codex-rs/config/src/lib.rs b/codex-rs/config/src/lib.rs index e3d95acb8..eb0e7713f 100644 --- a/codex-rs/config/src/lib.rs +++ b/codex-rs/config/src/lib.rs @@ -7,6 +7,7 @@ mod fingerprint; mod hook_config; mod host_name; mod key_aliases; +pub mod loader; mod marketplace_edit; mod mcp_edit; mod mcp_types; @@ -17,7 +18,6 @@ pub mod profile_toml; mod project_root_markers; mod requirements_exec_policy; pub mod schema; -pub mod shell_environment; mod skills_config; mod state; mod thread_config; diff --git a/codex-rs/core/src/config_loader/README.md b/codex-rs/config/src/loader/README.md similarity index 93% rename from codex-rs/core/src/config_loader/README.md rename to codex-rs/config/src/loader/README.md index 6ee445421..316027318 100644 --- a/codex-rs/core/src/config_loader/README.md +++ b/codex-rs/config/src/loader/README.md @@ -1,4 +1,4 @@ -# `codex-core` config loader +# `codex-config` loader This module is the canonical place to **load and describe Codex configuration layers** (user config, CLI/session overrides, managed config, and MDM-managed preferences) and to produce: @@ -8,7 +8,7 @@ This module is the canonical place to **load and describe Codex configuration la ## Public surface -Exported from `codex_core::config_loader`: +Exported from `codex_config::loader`: - `load_config_layers_state(fs, codex_home, cwd_opt, cli_overrides, overrides, cloud_requirements, thread_config_loader, host_name) -> ConfigLayerStack` - `ConfigLayerStack` @@ -41,8 +41,10 @@ computing the effective config and origins metadata. This is what Most callers want the effective config plus metadata: ```rust -use codex_core::config_loader::{CloudRequirementsLoader, LoaderOverrides, load_config_layers_state}; use codex_config::NoopThreadConfigLoader; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; +use codex_config::loader::load_config_layers_state; use codex_exec_server::LOCAL_FS; use codex_utils_absolute_path::AbsolutePathBuf; use toml::Value as TomlValue; diff --git a/codex-rs/core/src/config_loader/layer_io.rs b/codex-rs/config/src/loader/layer_io.rs similarity index 96% rename from codex-rs/core/src/config_loader/layer_io.rs rename to codex-rs/config/src/loader/layer_io.rs index 6bd9a9130..773a71f3b 100644 --- a/codex-rs/core/src/config_loader/layer_io.rs +++ b/codex-rs/config/src/loader/layer_io.rs @@ -1,10 +1,10 @@ -use super::LoaderOverrides; #[cfg(target_os = "macos")] use super::macos::ManagedAdminConfigLayer; #[cfg(target_os = "macos")] use super::macos::load_managed_admin_config_layer; -use codex_config::config_error_from_toml; -use codex_config::io_error_from_config_error; +use crate::diagnostics::config_error_from_toml; +use crate::diagnostics::io_error_from_config_error; +use crate::state::LoaderOverrides; use codex_exec_server::ExecutorFileSystem; use codex_utils_absolute_path::AbsolutePathBuf; use std::io; diff --git a/codex-rs/core/src/config_loader/macos.rs b/codex-rs/config/src/loader/macos.rs similarity index 97% rename from codex-rs/core/src/config_loader/macos.rs rename to codex-rs/config/src/loader/macos.rs index 977a09a9c..252542972 100644 --- a/codex-rs/core/src/config_loader/macos.rs +++ b/codex-rs/config/src/loader/macos.rs @@ -1,7 +1,7 @@ -use super::ConfigRequirementsToml; -use super::ConfigRequirementsWithSources; -use super::RequirementSource; use super::merge_requirements_with_remote_sandbox_config; +use crate::config_requirements::ConfigRequirementsToml; +use crate::config_requirements::ConfigRequirementsWithSources; +use crate::config_requirements::RequirementSource; use base64::Engine; use base64::prelude::BASE64_STANDARD; use core_foundation::base::TCFType; diff --git a/codex-rs/core/src/config_loader/mod.rs b/codex-rs/config/src/loader/mod.rs similarity index 92% rename from codex-rs/core/src/config_loader/mod.rs rename to codex-rs/config/src/loader/mod.rs index 4681aa075..e930e8b62 100644 --- a/codex-rs/core/src/config_loader/mod.rs +++ b/codex-rs/config/src/loader/mod.rs @@ -2,17 +2,29 @@ mod layer_io; #[cfg(target_os = "macos")] mod macos; -#[cfg(test)] -mod tests; - -use crate::config_loader::layer_io::LoadedConfigLayers; +use self::layer_io::LoadedConfigLayers; +use crate::CONFIG_TOML_FILE; +use crate::cloud_requirements::CloudRequirementsLoader; +use crate::config_requirements::ConfigRequirementsToml; +use crate::config_requirements::ConfigRequirementsWithSources; +use crate::config_requirements::RequirementSource; +use crate::config_requirements::SandboxModeRequirement; +use crate::config_toml::ConfigToml; +use crate::config_toml::ProjectConfig; +use crate::diagnostics::ConfigError; +use crate::diagnostics::config_error_from_toml; +use crate::diagnostics::first_layer_config_error_from_entries as typed_first_layer_config_error_from_entries; +use crate::diagnostics::io_error_from_config_error; +use crate::merge::merge_toml_values; +use crate::overrides::build_cli_overrides_layer; +use crate::project_root_markers::default_project_root_markers; +use crate::project_root_markers::project_root_markers_from_config; +use crate::state::ConfigLayerEntry; +use crate::state::ConfigLayerStack; +use crate::state::LoaderOverrides; +use crate::thread_config::ThreadConfigContext; +use crate::thread_config::ThreadConfigLoader; use codex_app_server_protocol::ConfigLayerSource; -use codex_config::CONFIG_TOML_FILE; -use codex_config::ConfigRequirementsWithSources; -use codex_config::ThreadConfigContext; -use codex_config::ThreadConfigLoader; -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; @@ -29,71 +41,14 @@ use std::path::Path; use std::path::PathBuf; use toml::Value as TomlValue; -pub use codex_config::AppRequirementToml; -pub use codex_config::AppsRequirementsToml; -pub use codex_config::CloudRequirementsLoadError; -pub use codex_config::CloudRequirementsLoadErrorCode; -pub use codex_config::CloudRequirementsLoader; -pub use codex_config::ConfigError; -pub use codex_config::ConfigLayerEntry; -pub use codex_config::ConfigLayerStack; -pub use codex_config::ConfigLayerStackOrdering; -pub use codex_config::ConfigLoadError; -pub use codex_config::ConfigRequirements; -pub use codex_config::ConfigRequirementsToml; -pub use codex_config::ConstrainedWithSource; -pub use codex_config::FeatureRequirementsToml; -pub use codex_config::FilesystemConstraints; -pub use codex_config::FilesystemDenyReadPattern; -pub use codex_config::HookEventsToml; -pub use codex_config::HookHandlerConfig; -pub use codex_config::LoaderOverrides; -pub use codex_config::ManagedHooksRequirementsToml; -pub use codex_config::MatcherGroup; -pub use codex_config::McpServerIdentity; -pub use codex_config::McpServerRequirement; -pub use codex_config::NetworkConstraints; -pub use codex_config::NetworkDomainPermissionToml; -pub use codex_config::NetworkDomainPermissionsToml; -pub use codex_config::NetworkRequirementsToml; -pub use codex_config::NetworkUnixSocketPermissionToml; -pub use codex_config::NetworkUnixSocketPermissionsToml; -pub use codex_config::RemoteSandboxConfigToml; -pub use codex_config::RequirementSource; -pub use codex_config::ResidencyRequirement; -pub use codex_config::SandboxModeRequirement; -pub use codex_config::Sourced; -pub use codex_config::TextPosition; -pub use codex_config::TextRange; -pub use codex_config::WebSearchModeRequirement; -pub(crate) use codex_config::build_cli_overrides_layer; -pub(crate) use codex_config::config_error_from_toml; -pub use codex_config::default_project_root_markers; -pub use codex_config::format_config_error; -pub use codex_config::format_config_error_with_source; -pub(crate) use codex_config::io_error_from_config_error; -pub use codex_config::merge_toml_values; -pub use codex_config::project_root_markers_from_config; -#[cfg(test)] -pub(crate) use codex_config::version_for_toml; - -/// On Unix systems, load default settings from this file path, if present. -/// Note that /etc/codex/ is treated as a "config folder," so subfolders such -/// as skills/ and rules/ will also be honored. -pub const SYSTEM_CONFIG_TOML_FILE_UNIX: &str = "/etc/codex/config.toml"; +#[cfg(unix)] +const SYSTEM_CONFIG_TOML_FILE_UNIX: &str = "/etc/codex/config.toml"; #[cfg(windows)] const DEFAULT_PROGRAM_DATA_DIR_WINDOWS: &str = r"C:\ProgramData"; -pub(crate) async fn first_layer_config_error(layers: &ConfigLayerStack) -> Option { - codex_config::first_layer_config_error::(layers, CONFIG_TOML_FILE).await -} - -pub(crate) async fn first_layer_config_error_from_entries( - layers: &[ConfigLayerEntry], -) -> Option { - codex_config::first_layer_config_error_from_entries::(layers, CONFIG_TOML_FILE) - .await +async fn first_layer_config_error_from_entries(layers: &[ConfigLayerEntry]) -> Option { + typed_first_layer_config_error_from_entries::(layers, CONFIG_TOML_FILE).await } /// To build up the set of admin-enforced constraints, we build up from multiple @@ -163,7 +118,7 @@ pub async fn load_config_layers_state( .await?; // Honor the system requirements.toml location. - let requirements_toml_file = system_requirements_toml_file()?; + let requirements_toml_file = system_requirements_toml_file_with_overrides(&overrides)?; load_requirements_toml( fs, &mut config_requirements_toml, @@ -175,7 +130,7 @@ pub async fn load_config_layers_state( // 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(fs, codex_home, overrides).await?; + layer_io::load_config_layers_internal(fs, codex_home, overrides.clone()).await?; load_requirements_from_legacy_scheme( &mut config_requirements_toml, loaded_config_layers.clone(), @@ -210,7 +165,7 @@ pub async fn load_config_layers_state( // Include an entry for the "system" config folder, loading its config.toml, // if it exists. - let system_config_toml_file = system_config_toml_file()?; + let system_config_toml_file = system_config_toml_file_with_overrides(&overrides)?; let system_layer = load_config_toml_for_required_layer(fs, &system_config_toml_file, |config_toml| { ConfigLayerEntry::new( @@ -428,7 +383,8 @@ async fn load_config_toml_for_required_layer( /// If available, apply requirements from the platform system /// `requirements.toml` location to `config_requirements_toml` by filling in /// any unset fields. -async fn load_requirements_toml( +#[doc(hidden)] +pub async fn load_requirements_toml( fs: &dyn ExecutorFileSystem, config_requirements_toml: &mut ConfigRequirementsWithSources, requirements_toml_file: &AbsolutePathBuf, @@ -494,16 +450,34 @@ fn system_requirements_toml_file() -> io::Result { windows_system_requirements_toml_file() } +fn system_requirements_toml_file_with_overrides( + overrides: &LoaderOverrides, +) -> io::Result { + match &overrides.system_requirements_path { + Some(path) => AbsolutePathBuf::from_absolute_path(path), + None => system_requirements_toml_file(), + } +} + #[cfg(unix)] -fn system_config_toml_file() -> io::Result { +pub fn system_config_toml_file() -> io::Result { AbsolutePathBuf::from_absolute_path(Path::new(SYSTEM_CONFIG_TOML_FILE_UNIX)) } #[cfg(windows)] -fn system_config_toml_file() -> io::Result { +pub fn system_config_toml_file() -> io::Result { windows_system_config_toml_file() } +fn system_config_toml_file_with_overrides( + overrides: &LoaderOverrides, +) -> io::Result { + match &overrides.system_config_path { + Some(path) => AbsolutePathBuf::from_absolute_path(path), + None => system_config_toml_file(), + } +} + #[cfg(windows)] fn windows_codex_system_dir() -> PathBuf { let program_data = windows_program_data_dir_from_known_folder().unwrap_or_else(|err| { @@ -844,7 +818,8 @@ fn project_trust_for_lookup_key( /// /// This ensures that multiple config layers can be merged together correctly /// even if they were loaded from different directories. -pub(crate) fn resolve_relative_paths_in_config_toml( +#[doc(hidden)] +pub fn resolve_relative_paths_in_config_toml( value_from_config_toml: TomlValue, base_dir: &Path, ) -> io::Result { diff --git a/codex-rs/config/src/state.rs b/codex-rs/config/src/state.rs index 92f36509f..6bb846edd 100644 --- a/codex-rs/config/src/state.rs +++ b/codex-rs/config/src/state.rs @@ -18,6 +18,8 @@ use toml::Value as TomlValue; #[derive(Debug, Default, Clone)] pub struct LoaderOverrides { pub managed_config_path: Option, + pub system_config_path: Option, + pub system_requirements_path: Option, pub ignore_user_config: bool, pub ignore_user_and_project_exec_policy_rules: bool, //TODO(gt): Add a macos_ prefix to this field and remove the target_os check. @@ -31,11 +33,17 @@ impl LoaderOverrides { /// /// This is intended for tests that should load only repo-controlled config fixtures. pub fn without_managed_config_for_tests() -> Self { - Self::with_managed_config_path_for_tests( - std::env::temp_dir() - .join("codex-config-tests") - .join("managed_config.toml"), - ) + let base = std::env::temp_dir().join("codex-config-tests"); + Self { + managed_config_path: Some(base.join("managed_config.toml")), + system_config_path: Some(base.join("config.toml")), + system_requirements_path: Some(base.join("requirements.toml")), + ignore_user_config: false, + ignore_user_and_project_exec_policy_rules: false, + #[cfg(target_os = "macos")] + managed_preferences_base64: Some(String::new()), + macos_managed_config_requirements_base64: Some(String::new()), + } } /// Returns overrides with host MDM disabled and managed config loaded from `managed_config_path`. @@ -44,11 +52,7 @@ impl LoaderOverrides { pub fn with_managed_config_path_for_tests(managed_config_path: PathBuf) -> Self { Self { managed_config_path: Some(managed_config_path), - ignore_user_config: false, - ignore_user_and_project_exec_policy_rules: false, - #[cfg(target_os = "macos")] - managed_preferences_base64: Some(String::new()), - macos_managed_config_requirements_base64: Some(String::new()), + ..Self::without_managed_config_for_tests() } } } diff --git a/codex-rs/config/src/types.rs b/codex-rs/config/src/types.rs index 6668e2531..114ded97e 100644 --- a/codex-rs/config/src/types.rs +++ b/codex-rs/config/src/types.rs @@ -12,15 +12,17 @@ pub use crate::mcp_types::McpServerTransportConfig; pub use crate::mcp_types::RawMcpServerConfig; pub use codex_protocol::config_types::AltScreenMode; pub use codex_protocol::config_types::ApprovalsReviewer; +use codex_protocol::config_types::EnvironmentVariablePattern; pub use codex_protocol::config_types::ModeKind; pub use codex_protocol::config_types::Personality; pub use codex_protocol::config_types::ServiceTier; +use codex_protocol::config_types::ShellEnvironmentPolicy; +use codex_protocol::config_types::ShellEnvironmentPolicyInherit; pub use codex_protocol::config_types::WebSearchMode; use codex_utils_absolute_path::AbsolutePathBuf; use std::collections::BTreeMap; use std::collections::HashMap; use std::fmt; -use wildmatch::WildMatchPattern; use schemars::JsonSchema; use serde::Deserialize; @@ -707,21 +709,6 @@ impl From for codex_app_server_protocol::SandboxSettings } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema)] -#[serde(rename_all = "kebab-case")] -pub enum ShellEnvironmentPolicyInherit { - /// "Core" environment variables for the platform. On UNIX, this would - /// include HOME, LOGNAME, PATH, SHELL, and USER, among others. - Core, - - /// Inherits the full environment from the parent process. - #[default] - All, - - /// Do not inherit any environment variables from the parent process. - None, -} - /// Policy for building the `env` when spawning a process via either the /// `shell` or `local_shell` tool. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)] @@ -742,37 +729,6 @@ pub struct ShellEnvironmentPolicyToml { pub experimental_use_profile: Option, } -pub type EnvironmentVariablePattern = WildMatchPattern<'*', '?'>; - -/// Deriving the `env` based on this policy works as follows: -/// 1. Create an initial map based on the `inherit` policy. -/// 2. If `ignore_default_excludes` is false, filter the map using the default -/// exclude pattern(s), which are: `"*KEY*"`, `"*SECRET*"`, and `"*TOKEN*"`. -/// 3. If `exclude` is not empty, filter the map using the provided patterns. -/// 4. Insert any entries from `r#set` into the map. -/// 5. If non-empty, filter the map using the `include_only` patterns. -#[derive(Debug, Clone, PartialEq)] -pub struct ShellEnvironmentPolicy { - /// Starting point when building the environment. - pub inherit: ShellEnvironmentPolicyInherit, - - /// True to skip the check to exclude default environment variables that - /// contain "KEY", "SECRET", or "TOKEN" in their name. Defaults to true. - pub ignore_default_excludes: bool, - - /// Environment variable names to exclude from the environment. - pub exclude: Vec, - - /// (key, value) pairs to insert in the environment. - pub r#set: HashMap, - - /// Environment variable names to retain in the environment. - pub include_only: Vec, - - /// If true, the shell profile will be used to run the command. - pub use_profile: bool, -} - impl From for ShellEnvironmentPolicy { fn from(toml: ShellEnvironmentPolicyToml) -> Self { // Default to inheriting the full environment when not specified. @@ -804,19 +760,6 @@ impl From for ShellEnvironmentPolicy { } } -impl Default for ShellEnvironmentPolicy { - fn default() -> Self { - Self { - inherit: ShellEnvironmentPolicyInherit::All, - ignore_default_excludes: true, - exclude: Vec::new(), - r#set: HashMap::new(), - include_only: Vec::new(), - use_profile: false, - } - } -} - #[cfg(test)] #[path = "types_tests.rs"] mod tests; diff --git a/codex-rs/core/Cargo.toml b/codex-rs/core/Cargo.toml index 42deea968..b8d3b146f 100644 --- a/codex-rs/core/Cargo.toml +++ b/codex-rs/core/Cargo.toml @@ -120,9 +120,6 @@ uuid = { workspace = true, features = ["serde", "v4", "v5"] } which = { workspace = true } whoami = { workspace = true } -[target.'cfg(target_os = "macos")'.dependencies] -core-foundation = "0.9" - # Build OpenSSL from source for musl builds. [target.x86_64-unknown-linux-musl.dependencies] openssl-sys = { workspace = true, features = ["vendored"] } @@ -131,13 +128,6 @@ openssl-sys = { workspace = true, features = ["vendored"] } [target.aarch64-unknown-linux-musl.dependencies] openssl-sys = { workspace = true, features = ["vendored"] } -[target.'cfg(target_os = "windows")'.dependencies] -windows-sys = { version = "0.52", features = [ - "Win32_Foundation", - "Win32_System_Com", - "Win32_UI_Shell", -] } - [target.'cfg(unix)'.dependencies] codex-shell-escalation = { workspace = true } diff --git a/codex-rs/core/src/agent/role.rs b/codex-rs/core/src/agent/role.rs index 0ee1de760..2ab16cd22 100644 --- a/codex-rs/core/src/agent/role.rs +++ b/codex-rs/core/src/agent/role.rs @@ -11,13 +11,13 @@ use crate::config::Config; use crate::config::ConfigOverrides; use crate::config::agent_roles::parse_agent_role_file_contents; use crate::config::deserialize_config_toml_with_base; -use crate::config_loader::ConfigLayerEntry; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::resolve_relative_paths_in_config_toml; use anyhow::anyhow; use codex_app_server_protocol::ConfigLayerSource; +use codex_config::ConfigLayerEntry; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; use codex_config::config_toml::ConfigToml; +use codex_config::loader::resolve_relative_paths_in_config_toml; use codex_exec_server::LOCAL_FS; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/codex-rs/core/src/agent/role_tests.rs b/codex-rs/core/src/agent/role_tests.rs index f379fbef1..d8b277db9 100644 --- a/codex-rs/core/src/agent/role_tests.rs +++ b/codex-rs/core/src/agent/role_tests.rs @@ -2,9 +2,9 @@ use super::*; use crate::SkillsManager; use crate::config::CONFIG_TOML_FILE; use crate::config::ConfigBuilder; -use crate::config_loader::ConfigLayerStackOrdering; use crate::plugins::PluginsManager; use crate::skills_load_input_from_config; +use codex_config::ConfigLayerStackOrdering; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::Verbosity; use codex_protocol::openai_models::ReasoningEffort; diff --git a/codex-rs/core/src/agents_md.rs b/codex-rs/core/src/agents_md.rs index b7fb7b11c..7a9fd7493 100644 --- a/codex-rs/core/src/agents_md.rs +++ b/codex-rs/core/src/agents_md.rs @@ -16,11 +16,11 @@ //! 3. We do **not** walk past the project root. use crate::config::Config; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::default_project_root_markers; -use crate::config_loader::merge_toml_values; -use crate::config_loader::project_root_markers_from_config; use codex_app_server_protocol::ConfigLayerSource; +use codex_config::ConfigLayerStackOrdering; +use codex_config::default_project_root_markers; +use codex_config::merge_toml_values; +use codex_config::project_root_markers_from_config; use codex_exec_server::Environment; use codex_exec_server::ExecutorFileSystem; use codex_features::Feature; diff --git a/codex-rs/core/src/config/agent_roles.rs b/codex-rs/core/src/config/agent_roles.rs index 898ddef8c..abdef33e7 100644 --- a/codex-rs/core/src/config/agent_roles.rs +++ b/codex-rs/core/src/config/agent_roles.rs @@ -1,6 +1,6 @@ use super::AgentRoleConfig; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; use codex_config::config_toml::AgentRoleToml; use codex_config::config_toml::AgentsToml; use codex_config::config_toml::ConfigToml; diff --git a/codex-rs/core/src/config_loader/tests.rs b/codex-rs/core/src/config/config_loader_tests.rs similarity index 95% rename from codex-rs/core/src/config_loader/tests.rs rename to codex-rs/core/src/config/config_loader_tests.rs index 82d621a5f..00d67ae1e 100644 --- a/codex-rs/core/src/config_loader/tests.rs +++ b/codex-rs/core/src/config/config_loader_tests.rs @@ -1,25 +1,29 @@ -use super::LoaderOverrides; -use super::load_config_layers_state; use crate::config::ConfigBuilder; use crate::config::ConfigOverrides; use crate::config::ConstraintError; -use crate::config_loader::CloudRequirementsLoadError; -use crate::config_loader::CloudRequirementsLoader; -use crate::config_loader::ConfigLayerEntry; -use crate::config_loader::ConfigLoadError; -use crate::config_loader::ConfigRequirements; -use crate::config_loader::ConfigRequirementsToml; -use crate::config_loader::ConfigRequirementsWithSources; -use crate::config_loader::FilesystemDenyReadPattern; -use crate::config_loader::RequirementSource; -use crate::config_loader::load_requirements_toml; -use crate::config_loader::version_for_toml; +use codex_app_server_protocol::ConfigLayerSource; use codex_config::CONFIG_TOML_FILE; +use codex_config::CloudRequirementsLoadError; +use codex_config::CloudRequirementsLoader; +use codex_config::ConfigError; +use codex_config::ConfigLayerEntry; +use codex_config::ConfigLayerStackOrdering; +use codex_config::ConfigLoadError; +use codex_config::ConfigRequirements; +use codex_config::ConfigRequirementsToml; +use codex_config::ConfigRequirementsWithSources; +use codex_config::FilesystemDenyReadPattern; +use codex_config::LoaderOverrides; +use codex_config::RequirementSource; use codex_config::SessionThreadConfig; use codex_config::StaticThreadConfigLoader; use codex_config::ThreadConfigSource; +use codex_config::config_error_from_toml; use codex_config::config_toml::ConfigToml; use codex_config::config_toml::ProjectConfig; +use codex_config::loader::load_config_layers_state; +use codex_config::loader::load_requirements_toml; +use codex_config::version_for_toml; use codex_exec_server::LOCAL_FS; use codex_protocol::config_types::TrustLevel; use codex_protocol::config_types::WebSearchMode; @@ -33,7 +37,7 @@ use std::path::Path; use tempfile::tempdir; use toml::Value as TomlValue; -fn config_error_from_io(err: &std::io::Error) -> &super::ConfigError { +fn config_error_from_io(err: &std::io::Error) -> &ConfigError { err.get_ref() .and_then(|err| err.downcast_ref::()) .map(ConfigLoadError::config_error) @@ -110,8 +114,7 @@ async fn returns_config_error_for_invalid_user_config_toml() { let config_error = config_error_from_io(&err); let expected_toml_error = toml::from_str::(contents).expect_err("parse error"); - let expected_config_error = - super::config_error_from_toml(&config_path, contents, expected_toml_error); + let expected_config_error = config_error_from_toml(&config_path, contents, expected_toml_error); assert_eq!(config_error, &expected_config_error); } @@ -202,7 +205,7 @@ async fn returns_config_error_for_invalid_managed_config_toml() { let config_error = config_error_from_io(&err); let expected_toml_error = toml::from_str::(contents).expect_err("parse error"); let expected_config_error = - super::config_error_from_toml(&managed_path, contents, expected_toml_error); + config_error_from_toml(&managed_path, contents, expected_toml_error); assert_eq!(config_error, &expected_config_error); } @@ -325,7 +328,7 @@ async fn returns_empty_when_all_layers_missing() { .expect("expected a user layer even when CODEX_HOME/config.toml does not exist"); assert_eq!( &ConfigLayerEntry { - name: super::ConfigLayerSource::User { + name: ConfigLayerSource::User { file: AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, tmp.path()) }, config: TomlValue::Table(toml::map::Map::new()), @@ -350,7 +353,7 @@ async fn returns_empty_when_all_layers_missing() { let num_system_layers = layers .layers_high_to_low() .iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::System { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::System { .. })) .count(); assert_eq!( num_system_layers, 1, @@ -374,12 +377,19 @@ async fn includes_thread_config_layers_in_stack() -> anyhow::Result<()> { let cwd_dir = tmp.path().join("project"); tokio::fs::create_dir_all(&cwd_dir).await?; let cwd = AbsolutePathBuf::from_absolute_path(&cwd_dir)?; + let overrides = LoaderOverrides::without_managed_config_for_tests(); + let expected_system_config = AbsolutePathBuf::from_absolute_path( + overrides + .system_config_path + .as_ref() + .expect("test overrides should include a system config path"), + )?; let layers = load_config_layers_state( LOCAL_FS.as_ref(), tmp.path(), Some(cwd), &[("features.plugins".to_string(), TomlValue::Boolean(true))], - LoaderOverrides::without_managed_config_for_tests(), + overrides, CloudRequirementsLoader::default(), &StaticThreadConfigLoader::new(vec![ThreadConfigSource::Session(SessionThreadConfig { features: BTreeMap::from([("plugins".to_string(), false)]), @@ -397,13 +407,13 @@ async fn includes_thread_config_layers_in_stack() -> anyhow::Result<()> { assert_eq!( layer_sources, vec![ - super::ConfigLayerSource::SessionFlags, - super::ConfigLayerSource::SessionFlags, - super::ConfigLayerSource::User { + ConfigLayerSource::SessionFlags, + ConfigLayerSource::SessionFlags, + ConfigLayerSource::User { file: AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, tmp.path()), }, - super::ConfigLayerSource::System { - file: super::system_config_toml_file()?, + ConfigLayerSource::System { + file: expected_system_config, }, ] ); @@ -482,7 +492,7 @@ flag = false .find(|layer| { matches!( layer.name, - super::ConfigLayerSource::LegacyManagedConfigTomlFromMdm + ConfigLayerSource::LegacyManagedConfigTomlFromMdm ) }) .expect("mdm layer"); @@ -687,14 +697,14 @@ personality = true .allowed_web_search_modes .as_deref() .cloned(), - Some(vec![crate::config_loader::WebSearchModeRequirement::Cached]) + Some(vec![codex_config::WebSearchModeRequirement::Cached]) ); assert_eq!( config_requirements_toml .feature_requirements .as_ref() .map(|requirements| requirements.value.clone()), - Some(crate::config_loader::FeatureRequirementsToml { + Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([("personality".to_string(), true)]), }) ); @@ -733,14 +743,14 @@ personality = true ); assert_eq!( config_requirements.enforce_residency.value(), - Some(crate::config_loader::ResidencyRequirement::Us) + Some(codex_config::ResidencyRequirement::Us) ); assert_eq!( config_requirements .feature_requirements .as_ref() .map(|requirements| requirements.value.clone()), - Some(crate::config_loader::FeatureRequirementsToml { + Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([("personality".to_string(), true)]), }) ); @@ -1174,8 +1184,8 @@ async fn load_config_layers_applies_matching_remote_sandbox_config() -> anyhow:: assert_eq!( layers.requirements_toml().allowed_sandbox_modes, Some(vec![ - crate::config_loader::SandboxModeRequirement::ReadOnly, - crate::config_loader::SandboxModeRequirement::WorkspaceWrite, + codex_config::SandboxModeRequirement::ReadOnly, + codex_config::SandboxModeRequirement::WorkspaceWrite, ]) ); assert!( @@ -1267,7 +1277,7 @@ async fn project_layers_prefer_closest_cwd() -> std::io::Result<()> { .layers_high_to_low() .into_iter() .filter_map(|layer| match &layer.name { - super::ConfigLayerSource::Project { dot_codex_folder } => Some(dot_codex_folder), + ConfigLayerSource::Project { dot_codex_folder } => Some(dot_codex_folder), _ => None, }) .collect(); @@ -1413,11 +1423,11 @@ async fn project_layer_is_added_when_dot_codex_exists_without_config_toml() -> s let project_layers: Vec<_> = layers .layers_high_to_low() .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); assert_eq!( vec![&ConfigLayerEntry { - name: super::ConfigLayerSource::Project { + name: ConfigLayerSource::Project { dot_codex_folder: AbsolutePathBuf::from_absolute_path(project_root.join(".codex"))?, }, config: TomlValue::Table(toml::map::Map::new()), @@ -1454,11 +1464,11 @@ async fn codex_home_is_not_loaded_as_project_layer_from_home_dir() -> std::io::R let project_layers: Vec<_> = layers .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); let expected: Vec<&ConfigLayerEntry> = Vec::new(); assert_eq!(expected, project_layers); @@ -1513,17 +1523,17 @@ async fn codex_home_within_project_tree_is_not_double_loaded() -> std::io::Resul let project_layers: Vec<_> = layers .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); let child_config: TomlValue = toml::from_str("foo = \"child\"\n").expect("parse child config"); assert_eq!( vec![&ConfigLayerEntry { - name: super::ConfigLayerSource::Project { + name: ConfigLayerSource::Project { dot_codex_folder: AbsolutePathBuf::from_absolute_path(&nested_dot_codex)?, }, config: child_config.clone(), @@ -1585,11 +1595,11 @@ async fn project_layers_disabled_when_untrusted_or_unknown() -> std::io::Result< .await?; let project_layers_untrusted: Vec<_> = layers_untrusted .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); assert_eq!(project_layers_untrusted.len(), 1); assert!( @@ -1626,11 +1636,11 @@ async fn project_layers_disabled_when_untrusted_or_unknown() -> std::io::Result< .await?; let project_layers_unknown: Vec<_> = layers_unknown .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); assert_eq!(project_layers_unknown.len(), 1); assert!( @@ -1695,11 +1705,11 @@ async fn project_trust_does_not_match_configured_alias_for_canonical_cwd() -> st let project_layers: Vec<_> = layers .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); assert_eq!(project_layers.len(), 1); assert!( @@ -1849,11 +1859,11 @@ async fn invalid_project_config_ignored_when_untrusted_or_unknown() -> std::io:: .await?; let project_layers: Vec<_> = layers .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); assert_eq!( project_layers.len(), @@ -1919,11 +1929,11 @@ async fn project_layer_without_config_toml_is_disabled_when_untrusted_or_unknown .await?; let project_layers: Vec<_> = layers .get_layers( - super::ConfigLayerStackOrdering::HighestPrecedenceFirst, + ConfigLayerStackOrdering::HighestPrecedenceFirst, /*include_disabled*/ true, ) .into_iter() - .filter(|layer| matches!(layer.name, super::ConfigLayerSource::Project { .. })) + .filter(|layer| matches!(layer.name, ConfigLayerSource::Project { .. })) .collect(); assert_eq!( project_layers.len(), @@ -2029,7 +2039,7 @@ async fn project_root_markers_supports_alternate_markers() -> std::io::Result<() .layers_high_to_low() .into_iter() .filter_map(|layer| match &layer.name { - super::ConfigLayerSource::Project { dot_codex_folder } => Some(dot_codex_folder), + ConfigLayerSource::Project { dot_codex_folder } => Some(dot_codex_folder), _ => None, }) .collect(); @@ -2051,14 +2061,14 @@ async fn project_root_markers_supports_alternate_markers() -> std::io::Result<() } mod requirements_exec_policy_tests { - use crate::config_loader::ConfigLayerEntry; - use crate::config_loader::ConfigLayerStack; - use crate::config_loader::ConfigRequirements; - use crate::config_loader::ConfigRequirementsToml; - use crate::config_loader::ConfigRequirementsWithSources; - use crate::config_loader::RequirementSource; use crate::exec_policy::load_exec_policy; use codex_app_server_protocol::ConfigLayerSource; + use codex_config::ConfigLayerEntry; + use codex_config::ConfigLayerStack; + use codex_config::ConfigRequirements; + use codex_config::ConfigRequirementsToml; + use codex_config::ConfigRequirementsWithSources; + use codex_config::RequirementSource; use codex_config::RequirementsExecPolicyDecisionToml; use codex_config::RequirementsExecPolicyParseError; use codex_config::RequirementsExecPolicyPatternTokenToml; diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 3b0dd3359..38dce5df3 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -4,11 +4,10 @@ use crate::config::ThreadStoreConfig; use crate::config::edit::ConfigEdit; use crate::config::edit::ConfigEditsBuilder; use crate::config::edit::apply_blocking; -use crate::config_loader::RequirementSource; -use crate::config_loader::project_trust_key; use crate::plugins::PluginsManager; use assert_matches::assert_matches; use codex_config::CONFIG_TOML_FILE; +use codex_config::RequirementSource; use codex_config::config_toml::AgentRoleToml; use codex_config::config_toml::AgentsToml; use codex_config::config_toml::AutoReviewToml; @@ -21,6 +20,7 @@ use codex_config::config_toml::RealtimeTransport; use codex_config::config_toml::RealtimeWsMode; use codex_config::config_toml::RealtimeWsVersion; use codex_config::config_toml::ToolsToml; +use codex_config::loader::project_trust_key; use codex_config::permissions_toml::FilesystemPermissionToml; use codex_config::permissions_toml::FilesystemPermissionsToml; use codex_config::permissions_toml::NetworkDomainPermissionToml; @@ -3981,7 +3981,7 @@ async fn load_config_uses_requirements_guardian_policy_config() -> std::io::Resu let config_layer_stack = ConfigLayerStack::new( Vec::new(), Default::default(), - crate::config_loader::ConfigRequirementsToml { + codex_config::ConfigRequirementsToml { guardian_policy_config: Some( " Use the workspace-managed guardian policy. ".to_string(), ), @@ -4062,7 +4062,7 @@ async fn requirements_guardian_policy_beats_auto_review() -> std::io::Result<()> let config_layer_stack = ConfigLayerStack::new( Vec::new(), Default::default(), - crate::config_loader::ConfigRequirementsToml { + codex_config::ConfigRequirementsToml { guardian_policy_config: Some("Use the managed guardian policy.".to_string()), ..Default::default() }, @@ -4126,7 +4126,7 @@ async fn load_config_ignores_empty_requirements_guardian_policy_config() -> std: let config_layer_stack = ConfigLayerStack::new( Vec::new(), Default::default(), - crate::config_loader::ConfigRequirementsToml { + codex_config::ConfigRequirementsToml { guardian_policy_config: Some(" ".to_string()), ..Default::default() }, @@ -4258,15 +4258,15 @@ config_file = "./agents/researcher.toml" "#, ) .expect("agent role layer config should parse"); - let config_layer_stack = crate::config_loader::ConfigLayerStack::new( - vec![crate::config_loader::ConfigLayerEntry::new( + let config_layer_stack = codex_config::ConfigLayerStack::new( + vec![codex_config::ConfigLayerEntry::new( codex_app_server_protocol::ConfigLayerSource::User { file: codex_home.path().join(CONFIG_TOML_FILE).abs(), }, layer_config, )], Default::default(), - crate::config_loader::ConfigRequirementsToml::default(), + codex_config::ConfigRequirementsToml::default(), ) .map_err(std::io::Error::other)?; @@ -6035,14 +6035,12 @@ async fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset() { let fixture = create_test_fixture()?; - let requirements_toml = crate::config_loader::ConfigRequirementsToml { + let requirements_toml = codex_config::ConfigRequirementsToml { allowed_approval_policies: None, allowed_approvals_reviewers: None, allowed_sandbox_modes: None, remote_sandbox_config: None, - allowed_web_search_modes: Some(vec![ - crate::config_loader::WebSearchModeRequirement::Cached, - ]), + allowed_web_search_modes: Some(vec![codex_config::WebSearchModeRequirement::Cached]), feature_requirements: None, hooks: None, mcp_servers: None, @@ -6053,7 +6051,7 @@ async fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset() permissions: None, guardian_policy_config: None, }; - let requirement_source = crate::config_loader::RequirementSource::Unknown; + let requirement_source = codex_config::RequirementSource::Unknown; let requirement_source_for_error = requirement_source.clone(); let allowed = vec![WebSearchMode::Disabled, WebSearchMode::Cached]; let constrained = Constrained::new(WebSearchMode::Cached, move |candidate| { @@ -6068,15 +6066,15 @@ async fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset() }) } })?; - let requirements = crate::config_loader::ConfigRequirements { - web_search_mode: crate::config_loader::ConstrainedWithSource::new( + let requirements = codex_config::ConfigRequirements { + web_search_mode: codex_config::ConstrainedWithSource::new( constrained, Some(requirement_source), ), ..Default::default() }; let config_layer_stack = - crate::config_loader::ConfigLayerStack::new(Vec::new(), requirements, requirements_toml) + codex_config::ConfigLayerStack::new(Vec::new(), requirements, requirements_toml) .expect("config layer stack"); let config = Config::load_config_with_layer_stack( @@ -6688,10 +6686,8 @@ async fn requirements_disallowing_default_sandbox_falls_back_to_required_default let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - allowed_sandbox_modes: Some(vec![ - crate::config_loader::SandboxModeRequirement::ReadOnly, - ]), + Ok(Some(codex_config::ConfigRequirementsToml { + allowed_sandbox_modes: Some(vec![codex_config::SandboxModeRequirement::ReadOnly]), ..Default::default() })) })) @@ -6713,10 +6709,10 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s "#, )?; - let requirements = crate::config_loader::ConfigRequirementsToml { + let requirements = codex_config::ConfigRequirementsToml { allowed_approval_policies: None, allowed_approvals_reviewers: None, - allowed_sandbox_modes: Some(vec![crate::config_loader::SandboxModeRequirement::ReadOnly]), + allowed_sandbox_modes: Some(vec![codex_config::SandboxModeRequirement::ReadOnly]), remote_sandbox_config: None, allowed_web_search_modes: None, feature_requirements: None, @@ -6793,9 +6789,9 @@ async fn requirements_web_search_mode_overrides_danger_full_access_default() -> .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_web_search_modes: Some(vec![ - crate::config_loader::WebSearchModeRequirement::Cached, + codex_config::WebSearchModeRequirement::Cached, ]), ..Default::default() })) @@ -6834,7 +6830,7 @@ trust_level = "untrusted" .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(workspace.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_approval_policies: Some(vec![AskForApproval::OnRequest]), ..Default::default() })) @@ -6863,7 +6859,7 @@ async fn explicit_approval_policy_falls_back_when_disallowed_by_requirements() - .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_approval_policies: Some(vec![AskForApproval::OnRequest]), ..Default::default() })) @@ -6884,8 +6880,8 @@ async fn feature_requirements_normalize_effective_feature_values() -> std::io::R let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([ ("personality".to_string(), true), ("shell_tool".to_string(), false), @@ -6918,8 +6914,8 @@ async fn feature_requirements_auto_review_disables_guardian_approval() -> std::i let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([("auto_review".to_string(), false)]), }), ..Default::default() @@ -6940,8 +6936,8 @@ async fn browser_feature_requirements_are_valid() -> std::io::Result<()> { let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([ ("in_app_browser".to_string(), false), ("browser_use".to_string(), false), @@ -6975,8 +6971,8 @@ shell_tool = true .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([ ("personality".to_string(), true), ("shell_tool".to_string(), false), @@ -7122,7 +7118,7 @@ async fn requirements_disallowing_default_approvals_reviewer_falls_back_to_requi let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_approvals_reviewers: Some(vec![ApprovalsReviewer::AutoReview]), ..Default::default() })) @@ -7148,7 +7144,7 @@ async fn root_approvals_reviewer_falls_back_when_disallowed_by_requirements() -> .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_approvals_reviewers: Some(vec![ApprovalsReviewer::AutoReview]), ..Default::default() })) @@ -7185,7 +7181,7 @@ approvals_reviewer = "user" .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_approvals_reviewers: Some(vec![ApprovalsReviewer::AutoReview]), ..Default::default() })) @@ -7211,7 +7207,7 @@ async fn approvals_reviewer_preserves_valid_user_choice_when_allowed_by_requirem .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { allowed_approvals_reviewers: Some(vec![ ApprovalsReviewer::User, ApprovalsReviewer::AutoReview, @@ -7363,8 +7359,8 @@ async fn feature_requirements_normalize_runtime_feature_mutations() -> std::io:: let mut config = ConfigBuilder::default() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([ ("personality".to_string(), true), ("shell_tool".to_string(), false), @@ -7399,8 +7395,8 @@ async fn feature_requirements_warn_on_collab_legacy_alias() -> std::io::Result<( let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([("collab".to_string(), true)]), }), ..Default::default() @@ -7429,8 +7425,8 @@ async fn feature_requirements_warn_and_ignore_unknown_feature() -> std::io::Resu let config = ConfigBuilder::without_managed_config_for_tests() .codex_home(codex_home.path().to_path_buf()) .cloud_requirements(CloudRequirementsLoader::new(async { - Ok(Some(crate::config_loader::ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + Ok(Some(codex_config::ConfigRequirementsToml { + feature_requirements: Some(codex_config::FeatureRequirementsToml { entries: BTreeMap::from([("made_up_feature".to_string(), true)]), }), ..Default::default() diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index c7f13c63d..e8c83fe95 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -1,20 +1,6 @@ use crate::agents_md::AgentsMdManager; use crate::config::edit::ConfigEdit; use crate::config::edit::ConfigEditsBuilder; -use crate::config_loader::CloudRequirementsLoader; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::ConfigRequirements; -use crate::config_loader::ConfigRequirementsToml; -use crate::config_loader::ConstrainedWithSource; -use crate::config_loader::FeatureRequirementsToml; -use crate::config_loader::LoaderOverrides; -use crate::config_loader::McpServerIdentity; -use crate::config_loader::McpServerRequirement; -use crate::config_loader::ResidencyRequirement; -use crate::config_loader::Sourced; -use crate::config_loader::load_config_layers_state; -use crate::config_loader::project_trust_key; use crate::memories::memory_root; use crate::path_utils::normalize_for_native_workdir; use crate::unified_exec::DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS; @@ -22,6 +8,18 @@ use crate::unified_exec::MIN_EMPTY_YIELD_TIME_MS; use crate::windows_sandbox::WindowsSandboxLevelExt; use crate::windows_sandbox::resolve_windows_sandbox_mode; use crate::windows_sandbox::resolve_windows_sandbox_private_desktop; +use codex_config::CloudRequirementsLoader; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::ConfigRequirements; +use codex_config::ConfigRequirementsToml; +use codex_config::ConstrainedWithSource; +use codex_config::FeatureRequirementsToml; +use codex_config::LoaderOverrides; +use codex_config::McpServerIdentity; +use codex_config::McpServerRequirement; +use codex_config::ResidencyRequirement; +use codex_config::Sourced; use codex_config::ThreadConfigLoader; use codex_config::config_toml::ConfigToml; use codex_config::config_toml::ProjectConfig; @@ -29,6 +27,8 @@ use codex_config::config_toml::RealtimeAudioConfig; use codex_config::config_toml::RealtimeConfig; use codex_config::config_toml::ThreadStoreToml; use codex_config::config_toml::validate_model_providers; +use codex_config::loader::load_config_layers_state; +use codex_config::loader::project_trust_key; use codex_config::profile_toml::ConfigProfile; use codex_config::types::ApprovalsReviewer; use codex_config::types::AuthCredentialsStoreMode; @@ -44,7 +44,6 @@ use codex_config::types::OAuthCredentialsStoreMode; use codex_config::types::OtelConfig; use codex_config::types::OtelConfigToml; use codex_config::types::OtelExporterKind; -use codex_config::types::ShellEnvironmentPolicy; use codex_config::types::ToolSuggestConfig; use codex_config::types::ToolSuggestDiscoverable; use codex_config::types::TuiNotificationSettings; @@ -74,6 +73,7 @@ use codex_protocol::config_types::Personality; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::SandboxMode; use codex_protocol::config_types::ServiceTier; +use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::config_types::TrustLevel; use codex_protocol::config_types::Verbosity; use codex_protocol::config_types::WebSearchConfig; @@ -876,10 +876,13 @@ impl ConfigBuilder { let config_toml: ConfigToml = match merged_toml.try_into() { Ok(config_toml) => config_toml, Err(err) => { - if let Some(config_error) = - crate::config_loader::first_layer_config_error(&config_layer_stack).await + if let Some(config_error) = codex_config::first_layer_config_error::( + &config_layer_stack, + codex_config::CONFIG_TOML_FILE, + ) + .await { - return Err(crate::config_loader::io_error_from_config_error( + return Err(codex_config::io_error_from_config_error( std::io::ErrorKind::InvalidData, config_error, Some(err), @@ -979,8 +982,8 @@ impl Config { format!("failed to serialize default config: {e}"), ) })?; - let cli_layer = crate::config_loader::build_cli_overrides_layer(&cli_overrides); - crate::config_loader::merge_toml_values(&mut merged, &cli_layer); + let cli_layer = codex_config::build_cli_overrides_layer(&cli_overrides); + codex_config::merge_toml_values(&mut merged, &cli_layer); let codex_home = AbsolutePathBuf::from_absolute_path_checked(codex_home)?; let config_toml = deserialize_config_toml_with_base(merged, &codex_home)?; Self::load_config_with_layer_stack( @@ -1462,7 +1465,7 @@ fn resolve_permission_config_syntax( fn apply_managed_filesystem_constraints( file_system_sandbox_policy: &mut FileSystemSandboxPolicy, - filesystem_constraints: &crate::config_loader::FilesystemConstraints, + filesystem_constraints: &codex_config::FilesystemConstraints, ) { for deny_read in &filesystem_constraints.deny_read { let deny_entry = if deny_read.contains_glob() { @@ -2801,3 +2804,7 @@ pub fn log_dir(cfg: &Config) -> std::io::Result { #[cfg(test)] #[path = "config_tests.rs"] mod tests; + +#[cfg(test)] +#[path = "config_loader_tests.rs"] +mod config_loader_tests; diff --git a/codex-rs/core/src/config/network_proxy_spec.rs b/codex-rs/core/src/config/network_proxy_spec.rs index acabe24f2..1bb5e1c9f 100644 --- a/codex-rs/core/src/config/network_proxy_spec.rs +++ b/codex-rs/core/src/config/network_proxy_spec.rs @@ -1,5 +1,5 @@ -use crate::config_loader::NetworkConstraints; use async_trait::async_trait; +use codex_config::NetworkConstraints; use codex_execpolicy::Policy; use codex_network_proxy::BlockedRequestObserver; use codex_network_proxy::ConfigReloader; diff --git a/codex-rs/core/src/config/network_proxy_spec_tests.rs b/codex-rs/core/src/config/network_proxy_spec_tests.rs index 5ba4bd153..fb4231aca 100644 --- a/codex-rs/core/src/config/network_proxy_spec_tests.rs +++ b/codex-rs/core/src/config/network_proxy_spec_tests.rs @@ -1,6 +1,6 @@ use super::*; -use crate::config_loader::NetworkDomainPermissionToml; -use crate::config_loader::NetworkDomainPermissionsToml; +use codex_config::NetworkDomainPermissionToml; +use codex_config::NetworkDomainPermissionsToml; use codex_network_proxy::NetworkDomainPermission; use pretty_assertions::assert_eq; diff --git a/codex-rs/core/src/connectors.rs b/codex-rs/core/src/connectors.rs index 4c710e3a3..456f3a7ea 100644 --- a/codex-rs/core/src/connectors.rs +++ b/codex-rs/core/src/connectors.rs @@ -25,11 +25,11 @@ use serde::de::DeserializeOwned; use tracing::warn; use crate::config::Config; -use crate::config_loader::AppsRequirementsToml; use crate::mcp::McpManager; use crate::plugins::PluginsManager; use crate::plugins::list_tool_suggest_discoverable_plugins; use crate::session::INITIAL_SUBMIT_ID; +use codex_config::AppsRequirementsToml; use codex_config::types::AppToolApproval; use codex_config::types::AppsConfigToml; use codex_config::types::ToolSuggestDiscoverableType; diff --git a/codex-rs/core/src/connectors_tests.rs b/codex-rs/core/src/connectors_tests.rs index 0f9e834d8..885b573da 100644 --- a/codex-rs/core/src/connectors_tests.rs +++ b/codex-rs/core/src/connectors_tests.rs @@ -1,12 +1,12 @@ use super::*; use crate::config::CONFIG_TOML_FILE; use crate::config::ConfigBuilder; -use crate::config_loader::AppRequirementToml; -use crate::config_loader::AppsRequirementsToml; -use crate::config_loader::CloudRequirementsLoader; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigRequirements; -use crate::config_loader::ConfigRequirementsToml; +use codex_config::AppRequirementToml; +use codex_config::AppsRequirementsToml; +use codex_config::CloudRequirementsLoader; +use codex_config::ConfigLayerStack; +use codex_config::ConfigRequirements; +use codex_config::ConfigRequirementsToml; use codex_config::types::AppConfig; use codex_config::types::AppToolConfig; use codex_config::types::AppToolsConfig; diff --git a/codex-rs/core/src/exec_env.rs b/codex-rs/core/src/exec_env.rs index ad94bc51a..938667b12 100644 --- a/codex-rs/core/src/exec_env.rs +++ b/codex-rs/core/src/exec_env.rs @@ -1,10 +1,11 @@ -#[cfg(test)] -use codex_config::types::EnvironmentVariablePattern; -use codex_config::types::ShellEnvironmentPolicy; use codex_protocol::ThreadId; +#[cfg(test)] +use codex_protocol::config_types::EnvironmentVariablePattern; +use codex_protocol::config_types::ShellEnvironmentPolicy; +use codex_protocol::shell_environment; use std::collections::HashMap; -pub use codex_config::shell_environment::CODEX_THREAD_ID_ENV_VAR; +pub use codex_protocol::shell_environment::CODEX_THREAD_ID_ENV_VAR; /// Construct an environment map based on the rules in the specified policy. The /// resulting map can be passed directly to `Command::envs()` after calling @@ -21,7 +22,7 @@ pub fn create_env( thread_id: Option, ) -> HashMap { let thread_id = thread_id.map(|thread_id| thread_id.to_string()); - codex_config::shell_environment::create_env(policy, thread_id.as_deref()) + shell_environment::create_env(policy, thread_id.as_deref()) } #[cfg(all(test, target_os = "windows"))] @@ -34,7 +35,7 @@ where I: IntoIterator, { let thread_id = thread_id.map(|thread_id| thread_id.to_string()); - codex_config::shell_environment::create_env_from_vars(vars, policy, thread_id.as_deref()) + shell_environment::create_env_from_vars(vars, policy, thread_id.as_deref()) } #[cfg(test)] @@ -47,7 +48,7 @@ where I: IntoIterator, { let thread_id = thread_id.map(|thread_id| thread_id.to_string()); - codex_config::shell_environment::populate_env(vars, policy, thread_id.as_deref()) + shell_environment::populate_env(vars, policy, thread_id.as_deref()) } #[cfg(test)] diff --git a/codex-rs/core/src/exec_env_tests.rs b/codex-rs/core/src/exec_env_tests.rs index 81b5c0bb3..725edd8cc 100644 --- a/codex-rs/core/src/exec_env_tests.rs +++ b/codex-rs/core/src/exec_env_tests.rs @@ -1,5 +1,5 @@ use super::*; -use codex_config::types::ShellEnvironmentPolicyInherit; +use codex_protocol::config_types::ShellEnvironmentPolicyInherit; use maplit::hashmap; use pretty_assertions::assert_eq; diff --git a/codex-rs/core/src/exec_policy.rs b/codex-rs/core/src/exec_policy.rs index 54ad8058d..9fbb5b015 100644 --- a/codex-rs/core/src/exec_policy.rs +++ b/codex-rs/core/src/exec_policy.rs @@ -5,9 +5,9 @@ use std::sync::Arc; use arc_swap::ArcSwap; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; use codex_app_server_protocol::ConfigLayerSource; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; use codex_execpolicy::AmendError; use codex_execpolicy::Decision; use codex_execpolicy::Error as ExecPolicyRuleError; diff --git a/codex-rs/core/src/exec_policy_tests.rs b/codex-rs/core/src/exec_policy_tests.rs index fe4560a78..c1f6aa0e6 100644 --- a/codex-rs/core/src/exec_policy_tests.rs +++ b/codex-rs/core/src/exec_policy_tests.rs @@ -1,17 +1,17 @@ use super::*; use crate::config::Config; use crate::config::ConfigBuilder; -use crate::config_loader::ConfigLayerEntry; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::ConfigRequirements; -use crate::config_loader::ConfigRequirementsToml; -use crate::config_loader::LoaderOverrides; -use crate::config_loader::RequirementSource; -use crate::config_loader::Sourced; use codex_app_server_protocol::ConfigLayerSource; use codex_config::CONFIG_TOML_FILE; +use codex_config::ConfigLayerEntry; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::ConfigRequirements; +use codex_config::ConfigRequirementsToml; +use codex_config::LoaderOverrides; +use codex_config::RequirementSource; use codex_config::RequirementsExecPolicy; +use codex_config::Sourced; use codex_config::config_toml::ConfigToml; use codex_config::config_toml::ProjectConfig; use codex_protocol::config_types::TrustLevel; diff --git a/codex-rs/core/src/guardian/tests.rs b/codex-rs/core/src/guardian/tests.rs index c78884bce..76b4a8464 100644 --- a/codex-rs/core/src/guardian/tests.rs +++ b/codex-rs/core/src/guardian/tests.rs @@ -5,18 +5,18 @@ use crate::config::Constrained; use crate::config::ManagedFeatures; use crate::config::NetworkProxySpec; use crate::config::test_config; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::FeatureRequirementsToml; -use crate::config_loader::NetworkConstraints; -use crate::config_loader::NetworkDomainPermissionToml; -use crate::config_loader::NetworkDomainPermissionsToml; -use crate::config_loader::RequirementSource; -use crate::config_loader::Sourced; use crate::guardian::approval_request::guardian_request_target_item_id; use crate::session::session::Session; use crate::session::turn_context::TurnContext; use crate::test_support; use codex_analytics::GuardianApprovalRequestSource; +use codex_config::ConfigLayerStack; +use codex_config::FeatureRequirementsToml; +use codex_config::NetworkConstraints; +use codex_config::NetworkDomainPermissionToml; +use codex_config::NetworkDomainPermissionsToml; +use codex_config::RequirementSource; +use codex_config::Sourced; use codex_config::config_toml::ConfigToml; use codex_config::types::McpServerConfig; use codex_exec_server::LOCAL_FS; @@ -2122,7 +2122,7 @@ async fn guardian_review_session_config_uses_requirements_guardian_policy_config let config_layer_stack = ConfigLayerStack::new( Vec::new(), Default::default(), - crate::config_loader::ConfigRequirementsToml { + codex_config::ConfigRequirementsToml { guardian_policy_config: Some( " Use the workspace-managed guardian policy. ".to_string(), ), diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index 3e2d2ee52..c6f879209 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -25,7 +25,6 @@ mod codex_delegate; mod command_canonicalization; mod commit_attribution; pub mod config; -pub mod config_loader; pub mod connectors; pub mod context; mod context_manager; diff --git a/codex-rs/core/src/network_proxy_loader.rs b/codex-rs/core/src/network_proxy_loader.rs index 78428fabf..f168b79f4 100644 --- a/codex-rs/core/src/network_proxy_loader.rs +++ b/codex-rs/core/src/network_proxy_loader.rs @@ -1,10 +1,5 @@ use crate::config::find_codex_home; use crate::config::resolve_permission_profile; -use crate::config_loader::CloudRequirementsLoader; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::LoaderOverrides; -use crate::config_loader::load_config_layers_state; use crate::exec_policy::ExecPolicyError; use crate::exec_policy::format_exec_policy_error_with_source; use crate::exec_policy::load_exec_policy; @@ -13,6 +8,11 @@ use anyhow::Result; use async_trait::async_trait; use codex_app_server_protocol::ConfigLayerSource; use codex_config::CONFIG_TOML_FILE; +use codex_config::CloudRequirementsLoader; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::LoaderOverrides; +use codex_config::loader::load_config_layers_state; use codex_config::permissions_toml::NetworkToml; use codex_config::permissions_toml::PermissionsToml; use codex_config::permissions_toml::overlay_network_domain_permissions; diff --git a/codex-rs/core/src/plugins/manager.rs b/codex-rs/core/src/plugins/manager.rs index 77265ece7..880ad8ed2 100644 --- a/codex-rs/core/src/plugins/manager.rs +++ b/codex-rs/core/src/plugins/manager.rs @@ -4,8 +4,8 @@ use crate::SkillMetadata; use crate::config::Config; use crate::config::edit::ConfigEdit; use crate::config::edit::ConfigEditsBuilder; -use crate::config_loader::ConfigLayerStack; use codex_analytics::AnalyticsEventsClient; +use codex_config::ConfigLayerStack; use codex_config::types::PluginConfig; use codex_core_plugins::OPENAI_CURATED_MARKETPLACE_NAME; use codex_core_plugins::installed_marketplaces::installed_marketplace_roots_from_layer_stack; diff --git a/codex-rs/core/src/plugins/manager_tests.rs b/codex-rs/core/src/plugins/manager_tests.rs index c8bbba01b..2c5c6805b 100644 --- a/codex-rs/core/src/plugins/manager_tests.rs +++ b/codex-rs/core/src/plugins/manager_tests.rs @@ -1,10 +1,6 @@ use super::*; use crate::config::CONFIG_TOML_FILE; use crate::config::ConfigBuilder; -use crate::config_loader::ConfigLayerEntry; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigRequirements; -use crate::config_loader::ConfigRequirementsToml; use crate::plugins::LoadedPlugin; use crate::plugins::PluginLoadOutcome; use crate::plugins::test_support::TEST_CURATED_PLUGIN_CACHE_VERSION; @@ -13,6 +9,10 @@ use crate::plugins::test_support::write_curated_plugin_sha_with as write_curated use crate::plugins::test_support::write_file; use crate::plugins::test_support::write_openai_curated_marketplace; use codex_app_server_protocol::ConfigLayerSource; +use codex_config::ConfigLayerEntry; +use codex_config::ConfigLayerStack; +use codex_config::ConfigRequirements; +use codex_config::ConfigRequirementsToml; use codex_config::McpServerConfig; use codex_config::types::McpServerTransportConfig; use codex_core_plugins::installed_marketplaces::marketplace_install_root; diff --git a/codex-rs/core/src/session/handlers.rs b/codex-rs/core/src/session/handlers.rs index 16f4f9b6b..8055b8f3a 100644 --- a/codex-rs/core/src/session/handlers.rs +++ b/codex-rs/core/src/session/handlers.rs @@ -14,14 +14,14 @@ use crate::session::session::Session; use crate::session::session::SessionSettingsUpdate; use crate::config::Config; -use crate::config_loader::CloudRequirementsLoader; -use crate::config_loader::LoaderOverrides; -use crate::config_loader::load_config_layers_state; use crate::realtime_context::REALTIME_TURN_TOKEN_BUDGET; 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 crate::session::spawn_review_thread; +use codex_config::CloudRequirementsLoader; +use codex_config::LoaderOverrides; +use codex_config::loader::load_config_layers_state; use codex_exec_server::LOCAL_FS; use codex_features::Feature; use codex_utils_absolute_path::AbsolutePathBuf; diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index 3eb6fdddf..866458a2c 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -176,8 +176,8 @@ use crate::context_manager::TotalTokenUsageBreakdown; use crate::thread_rollout_truncation::initial_history_has_prior_user_turns; use codex_config::CONFIG_TOML_FILE; use codex_config::types::McpServerConfig; -use codex_config::types::ShellEnvironmentPolicy; use codex_model_provider_info::ModelProviderInfo; +use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::error::CodexErr; use codex_protocol::error::Result as CodexResult; #[cfg(test)] diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 0206ee460..6b1bddbb8 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -2,14 +2,6 @@ use super::turn_context::TurnEnvironment; use super::*; use crate::config::ConfigBuilder; use crate::config::test_config; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::NetworkConstraints; -use crate::config_loader::NetworkDomainPermissionToml; -use crate::config_loader::NetworkDomainPermissionsToml; -use crate::config_loader::RequirementSource; -use crate::config_loader::Sourced; -use crate::config_loader::project_trust_key; use crate::context::ContextualUserFragment; use crate::context::TurnAborted; use crate::exec::ExecCapturePolicy; @@ -19,6 +11,14 @@ use crate::skills::SkillRenderSideEffects; use crate::skills::render::SkillMetadataBudget; use crate::test_support::models_manager_with_provider; use crate::tools::format_exec_output_str; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::NetworkConstraints; +use codex_config::NetworkDomainPermissionToml; +use codex_config::NetworkDomainPermissionsToml; +use codex_config::RequirementSource; +use codex_config::Sourced; +use codex_config::loader::project_trust_key; use codex_features::Feature; use codex_features::Features; @@ -925,7 +925,7 @@ async fn danger_full_access_tool_attempts_do_not_enforce_managed_network() -> an RequirementSource::CloudRequirements, )); let mut requirements_toml = config.config_layer_stack.requirements_toml().clone(); - requirements_toml.network = Some(crate::config_loader::NetworkRequirementsToml { + requirements_toml.network = Some(codex_config::NetworkRequirementsToml { enabled: Some(true), ..Default::default() }); diff --git a/codex-rs/core/src/session/tests/guardian_tests.rs b/codex-rs/core/src/session/tests/guardian_tests.rs index d76660b29..ed6c6b60e 100644 --- a/codex-rs/core/src/session/tests/guardian_tests.rs +++ b/codex-rs/core/src/session/tests/guardian_tests.rs @@ -1,8 +1,5 @@ use super::*; use crate::compact::InitialContextInjection; -use crate::config_loader::ConfigLayerEntry; -use crate::config_loader::ConfigRequirements; -use crate::config_loader::ConfigRequirementsToml; use crate::exec::ExecCapturePolicy; use crate::exec::ExecParams; use crate::exec_policy::ExecPolicyManager; @@ -13,6 +10,9 @@ use crate::tools::context::FunctionToolOutput; use crate::tools::context::ToolCallSource; use crate::turn_diff_tracker::TurnDiffTracker; use codex_app_server_protocol::ConfigLayerSource; +use codex_config::ConfigLayerEntry; +use codex_config::ConfigRequirements; +use codex_config::ConfigRequirementsToml; use codex_exec_server::EnvironmentManager; use codex_execpolicy::Decision; use codex_execpolicy::Evaluation; diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index 705a9ecb4..ee1da9b00 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -18,7 +18,6 @@ use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHa use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2; use crate::tools::handlers::multi_agents_v2::WaitAgentHandler as WaitAgentHandlerV2; use crate::turn_diff_tracker::TurnDiffTracker; -use codex_config::types::ShellEnvironmentPolicy; use codex_features::Feature; use codex_login::AuthManager; use codex_login::CodexAuth; @@ -26,6 +25,7 @@ use codex_model_provider::create_model_provider; use codex_model_provider_info::built_in_model_providers; use codex_protocol::AgentPath; use codex_protocol::ThreadId; +use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::models::BaseInstructions; use codex_protocol::models::ContentItem; use codex_protocol::models::FunctionCallOutputBody; diff --git a/codex-rs/core/src/unified_exec/process_manager.rs b/codex-rs/core/src/unified_exec/process_manager.rs index bd4452ce1..b1b5c62b0 100644 --- a/codex-rs/core/src/unified_exec/process_manager.rs +++ b/codex-rs/core/src/unified_exec/process_manager.rs @@ -50,7 +50,7 @@ use crate::unified_exec::process::OutputBuffer; use crate::unified_exec::process::OutputHandles; use crate::unified_exec::process::SpawnLifecycleHandle; use crate::unified_exec::process::UnifiedExecProcess; -use codex_config::types::ShellEnvironmentPolicy; +use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::error::CodexErr; use codex_protocol::error::SandboxErr; use codex_protocol::protocol::ExecCommandSource; diff --git a/codex-rs/core/src/unified_exec/process_manager_tests.rs b/codex-rs/core/src/unified_exec/process_manager_tests.rs index 955c37bd5..78b004795 100644 --- a/codex-rs/core/src/unified_exec/process_manager_tests.rs +++ b/codex-rs/core/src/unified_exec/process_manager_tests.rs @@ -91,7 +91,7 @@ fn exec_server_params_use_env_policy_overlay_contract() { ]), exec_server_env_config: Some(ExecServerEnvConfig { policy: codex_exec_server::ExecEnvPolicy { - inherit: codex_config::types::ShellEnvironmentPolicyInherit::Core, + inherit: codex_protocol::config_types::ShellEnvironmentPolicyInherit::Core, ignore_default_excludes: false, exclude: Vec::new(), r#set: HashMap::new(), diff --git a/codex-rs/core/tests/suite/approvals.rs b/codex-rs/core/tests/suite/approvals.rs index 9358506a2..0888c91c4 100644 --- a/codex-rs/core/tests/suite/approvals.rs +++ b/codex-rs/core/tests/suite/approvals.rs @@ -2,15 +2,15 @@ use anyhow::Context; use anyhow::Result; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::NetworkConstraints; +use codex_config::NetworkRequirementsToml; +use codex_config::RequirementSource; +use codex_config::Sourced; use codex_config::types::ApprovalsReviewer; use codex_core::CodexThread; use codex_core::config::Constrained; -use codex_core::config_loader::ConfigLayerStack; -use codex_core::config_loader::ConfigLayerStackOrdering; -use codex_core::config_loader::NetworkConstraints; -use codex_core::config_loader::NetworkRequirementsToml; -use codex_core::config_loader::RequirementSource; -use codex_core::config_loader::Sourced; use codex_core::sandboxing::SandboxPermissions; use codex_features::Feature; use codex_protocol::approvals::NetworkApprovalProtocol; diff --git a/codex-rs/core/tests/suite/deprecation_notice.rs b/codex-rs/core/tests/suite/deprecation_notice.rs index dc7280ea3..0ef7ddc33 100644 --- a/codex-rs/core/tests/suite/deprecation_notice.rs +++ b/codex-rs/core/tests/suite/deprecation_notice.rs @@ -2,10 +2,10 @@ use anyhow::Ok; use codex_app_server_protocol::ConfigLayerSource; -use codex_core::config_loader::ConfigLayerEntry; -use codex_core::config_loader::ConfigLayerStack; -use codex_core::config_loader::ConfigRequirements; -use codex_core::config_loader::ConfigRequirementsToml; +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; diff --git a/codex-rs/core/tests/suite/hooks.rs b/codex-rs/core/tests/suite/hooks.rs index c683d353a..851980c42 100644 --- a/codex-rs/core/tests/suite/hooks.rs +++ b/codex-rs/core/tests/suite/hooks.rs @@ -3,13 +3,13 @@ use std::path::Path; use anyhow::Context; use anyhow::Result; +use codex_config::ConfigLayerStack; +use codex_config::ConfigLayerStackOrdering; +use codex_config::NetworkConstraints; +use codex_config::NetworkRequirementsToml; +use codex_config::RequirementSource; +use codex_config::Sourced; use codex_core::config::Constrained; -use codex_core::config_loader::ConfigLayerStack; -use codex_core::config_loader::ConfigLayerStackOrdering; -use codex_core::config_loader::NetworkConstraints; -use codex_core::config_loader::NetworkRequirementsToml; -use codex_core::config_loader::RequirementSource; -use codex_core::config_loader::Sourced; use codex_features::Feature; use codex_protocol::items::parse_hook_prompt_fragment; use codex_protocol::models::ContentItem; diff --git a/codex-rs/core/tests/suite/permissions_messages.rs b/codex-rs/core/tests/suite/permissions_messages.rs index e3c04361b..1380f6162 100644 --- a/codex-rs/core/tests/suite/permissions_messages.rs +++ b/codex-rs/core/tests/suite/permissions_messages.rs @@ -1,7 +1,7 @@ use anyhow::Result; +use codex_config::ConfigLayerStack; use codex_core::ForkSnapshot; use codex_core::config::Constrained; -use codex_core::config_loader::ConfigLayerStack; use codex_core::context::ContextualUserFragment; use codex_core::context::PermissionsInstructions; use codex_core::load_exec_policy; diff --git a/codex-rs/exec-server/Cargo.toml b/codex-rs/exec-server/Cargo.toml index a1a25e6e9..21701d518 100644 --- a/codex-rs/exec-server/Cargo.toml +++ b/codex-rs/exec-server/Cargo.toml @@ -17,7 +17,6 @@ base64 = { workspace = true } bytes = { workspace = true } codex-app-server-protocol = { workspace = true } codex-client = { workspace = true } -codex-config = { workspace = true } codex-protocol = { workspace = true } codex-sandboxing = { workspace = true } codex-utils-absolute-path = { workspace = true } diff --git a/codex-rs/exec-server/src/local_process.rs b/codex-rs/exec-server/src/local_process.rs index bc9b2ba20..bc69ec610 100644 --- a/codex-rs/exec-server/src/local_process.rs +++ b/codex-rs/exec-server/src/local_process.rs @@ -6,9 +6,9 @@ use std::time::Duration; use async_trait::async_trait; use codex_app_server_protocol::JSONRPCErrorError; -use codex_config::shell_environment; -use codex_config::types::EnvironmentVariablePattern; -use codex_config::types::ShellEnvironmentPolicy; +use codex_protocol::config_types::EnvironmentVariablePattern; +use codex_protocol::config_types::ShellEnvironmentPolicy; +use codex_protocol::shell_environment; use codex_utils_pty::ExecCommandSession; use codex_utils_pty::TerminalSize; use tokio::sync::Mutex; @@ -706,7 +706,7 @@ fn notification_sender(inner: &Inner) -> Option { #[cfg(test)] mod tests { use super::*; - use codex_config::types::ShellEnvironmentPolicyInherit; + use codex_protocol::config_types::ShellEnvironmentPolicyInherit; use codex_utils_pty::ProcessDriver; use pretty_assertions::assert_eq; use tokio::sync::oneshot; diff --git a/codex-rs/exec-server/src/protocol.rs b/codex-rs/exec-server/src/protocol.rs index 435187d05..e801a7f43 100644 --- a/codex-rs/exec-server/src/protocol.rs +++ b/codex-rs/exec-server/src/protocol.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crate::FileSystemSandboxContext; use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; -use codex_config::types::ShellEnvironmentPolicyInherit; +use codex_protocol::config_types::ShellEnvironmentPolicyInherit; use codex_utils_absolute_path::AbsolutePathBuf; use serde::Deserialize; use serde::Serialize; diff --git a/codex-rs/exec/Cargo.toml b/codex-rs/exec/Cargo.toml index 0ec5d9b3c..632e47940 100644 --- a/codex-rs/exec/Cargo.toml +++ b/codex-rs/exec/Cargo.toml @@ -27,6 +27,7 @@ codex-arg0 = { workspace = true } codex-app-server-client = { workspace = true } codex-app-server-protocol = { workspace = true } codex-cloud-requirements = { workspace = true } +codex-config = { workspace = true } codex-core = { workspace = true } codex-feedback = { workspace = true } codex-git-utils = { workspace = true } diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index c96e06279..204be3d97 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -52,6 +52,9 @@ use codex_app_server_protocol::TurnStartResponse; use codex_app_server_protocol::TurnStartedNotification; use codex_arg0::Arg0DispatchPaths; use codex_cloud_requirements::cloud_requirements_loader_for_storage; +use codex_config::ConfigLoadError; +use codex_config::LoaderOverrides; +use codex_config::format_config_error_with_source; use codex_core::check_execpolicy_for_warnings; use codex_core::config::Config; use codex_core::config::ConfigBuilder; @@ -59,9 +62,6 @@ use codex_core::config::ConfigOverrides; use codex_core::config::find_codex_home; use codex_core::config::load_config_as_toml_with_cli_and_loader_overrides; use codex_core::config::resolve_oss_provider; -use codex_core::config_loader::ConfigLoadError; -use codex_core::config_loader::LoaderOverrides; -use codex_core::config_loader::format_config_error_with_source; use codex_core::find_thread_meta_by_name_str; use codex_core::format_exec_policy_error_with_source; use codex_core::path_utils; diff --git a/codex-rs/linux-sandbox/Cargo.toml b/codex-rs/linux-sandbox/Cargo.toml index c624251e6..519ae5138 100644 --- a/codex-rs/linux-sandbox/Cargo.toml +++ b/codex-rs/linux-sandbox/Cargo.toml @@ -29,7 +29,6 @@ serde_json = { workspace = true } url = { workspace = true } [target.'cfg(target_os = "linux")'.dev-dependencies] -codex-config = { workspace = true } codex-core = { workspace = true } pretty_assertions = { workspace = true } tempfile = { workspace = true } diff --git a/codex-rs/linux-sandbox/tests/suite/landlock.rs b/codex-rs/linux-sandbox/tests/suite/landlock.rs index 38478e11f..d1e84b89e 100644 --- a/codex-rs/linux-sandbox/tests/suite/landlock.rs +++ b/codex-rs/linux-sandbox/tests/suite/landlock.rs @@ -1,11 +1,11 @@ #![cfg(target_os = "linux")] #![allow(clippy::unwrap_used)] -use codex_config::types::ShellEnvironmentPolicy; use codex_core::exec::ExecCapturePolicy; use codex_core::exec::ExecParams; use codex_core::exec::process_exec_tool_call; use codex_core::exec_env::create_env; use codex_core::sandboxing::SandboxPermissions; +use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::error::CodexErr; use codex_protocol::error::Result; diff --git a/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs b/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs index 256373953..e906facac 100644 --- a/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs +++ b/codex-rs/linux-sandbox/tests/suite/managed_proxy.rs @@ -1,8 +1,8 @@ #![cfg(target_os = "linux")] #![allow(clippy::unwrap_used)] -use codex_config::types::ShellEnvironmentPolicy; use codex_core::exec_env::create_env; +use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::protocol::SandboxPolicy; use pretty_assertions::assert_eq; use std::collections::HashMap; diff --git a/codex-rs/protocol/Cargo.toml b/codex-rs/protocol/Cargo.toml index 2bd46d7d5..1de72dda3 100644 --- a/codex-rs/protocol/Cargo.toml +++ b/codex-rs/protocol/Cargo.toml @@ -44,6 +44,7 @@ ts-rs = { workspace = true, features = [ "no-serde-warnings", ] } uuid = { workspace = true, features = ["serde", "v7", "v4"] } +wildmatch = { workspace = true } [target.'cfg(target_os = "linux")'.dependencies] landlock = { workspace = true } diff --git a/codex-rs/protocol/src/config_types.rs b/codex-rs/protocol/src/config_types.rs index 2be5c6f12..da83ee858 100644 --- a/codex-rs/protocol/src/config_types.rs +++ b/codex-rs/protocol/src/config_types.rs @@ -8,11 +8,13 @@ use schemars::schema::SchemaObject; use serde::Deserialize; use serde::Serialize; use serde_json::Value; +use std::collections::HashMap; use std::num::NonZeroU64; use std::time::Duration; use strum_macros::Display; use strum_macros::EnumIter; use ts_rs::TS; +use wildmatch::WildMatchPattern; use crate::openai_models::ReasoningEffort; @@ -105,6 +107,65 @@ impl JsonSchema for ApprovalsReviewer { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum ShellEnvironmentPolicyInherit { + /// "Core" environment variables for the platform. On UNIX, this would + /// include HOME, LOGNAME, PATH, SHELL, and USER, among others. + Core, + + /// Inherits the full environment from the parent process. + #[default] + All, + + /// Do not inherit any environment variables from the parent process. + None, +} + +pub type EnvironmentVariablePattern = WildMatchPattern<'*', '?'>; + +/// Deriving the `env` based on this policy works as follows: +/// 1. Create an initial map based on the `inherit` policy. +/// 2. If `ignore_default_excludes` is false, filter the map using the default +/// exclude pattern(s), which are: `"*KEY*"`, `"*SECRET*"`, and `"*TOKEN*"`. +/// 3. If `exclude` is not empty, filter the map using the provided patterns. +/// 4. Insert any entries from `r#set` into the map. +/// 5. If non-empty, filter the map using the `include_only` patterns. +#[derive(Debug, Clone, PartialEq)] +pub struct ShellEnvironmentPolicy { + /// Starting point when building the environment. + pub inherit: ShellEnvironmentPolicyInherit, + + /// True to skip the check to exclude default environment variables that + /// contain "KEY", "SECRET", or "TOKEN" in their name. Defaults to true. + pub ignore_default_excludes: bool, + + /// Environment variable names to exclude from the environment. + pub exclude: Vec, + + /// (key, value) pairs to insert in the environment. + pub r#set: HashMap, + + /// Environment variable names to retain in the environment. + pub include_only: Vec, + + /// If true, the shell profile will be used to run the command. + pub use_profile: bool, +} + +impl Default for ShellEnvironmentPolicy { + fn default() -> Self { + Self { + inherit: ShellEnvironmentPolicyInherit::All, + ignore_default_excludes: true, + exclude: Vec::new(), + r#set: HashMap::new(), + include_only: Vec::new(), + use_profile: false, + } + } +} + fn string_enum_schema_with_description(values: &[&str], description: &str) -> Schema { let mut schema = SchemaObject { instance_type: Some(InstanceType::String.into()), diff --git a/codex-rs/protocol/src/lib.rs b/codex-rs/protocol/src/lib.rs index 2506dae74..175c92331 100644 --- a/codex-rs/protocol/src/lib.rs +++ b/codex-rs/protocol/src/lib.rs @@ -25,4 +25,5 @@ pub mod plan_tool; pub mod protocol; pub mod request_permissions; pub mod request_user_input; +pub mod shell_environment; pub mod user_input; diff --git a/codex-rs/config/src/shell_environment.rs b/codex-rs/protocol/src/shell_environment.rs similarity index 95% rename from codex-rs/config/src/shell_environment.rs rename to codex-rs/protocol/src/shell_environment.rs index 80fe0da42..2a7aace3e 100644 --- a/codex-rs/config/src/shell_environment.rs +++ b/codex-rs/protocol/src/shell_environment.rs @@ -1,6 +1,6 @@ -use crate::types::EnvironmentVariablePattern; -use crate::types::ShellEnvironmentPolicy; -use crate::types::ShellEnvironmentPolicyInherit; +use crate::config_types::EnvironmentVariablePattern; +use crate::config_types::ShellEnvironmentPolicy; +use crate::config_types::ShellEnvironmentPolicyInherit; use std::collections::HashMap; use std::collections::HashSet; @@ -76,7 +76,6 @@ where } }; - // Internal helper - does `name` match any pattern in `patterns`? let matches_any = |name: &str, patterns: &[EnvironmentVariablePattern]| -> bool { patterns.iter().any(|pattern| pattern.matches(name)) }; diff --git a/codex-rs/rmcp-client/src/stdio_server_launcher.rs b/codex-rs/rmcp-client/src/stdio_server_launcher.rs index b3d3b849d..ced594b78 100644 --- a/codex-rs/rmcp-client/src/stdio_server_launcher.rs +++ b/codex-rs/rmcp-client/src/stdio_server_launcher.rs @@ -28,10 +28,10 @@ use std::time::Duration; use anyhow::Result; use anyhow::anyhow; use codex_config::types::McpServerEnvVar; -use codex_config::types::ShellEnvironmentPolicyInherit; use codex_exec_server::ExecBackend; use codex_exec_server::ExecEnvPolicy; use codex_exec_server::ExecParams; +use codex_protocol::config_types::ShellEnvironmentPolicyInherit; #[cfg(unix)] use codex_utils_pty::process_group::kill_process_group; #[cfg(unix)] @@ -464,9 +464,9 @@ impl ExecutorStdioServerLauncher { #[cfg(test)] mod tests { use super::*; - use codex_config::shell_environment; - use codex_config::types::EnvironmentVariablePattern; - use codex_config::types::ShellEnvironmentPolicy; + use codex_protocol::config_types::EnvironmentVariablePattern; + use codex_protocol::config_types::ShellEnvironmentPolicy; + use codex_protocol::shell_environment; #[test] fn remote_env_policy_uses_core_env_without_remote_source_vars() {