diff --git a/codex-rs/cli/src/debug_sandbox.rs b/codex-rs/cli/src/debug_sandbox.rs index 9561dde36..4f77a4b82 100644 --- a/codex-rs/cli/src/debug_sandbox.rs +++ b/codex-rs/cli/src/debug_sandbox.rs @@ -473,6 +473,7 @@ async fn run_command_under_windows_session( ) -> ! { use codex_core::windows_sandbox::WindowsSandboxLevelExt; use codex_protocol::config_types::WindowsSandboxLevel; + use codex_windows_sandbox::WindowsSandboxProxySettingsMode; use codex_windows_sandbox::WindowsSandboxSessionRequest; use codex_windows_sandbox::spawn_windows_sandbox_session_for_level; @@ -485,6 +486,7 @@ async fn run_command_under_windows_session( cwd: cwd.as_path(), env_map: env, windows_sandbox_level: WindowsSandboxLevel::from_config(config), + proxy_settings_mode: WindowsSandboxProxySettingsMode::Reconcile, proxy_enforced: false, timeout_ms: None, read_roots_override: None, diff --git a/codex-rs/exec-server/src/fs_sandbox.rs b/codex-rs/exec-server/src/fs_sandbox.rs index 6db3804ae..41a3e1221 100644 --- a/codex-rs/exec-server/src/fs_sandbox.rs +++ b/codex-rs/exec-server/src/fs_sandbox.rs @@ -131,6 +131,8 @@ impl FileSystemSandboxRunner { sandbox_manager .transform_for_direct_spawn(SandboxDirectSpawnTransformRequest { workspace_roots, + windows_sandbox_proxy_settings_mode: + codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve, transform: SandboxTransformRequest { command, permissions: permission_profile, diff --git a/codex-rs/exec-server/src/process_sandbox.rs b/codex-rs/exec-server/src/process_sandbox.rs index e3bffeaa6..ef97d0ce5 100644 --- a/codex-rs/exec-server/src/process_sandbox.rs +++ b/codex-rs/exec-server/src/process_sandbox.rs @@ -107,6 +107,8 @@ pub(crate) fn prepare_exec_request( let request = sandbox_manager .transform_for_direct_spawn(SandboxDirectSpawnTransformRequest { workspace_roots, + windows_sandbox_proxy_settings_mode: + codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile, transform: SandboxTransformRequest { // TODO(jif): Preserve params.arg0 for the inner command across the sandbox // wrapper, or reject sandboxed requests with a custom arg0. diff --git a/codex-rs/sandboxing/src/lib.rs b/codex-rs/sandboxing/src/lib.rs index 0688d0f92..c9109146b 100644 --- a/codex-rs/sandboxing/src/lib.rs +++ b/codex-rs/sandboxing/src/lib.rs @@ -12,6 +12,7 @@ mod windows; pub use bwrap::find_system_bwrap_in_path; #[cfg(target_os = "linux")] pub use bwrap::system_bwrap_warning; +pub use codex_windows_sandbox::WindowsSandboxProxySettingsMode; pub use denial::is_likely_sandbox_denied; pub use manager::SandboxCommand; pub use manager::SandboxDirectSpawnTransformRequest; diff --git a/codex-rs/sandboxing/src/manager.rs b/codex-rs/sandboxing/src/manager.rs index 30870417f..51d2d6c98 100644 --- a/codex-rs/sandboxing/src/manager.rs +++ b/codex-rs/sandboxing/src/manager.rs @@ -152,6 +152,7 @@ pub struct SandboxTransformRequest<'a> { pub struct SandboxDirectSpawnTransformRequest<'a> { pub transform: SandboxTransformRequest<'a>, pub workspace_roots: &'a [AbsolutePathBuf], + pub windows_sandbox_proxy_settings_mode: codex_windows_sandbox::WindowsSandboxProxySettingsMode, } // TODO(anp): Revisit this preparation type once this module's PathUri migration is complete. @@ -484,12 +485,14 @@ impl SandboxManager { codex_home: &Path, ) -> Result { let workspace_roots = request.workspace_roots; + let proxy_settings_mode = request.windows_sandbox_proxy_settings_mode; let mut request = self.transform(request.transform)?; if request.sandbox == SandboxType::WindowsRestrictedToken { wrap_windows_sandbox_exec_request_for_direct_spawn( &mut request, workspace_roots, codex_home, + proxy_settings_mode, )?; } Ok(request) @@ -501,6 +504,7 @@ fn wrap_windows_sandbox_exec_request_for_direct_spawn( request: &mut SandboxExecRequest, workspace_roots: &[AbsolutePathBuf], codex_home: &Path, + proxy_settings_mode: codex_windows_sandbox::WindowsSandboxProxySettingsMode, ) -> Result<(), SandboxTransformError> { // TODO(anp): Keep PathUri through the Windows sandbox wrapper boundary. let native_cwd = @@ -572,6 +576,7 @@ fn wrap_windows_sandbox_exec_request_for_direct_spawn( request.windows_sandbox_level, request.windows_sandbox_private_desktop, proxy_enforced, + proxy_settings_mode, read_roots_override, read_roots_include_platform_defaults, write_roots_override, diff --git a/codex-rs/sandboxing/src/manager_tests.rs b/codex-rs/sandboxing/src/manager_tests.rs index 547155c63..c1a52182d 100644 --- a/codex-rs/sandboxing/src/manager_tests.rs +++ b/codex-rs/sandboxing/src/manager_tests.rs @@ -499,6 +499,8 @@ fn transform_for_direct_spawn_windows_materializes_inner_helper() { .transform_for_direct_spawn_with_codex_home( SandboxDirectSpawnTransformRequest { workspace_roots: workspace_roots.as_slice(), + windows_sandbox_proxy_settings_mode: + codex_windows_sandbox::WindowsSandboxProxySettingsMode::Preserve, transform: SandboxTransformRequest { command: SandboxCommand { program: configured_helper.as_os_str().to_owned(), @@ -544,6 +546,12 @@ fn transform_for_direct_spawn_windows_materializes_inner_helper() { .iter() .any(|arg| arg == "--run-as-windows-sandbox") ); + assert!( + exec_request + .command + .iter() + .any(|arg| arg == "--preserve-proxy-settings") + ); assert!( exec_request .command diff --git a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs index 5b8bb3769..1da6f3294 100644 --- a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs +++ b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs @@ -150,6 +150,7 @@ mod windows_impl { &deny_read_paths_override, &deny_write_paths_override, proxy_enforced, + crate::WindowsSandboxProxySettingsMode::Reconcile, )?; // Build capability SID for ACL grants. let caps = load_or_create_cap_sids(codex_home)?; @@ -214,6 +215,7 @@ mod windows_impl { &deny_read_paths_override, &deny_write_paths_override, proxy_enforced, + crate::WindowsSandboxProxySettingsMode::Reconcile, )?; spawn_runner_transport( codex_home, diff --git a/codex-rs/windows-sandbox-rs/src/identity.rs b/codex-rs/windows-sandbox-rs/src/identity.rs index fcba538ce..9ac3402be 100644 --- a/codex-rs/windows-sandbox-rs/src/identity.rs +++ b/codex-rs/windows-sandbox-rs/src/identity.rs @@ -8,8 +8,8 @@ use crate::setup::SetupMarker; use crate::setup::gather_read_roots; use crate::setup::gather_write_roots_for_permissions; use crate::setup::offline_proxy_settings_from_env; -use crate::setup::run_elevated_setup; -use crate::setup::run_setup_refresh_with_overrides; +use crate::setup::run_elevated_setup_with_proxy_settings; +use crate::setup::run_setup_refresh_with_overrides_and_proxy_settings; use crate::setup::sandbox_users_path; use crate::setup::setup_marker_path; use anyhow::Context; @@ -154,6 +154,7 @@ pub fn require_logon_sandbox_creds( deny_read_paths_override: &[PathBuf], deny_write_paths_override: &[PathBuf], proxy_enforced: bool, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, ) -> Result { let sandbox_dir = crate::setup::sandbox_dir(codex_home); let needed_read = read_roots_override @@ -163,13 +164,19 @@ pub fn require_logon_sandbox_creds( .map(<[PathBuf]>::to_vec) .unwrap_or_else(|| gather_write_roots_for_permissions(permissions, command_cwd, env_map)); let network_identity = SandboxNetworkIdentity::from_permissions(permissions, proxy_enforced); - let desired_offline_proxy_settings = offline_proxy_settings_from_env(env_map, network_identity); + let marker = load_marker(codex_home)?; + let desired_offline_proxy_settings = desired_offline_proxy_settings( + marker.as_ref(), + proxy_settings_mode, + env_map, + network_identity, + ); // NOTE: Do not add CODEX_HOME/.sandbox to `needed_write`; it must remain non-writable by the // restricted capability token. The setup helper's `lock_sandbox_dir` is responsible for // granting the sandbox group access to this directory without granting the capability SID. let mut setup_reason: Option = None; - let mut identity = match load_marker(codex_home)? { + let mut identity = match marker { Some(marker) if marker.version_matches() => { if let Some(reason) = marker.request_mismatch_reason(network_identity, &desired_offline_proxy_settings) @@ -201,7 +208,7 @@ pub fn require_logon_sandbox_creds( } else { crate::logging::log_note("sandbox setup required", Some(&sandbox_dir)); } - run_elevated_setup( + run_elevated_setup_with_proxy_settings( crate::setup::SandboxSetupRequest { permissions, command_cwd, @@ -216,11 +223,12 @@ pub fn require_logon_sandbox_creds( deny_read_paths: Some(deny_read_paths_override.to_vec()), deny_write_paths: Some(deny_write_paths_override.to_vec()), }, + &desired_offline_proxy_settings, )?; identity = select_identity(network_identity, codex_home)?; } // Always refresh ACLs (non-elevated) for current roots via the setup binary. - run_setup_refresh_with_overrides( + run_setup_refresh_with_overrides_and_proxy_settings( crate::setup::SandboxSetupRequest { permissions, command_cwd, @@ -235,6 +243,7 @@ pub fn require_logon_sandbox_creds( deny_read_paths: Some(deny_read_paths_override.to_vec()), deny_write_paths: Some(deny_write_paths_override.to_vec()), }, + &desired_offline_proxy_settings, )?; let identity = identity.ok_or_else(|| { anyhow!( @@ -247,6 +256,22 @@ pub fn require_logon_sandbox_creds( }) } +fn desired_offline_proxy_settings( + marker: Option<&SetupMarker>, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, + env_map: &HashMap, + network_identity: SandboxNetworkIdentity, +) -> crate::setup::OfflineProxySettings { + match (marker, proxy_settings_mode) { + (Some(marker), crate::WindowsSandboxProxySettingsMode::Preserve) + if marker.version_matches() => + { + marker.offline_proxy_settings() + } + _ => offline_proxy_settings_from_env(env_map, network_identity), + } +} + #[allow(clippy::too_many_arguments)] pub(crate) fn refresh_logon_sandbox_creds( permissions: &ResolvedWindowsSandboxPermissions, @@ -259,6 +284,7 @@ pub(crate) fn refresh_logon_sandbox_creds( deny_read_paths_override: &[PathBuf], deny_write_paths_override: &[PathBuf], proxy_enforced: bool, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, ) -> Result { remove_sandbox_users_file(codex_home, "sandbox user login failed")?; require_logon_sandbox_creds( @@ -272,13 +298,20 @@ pub(crate) fn refresh_logon_sandbox_creds( deny_read_paths_override, deny_write_paths_override, proxy_enforced, + proxy_settings_mode, ) } #[cfg(test)] mod tests { + use super::desired_offline_proxy_settings; use super::remove_sandbox_users_file; + use crate::WindowsSandboxProxySettingsMode; + use crate::setup::SandboxNetworkIdentity; + use crate::setup::SetupMarker; use crate::setup::sandbox_users_path; + use pretty_assertions::assert_eq; + use std::collections::HashMap; use std::fs; use tempfile::TempDir; @@ -302,4 +335,40 @@ mod tests { remove_sandbox_users_file(codex_home.path(), "stale creds").expect("remove users"); assert!(!users_path.exists()); } + + #[test] + fn preserving_proxy_settings_uses_the_existing_marker() { + let marker = SetupMarker { + version: crate::setup::SETUP_VERSION, + offline_username: "offline".to_string(), + online_username: "online".to_string(), + created_at: None, + proxy_ports: vec![7890], + allow_local_binding: true, + }; + let env_map = HashMap::from([( + "HTTP_PROXY".to_string(), + "http://127.0.0.1:8080".to_string(), + )]); + + assert_eq!( + desired_offline_proxy_settings( + Some(&marker), + WindowsSandboxProxySettingsMode::Preserve, + &env_map, + SandboxNetworkIdentity::Offline, + ), + marker.offline_proxy_settings() + ); + assert_eq!( + desired_offline_proxy_settings( + Some(&marker), + WindowsSandboxProxySettingsMode::Reconcile, + &env_map, + SandboxNetworkIdentity::Offline, + ) + .proxy_ports, + vec![8080] + ); + } } diff --git a/codex-rs/windows-sandbox-rs/src/lib.rs b/codex-rs/windows-sandbox-rs/src/lib.rs index a7f3df6e2..766faf1a0 100644 --- a/codex-rs/windows-sandbox-rs/src/lib.rs +++ b/codex-rs/windows-sandbox-rs/src/lib.rs @@ -35,6 +35,15 @@ impl fmt::Debug for WindowsSandboxCancellationToken { } } +/// Controls whether a Windows sandbox launch reconciles persistent proxy +/// firewall settings or preserves the settings established by another launch. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum WindowsSandboxProxySettingsMode { + #[default] + Reconcile, + Preserve, +} + #[cfg(target_os = "windows")] mod acl; #[cfg(target_os = "windows")] diff --git a/codex-rs/windows-sandbox-rs/src/setup.rs b/codex-rs/windows-sandbox-rs/src/setup.rs index 428b5ff6a..1995c3336 100644 --- a/codex-rs/windows-sandbox-rs/src/setup.rs +++ b/codex-rs/windows-sandbox-rs/src/setup.rs @@ -130,14 +130,16 @@ pub fn run_setup_refresh( proxy_enforced, }, SetupRootOverrides::default(), + /*offline_proxy_settings_override*/ None, ) } -pub fn run_setup_refresh_with_overrides( +pub(crate) fn run_setup_refresh_with_overrides_and_proxy_settings( request: SandboxSetupRequest<'_>, overrides: SetupRootOverrides, + offline_proxy_settings: &OfflineProxySettings, ) -> Result<()> { - run_setup_refresh_inner(request, overrides) + run_setup_refresh_inner(request, overrides, Some(offline_proxy_settings)) } pub fn run_setup_refresh_with_extra_read_roots( @@ -174,12 +176,14 @@ pub fn run_setup_refresh_with_extra_read_roots( deny_read_paths: None, deny_write_paths: None, }, + /*offline_proxy_settings_override*/ None, ) } fn run_setup_refresh_inner( request: SandboxSetupRequest<'_>, overrides: SetupRootOverrides, + offline_proxy_settings_override: Option<&OfflineProxySettings>, ) -> Result<()> { if !request.permissions.is_enforceable_by_windows_sandbox() { anyhow::bail!("unsupported filesystem permissions for Windows sandbox setup"); @@ -187,9 +191,8 @@ fn run_setup_refresh_inner( let (read_roots, write_roots) = build_payload_roots(&request, &overrides); let deny_read_paths = build_payload_deny_read_paths(overrides.deny_read_paths); let deny_write_paths = build_payload_deny_write_paths(&request, overrides.deny_write_paths); - let network_identity = - SandboxNetworkIdentity::from_permissions(request.permissions, request.proxy_enforced); - let offline_proxy_settings = offline_proxy_settings_from_env(request.env_map, network_identity); + let offline_proxy_settings = + offline_proxy_settings_for_request(&request, offline_proxy_settings_override); let payload = ElevationPayload { version: SETUP_VERSION, offline_username: OFFLINE_USERNAME.to_string(), @@ -283,6 +286,13 @@ impl SetupMarker { self.version == SETUP_VERSION } + pub(crate) fn offline_proxy_settings(&self) -> OfflineProxySettings { + OfflineProxySettings { + proxy_ports: self.proxy_ports.clone(), + allow_local_binding: self.allow_local_binding, + } + } + pub(crate) fn request_mismatch_reason( &self, network_identity: SandboxNetworkIdentity, @@ -593,6 +603,17 @@ pub(crate) fn offline_proxy_settings_from_env( } } +fn offline_proxy_settings_for_request( + request: &SandboxSetupRequest<'_>, + offline_proxy_settings_override: Option<&OfflineProxySettings>, +) -> OfflineProxySettings { + offline_proxy_settings_override.cloned().unwrap_or_else(|| { + let network_identity = + SandboxNetworkIdentity::from_permissions(request.permissions, request.proxy_enforced); + offline_proxy_settings_from_env(request.env_map, network_identity) + }) +} + pub(crate) fn proxy_ports_from_env(env_map: &HashMap) -> Vec { let mut ports = BTreeSet::new(); for key in PROXY_ENV_KEYS { @@ -821,6 +842,24 @@ fn run_setup_exe( pub fn run_elevated_setup( request: SandboxSetupRequest<'_>, overrides: SetupRootOverrides, +) -> Result<()> { + run_elevated_setup_inner( + request, overrides, /*offline_proxy_settings_override*/ None, + ) +} + +pub(crate) fn run_elevated_setup_with_proxy_settings( + request: SandboxSetupRequest<'_>, + overrides: SetupRootOverrides, + offline_proxy_settings: &OfflineProxySettings, +) -> Result<()> { + run_elevated_setup_inner(request, overrides, Some(offline_proxy_settings)) +} + +fn run_elevated_setup_inner( + request: SandboxSetupRequest<'_>, + overrides: SetupRootOverrides, + offline_proxy_settings_override: Option<&OfflineProxySettings>, ) -> Result<()> { if !request.permissions.is_enforceable_by_windows_sandbox() { anyhow::bail!("unsupported filesystem permissions for Windows sandbox setup"); @@ -836,9 +875,8 @@ pub fn run_elevated_setup( let (read_roots, write_roots) = build_payload_roots(&request, &overrides); let deny_read_paths = build_payload_deny_read_paths(overrides.deny_read_paths); let deny_write_paths = build_payload_deny_write_paths(&request, overrides.deny_write_paths); - let network_identity = - SandboxNetworkIdentity::from_permissions(request.permissions, request.proxy_enforced); - let offline_proxy_settings = offline_proxy_settings_from_env(request.env_map, network_identity); + let offline_proxy_settings = + offline_proxy_settings_for_request(&request, offline_proxy_settings_override); let payload = ElevationPayload { version: SETUP_VERSION, offline_username: OFFLINE_USERNAME.to_string(), @@ -1170,6 +1208,37 @@ mod tests { ) } + #[test] + fn setup_request_prefers_explicit_proxy_settings() { + let tmp = TempDir::new().expect("tempdir"); + let command_cwd = tmp.path().join("workspace"); + fs::create_dir_all(&command_cwd).expect("create workspace"); + let permissions = permissions_for( + &PermissionProfile::read_only(), + workspace_roots_for(&command_cwd).as_slice(), + ); + let env_map = HashMap::from([( + "HTTP_PROXY".to_string(), + "http://127.0.0.1:8080".to_string(), + )]); + let explicit = super::OfflineProxySettings { + proxy_ports: vec![7890], + allow_local_binding: true, + }; + let request = super::SandboxSetupRequest { + permissions: &permissions, + command_cwd: &command_cwd, + env_map: &env_map, + codex_home: tmp.path(), + proxy_enforced: false, + }; + + assert_eq!( + super::offline_proxy_settings_for_request(&request, Some(&explicit)), + explicit + ); + } + #[test] fn report_helper_failure_uses_setup_error_report_when_clear_succeeded() { let tmp = TempDir::new().expect("tempdir"); diff --git a/codex-rs/windows-sandbox-rs/src/spawn_prep.rs b/codex-rs/windows-sandbox-rs/src/spawn_prep.rs index 9668edb1a..382a6a453 100644 --- a/codex-rs/windows-sandbox-rs/src/spawn_prep.rs +++ b/codex-rs/windows-sandbox-rs/src/spawn_prep.rs @@ -357,6 +357,7 @@ pub(crate) fn prepare_elevated_spawn_context_for_permissions( deny_read_paths_override: &[PathBuf], deny_write_paths_override: &[PathBuf], proxy_enforced: bool, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, ) -> Result { normalize_null_device_env(env_map); ensure_non_interactive_pager(env_map); @@ -412,6 +413,7 @@ pub(crate) fn prepare_elevated_spawn_context_for_permissions( deny_write_paths_override }, proxy_enforced, + proxy_settings_mode, )?; let caps = load_or_create_cap_sids(codex_home)?; let (psid_to_use, cap_sids) = if uses_write_capabilities { diff --git a/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs b/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs index 2e7437ad3..efe4a3f42 100644 --- a/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs +++ b/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs @@ -56,6 +56,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated_for_permission_profil cwd: &Path, mut env_map: HashMap, proxy_enforced: bool, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, timeout_ms: Option, read_roots_override: Option<&[PathBuf]>, read_roots_include_platform_defaults: bool, @@ -91,6 +92,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated_for_permission_profil &deny_read_paths_override, &deny_write_paths_override, proxy_enforced, + proxy_settings_mode, )?; let spawn_request = SpawnRequest { @@ -133,6 +135,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated_for_permission_profil &deny_read_paths_override, &deny_write_paths_override, /*proxy_enforced*/ false, + proxy_settings_mode, )?; spawn_runner_transport_task( codex_home, diff --git a/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs b/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs index 02792d6cb..84ccd0d8c 100644 --- a/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs +++ b/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs @@ -31,6 +31,7 @@ pub struct WindowsSandboxSessionRequest<'a> { pub env_map: HashMap, pub windows_sandbox_level: WindowsSandboxLevel, pub proxy_enforced: bool, + pub proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, pub timeout_ms: Option, pub read_roots_override: Option<&'a [PathBuf]>, pub read_roots_include_platform_defaults: bool, @@ -48,7 +49,7 @@ pub async fn spawn_windows_sandbox_session_for_level( if request.proxy_enforced || matches!(request.windows_sandbox_level, WindowsSandboxLevel::Elevated) { - spawn_windows_sandbox_session_elevated_for_permission_profile( + backends::elevated::spawn_windows_sandbox_session_elevated_for_permission_profile( request.permission_profile, request.workspace_roots, request.codex_home, @@ -56,6 +57,7 @@ pub async fn spawn_windows_sandbox_session_for_level( request.cwd, request.env_map, request.proxy_enforced, + request.proxy_settings_mode, request.timeout_ms, request.read_roots_override, request.read_roots_include_platform_defaults, @@ -145,6 +147,7 @@ pub async fn spawn_windows_sandbox_session_elevated_for_permission_profile( cwd, env_map, proxy_enforced, + crate::WindowsSandboxProxySettingsMode::Reconcile, timeout_ms, read_roots_override, read_roots_include_platform_defaults, diff --git a/codex-rs/windows-sandbox-rs/src/wrapper.rs b/codex-rs/windows-sandbox-rs/src/wrapper.rs index 375fb07cf..f02af2613 100644 --- a/codex-rs/windows-sandbox-rs/src/wrapper.rs +++ b/codex-rs/windows-sandbox-rs/src/wrapper.rs @@ -26,6 +26,7 @@ const DENY_WRITE_PATHS_JSON_FLAG: &str = "--deny-write-paths-json"; const ENV_JSON_FLAG: &str = "--env-json"; const PERMISSION_PROFILE_FLAG: &str = "--permission-profile"; const PRIVATE_DESKTOP_FLAG: &str = "--windows-sandbox-private-desktop"; +const PRESERVE_PROXY_SETTINGS_FLAG: &str = "--preserve-proxy-settings"; const PROXY_ENFORCED_FLAG: &str = "--proxy-enforced"; const READ_ROOTS_INCLUDE_PLATFORM_DEFAULTS_FLAG: &str = "--read-roots-include-platform-defaults"; const READ_ROOTS_JSON_FLAG: &str = "--read-roots-json"; @@ -43,6 +44,7 @@ pub fn create_windows_sandbox_command_args_for_permission_profile( windows_sandbox_level: WindowsSandboxLevel, windows_sandbox_private_desktop: bool, proxy_enforced: bool, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, read_roots_override: Option<&[PathBuf]>, read_roots_include_platform_defaults: bool, write_roots_override: Option<&[PathBuf]>, @@ -82,6 +84,9 @@ pub fn create_windows_sandbox_command_args_for_permission_profile( if proxy_enforced { args.push(PROXY_ENFORCED_FLAG.to_string()); } + if proxy_settings_mode == crate::WindowsSandboxProxySettingsMode::Preserve { + args.push(PRESERVE_PROXY_SETTINGS_FLAG.to_string()); + } if let Some(read_roots_override) = read_roots_override { push_json_arg(&mut args, READ_ROOTS_JSON_FLAG, &read_roots_override); } @@ -154,6 +159,7 @@ struct WindowsSandboxWrapperRequest { windows_sandbox_level: WindowsSandboxLevel, windows_sandbox_private_desktop: bool, proxy_enforced: bool, + proxy_settings_mode: crate::WindowsSandboxProxySettingsMode, read_roots_override: Option>, read_roots_include_platform_defaults: bool, write_roots_override: Option>, @@ -176,6 +182,7 @@ async fn run_windows_sandbox_wrapper_request(request: WindowsSandboxWrapperReque env_map: request.env_map, windows_sandbox_level: request.windows_sandbox_level, proxy_enforced: request.proxy_enforced, + proxy_settings_mode: request.proxy_settings_mode, timeout_ms: None, read_roots_override: request.read_roots_override.as_deref(), read_roots_include_platform_defaults: request.read_roots_include_platform_defaults, @@ -201,6 +208,7 @@ fn parse_windows_sandbox_wrapper_args(args: Vec) -> Result) -> Result windows_sandbox_private_desktop = true, + PRESERVE_PROXY_SETTINGS_FLAG => { + proxy_settings_mode = crate::WindowsSandboxProxySettingsMode::Preserve; + } PROXY_ENFORCED_FLAG => proxy_enforced = true, READ_ROOTS_INCLUDE_PLATFORM_DEFAULTS_FLAG => { read_roots_include_platform_defaults = true; @@ -282,6 +293,7 @@ fn parse_windows_sandbox_wrapper_args(args: Vec) -> Result