From 3abbf9fe2c6b6910e9de61f6a0c5bb468f74b5c8 Mon Sep 17 00:00:00 2001 From: Sean Huang Date: Mon, 14 Sep 2026 00:29:16 +0000 Subject: [PATCH] Extract Windows sandbox configuration preparation into a helper (#45312) ## What changed Expose `prepare_windows_sandbox_config` and `PreparedWindowsSandboxConfig` and use them during config loading. Preserve requirement enforcement and the separation between the configured mode and the effective sandbox level. ## Testing Add a unit test covering explicit mode precedence over feature fallback and ensuring a feature-only fallback leaves the configured mode unset. GitOrigin-RevId: 98e7f9fbc473b6a841257eca80d9a51950986055 --- codex-rs/core/src/config/mod.rs | 33 ++++--------- .../core/src/config/windows_sandbox_config.rs | 47 +++++++++++++++++++ .../config/windows_sandbox_config_tests.rs | 34 ++++++++++++++ 3 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 codex-rs/core/src/config/windows_sandbox_config.rs create mode 100644 codex-rs/core/src/config/windows_sandbox_config_tests.rs diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index e1e00a2445..96c2a43f22 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -177,6 +177,7 @@ mod resolved_permission_profile; #[cfg(test)] mod schema; mod token_budget_startup; +mod windows_sandbox_config; pub use auth_keyring::bootstrap_auth_config; pub use auth_keyring::resolve_bootstrap_auth_keyring_backend_kind; pub use codex_agent_roles::AgentRoleConfig; @@ -212,6 +213,8 @@ pub use permissions::network_proxy_config_from_profile_network; pub use permissions::resolve_permission_profile; pub(crate) use resolved_permission_profile::PermissionProfileState; pub use token_budget_startup::TokenBudgetStartupConfig; +pub use windows_sandbox_config::PreparedWindowsSandboxConfig; +pub use windows_sandbox_config::prepare_windows_sandbox_config; const DEFAULT_IGNORE_LARGE_UNTRACKED_DIRS: i64 = 200; const DEFAULT_IGNORE_LARGE_UNTRACKED_FILES: i64 = 10 * 1024 * 1024; @@ -3307,28 +3310,15 @@ impl Config { }; let respect_system_proxy = features.enabled(Feature::RespectSystemProxy); let enable_network_proxy = features.enabled(Feature::NetworkProxy); - let configured_windows_sandbox_mode = resolve_windows_sandbox_mode(&cfg); - // Keep the configured mode separate so a requirement-constrained mode - // does not look like it was explicitly selected in config. - let selected_windows_sandbox_mode = configured_windows_sandbox_mode.or_else(|| { - match WindowsSandboxLevel::from_features(&features) { - WindowsSandboxLevel::Elevated => Some(WindowsSandboxModeToml::Elevated), - WindowsSandboxLevel::RestrictedToken => Some(WindowsSandboxModeToml::Unelevated), - WindowsSandboxLevel::Disabled | WindowsSandboxLevel::Mxc => None, - } - }); - apply_requirement_constrained_value( - "windows.sandbox", - selected_windows_sandbox_mode, + let PreparedWindowsSandboxConfig { + mode: windows_sandbox_mode, + level: windows_sandbox_level, + } = prepare_windows_sandbox_config( + resolve_windows_sandbox_mode(&cfg), + WindowsSandboxLevel::from_features(&features), &mut constrained_windows_sandbox_mode, &mut startup_warnings, )?; - let effective_windows_sandbox_mode = *constrained_windows_sandbox_mode.get(); - let windows_sandbox_mode = if constrained_windows_sandbox_mode.source.is_some() { - effective_windows_sandbox_mode - } else { - configured_windows_sandbox_mode - }; let windows_sandbox_private_desktop = resolve_windows_sandbox_private_desktop(&cfg); let resolved_cwd = AbsolutePathBuf::try_from(normalize_for_native_workdir({ use std::env; @@ -3365,11 +3355,6 @@ impl Config { sandbox_mode, ); let requirements_toml = config_layer_stack.requirements_toml(); - let windows_sandbox_level = match effective_windows_sandbox_mode { - Some(WindowsSandboxModeToml::Elevated) => WindowsSandboxLevel::Elevated, - Some(WindowsSandboxModeToml::Unelevated) => WindowsSandboxLevel::RestrictedToken, - None => WindowsSandboxLevel::Disabled, - }; let persisted_permission_profile_id = if sandbox_mode.is_some() || permission_profile.is_some() || default_permissions_override.is_some() diff --git a/codex-rs/core/src/config/windows_sandbox_config.rs b/codex-rs/core/src/config/windows_sandbox_config.rs new file mode 100644 index 0000000000..e50695c323 --- /dev/null +++ b/codex-rs/core/src/config/windows_sandbox_config.rs @@ -0,0 +1,47 @@ +//! Windows sandbox mode selection after managed features have been resolved. +//! Keep configured mode distinct from the effective level unless policy pins it. + +use super::apply_requirement_constrained_value; +use codex_config::ConstrainedWithSource; +use codex_config::types::WindowsSandboxModeToml; +use codex_protocol::config_types::WindowsSandboxLevel; + +#[derive(Debug, PartialEq)] +pub struct PreparedWindowsSandboxConfig { + /// Explicit or requirement-constrained mode; excludes feature-only fallback. + pub mode: Option, + /// Effective sandbox level after Windows requirements have been applied. + pub level: WindowsSandboxLevel, +} + +/// Applies Windows requirements to the configured mode or feature-derived level. +/// The feature-derived level must already reflect managed feature requirements. +pub fn prepare_windows_sandbox_config( + configured_mode: Option, + feature_level: WindowsSandboxLevel, + constraint: &mut ConstrainedWithSource>, + warnings: &mut Vec, +) -> std::io::Result { + let selected_mode = configured_mode.or(match feature_level { + WindowsSandboxLevel::Elevated => Some(WindowsSandboxModeToml::Elevated), + WindowsSandboxLevel::RestrictedToken => Some(WindowsSandboxModeToml::Unelevated), + WindowsSandboxLevel::Disabled | WindowsSandboxLevel::Mxc => None, + }); + apply_requirement_constrained_value("windows.sandbox", selected_mode, constraint, warnings)?; + let effective_mode = *constraint.get(); + let mode = if constraint.source.is_some() { + effective_mode + } else { + configured_mode + }; + let level = match effective_mode { + Some(WindowsSandboxModeToml::Elevated) => WindowsSandboxLevel::Elevated, + Some(WindowsSandboxModeToml::Unelevated) => WindowsSandboxLevel::RestrictedToken, + None => WindowsSandboxLevel::Disabled, + }; + Ok(PreparedWindowsSandboxConfig { mode, level }) +} + +#[cfg(test)] +#[path = "windows_sandbox_config_tests.rs"] +mod tests; diff --git a/codex-rs/core/src/config/windows_sandbox_config_tests.rs b/codex-rs/core/src/config/windows_sandbox_config_tests.rs new file mode 100644 index 0000000000..c88425e934 --- /dev/null +++ b/codex-rs/core/src/config/windows_sandbox_config_tests.rs @@ -0,0 +1,34 @@ +//! Preserve explicit Windows mode priority without persisting feature fallbacks. + +use super::*; +use codex_config::ConfigRequirements; +use pretty_assertions::assert_eq; + +#[test] +fn configured_mode_takes_priority_without_persisting_feature_fallback() -> std::io::Result<()> { + for (configured_mode, expected) in [ + ( + None, + PreparedWindowsSandboxConfig { + mode: None, + level: WindowsSandboxLevel::Elevated, + }, + ), + ( + Some(WindowsSandboxModeToml::Unelevated), + PreparedWindowsSandboxConfig { + mode: Some(WindowsSandboxModeToml::Unelevated), + level: WindowsSandboxLevel::RestrictedToken, + }, + ), + ] { + let actual = prepare_windows_sandbox_config( + configured_mode, + WindowsSandboxLevel::Elevated, + &mut ConfigRequirements::default().windows_sandbox_mode, + &mut Vec::new(), + )?; + assert_eq!(actual, expected); + } + Ok(()) +}