Preserve Windows sandbox proxy settings in guardian sessions (#35036)

## Why

Guardian review commands can run without the proxy-port environment used to
configure the parent session. Reconciling persistent Windows sandbox settings
for those commands can discard the parent's proxy configuration.

## What changed

- Add a session-level Windows sandbox proxy-settings mode and use `Preserve`
  for guardian review sessions while keeping `Reconcile` as the default.
- Carry the mode through unified exec and the exec-server sandbox context to
  Windows process launches.
- In preserve mode, reuse the proxy settings recorded by the existing sandbox
  setup marker.

## Testing

Added coverage for guardian session configuration, exec-server transport, and
preserving an existing setup marker when proxy-port environment variables are
absent.

GitOrigin-RevId: 214655c6e6d97360906431773dc0de0fdda2db6e
This commit is contained in:
iceweasel-oai
2026-07-23 23:35:29 +00:00
committed by copyberry
parent d45055ae58
commit b115de97d7
23 changed files with 181 additions and 35 deletions
+3
View File
@@ -87,6 +87,7 @@ pub(crate) async fn run_codex_thread_interactive(
subagent_source: SubAgentSource,
initial_history: Option<InitialHistory>,
git_enrichment_policy: GitEnrichmentPolicy,
windows_sandbox_proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode,
) -> Result<(Arc<Session>, SessionIo), CodexErr> {
let (tx_sub, rx_sub) = async_channel::bounded(SUBMISSION_CHANNEL_CAPACITY);
let (tx_ops, rx_ops) = async_channel::bounded(SUBMISSION_CHANNEL_CAPACITY);
@@ -139,6 +140,7 @@ pub(crate) async fn run_codex_thread_interactive(
external_time_provider: Some(Arc::clone(&parent_session.services.time_provider)),
inherited_multi_agent_version: Some(MultiAgentVersion::Disabled),
git_enrichment_policy,
windows_sandbox_proxy_settings_mode,
}))
.or_cancel(&cancel_token)
.await??;
@@ -224,6 +226,7 @@ pub(crate) async fn run_codex_thread_one_shot(
subagent_source,
initial_history,
GitEnrichmentPolicy::Fresh,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
))
.await?;
@@ -212,6 +212,7 @@ async fn run_codex_thread_interactive_respects_pre_cancelled_spawn() {
SubAgentSource::Review,
/*initial_history*/ None,
crate::session::GitEnrichmentPolicy::Fresh,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
),
)
.await
@@ -680,6 +680,7 @@ async fn spawn_guardian_review_session(
SubAgentSource::Other(GUARDIAN_REVIEWER_NAME.to_string()),
initial_history,
GitEnrichmentPolicy::Skip,
codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve,
))
.await?;
@@ -1254,6 +1255,31 @@ mod tests {
}
}
#[tokio::test]
async fn spawned_guardian_session_preserves_windows_sandbox_proxy_settings() {
let params = test_review_params().await;
let manager = GuardianReviewSessionManager::default();
manager
.initialize(params.parent_session, params.parent_turn)
.await
.expect("initialize Guardian session");
let mode = manager
.state
.lock()
.await
.trunk
.as_ref()
.expect("Guardian session")
.session
.windows_sandbox_proxy_settings_mode;
assert_eq!(
mode,
codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve
);
manager.shutdown().await;
}
#[tokio::test]
async fn guardian_review_session_config_change_invalidates_cached_session() {
let parent_config = crate::config::test_config().await;
+4
View File
@@ -455,6 +455,8 @@ pub(crate) struct SessionSpawnArgs {
pub(crate) external_time_provider: Option<Arc<dyn TimeProvider>>,
pub(crate) inherited_multi_agent_version: Option<MultiAgentVersion>,
pub(crate) git_enrichment_policy: GitEnrichmentPolicy,
pub(crate) windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode,
}
pub(crate) fn resolve_multi_agent_version(
@@ -544,6 +546,7 @@ impl Session {
external_time_provider,
inherited_multi_agent_version,
git_enrichment_policy,
windows_sandbox_proxy_settings_mode,
} = args;
let (tx_sub, rx_sub) = async_channel::bounded(SUBMISSION_CHANNEL_CAPACITY);
let (tx_event, rx_event) = async_channel::unbounded();
@@ -732,6 +735,7 @@ impl Session {
external_time_provider,
multi_agent_version,
git_enrichment_policy,
windows_sandbox_proxy_settings_mode,
))
.await
.map_err(|e| {
+4
View File
@@ -37,6 +37,8 @@ pub(crate) struct Session {
/// The set of enabled features should be invariant for the lifetime of the
/// session.
pub(super) features: ManagedFeatures,
pub(crate) windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode,
pub(super) multi_agent_version: OnceLock<MultiAgentVersion>,
pub(super) mcp_refresh_pending: std::sync::atomic::AtomicBool,
/// Serializes runtime refreshes without blocking calls that own a snapshot.
@@ -514,6 +516,7 @@ impl Session {
external_time_provider: Option<Arc<dyn TimeProvider>>,
multi_agent_version: Option<MultiAgentVersion>,
git_enrichment_policy: GitEnrichmentPolicy,
windows_sandbox_proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode,
) -> anyhow::Result<Arc<Self>> {
debug!(
"Configuring session: model={}; provider={:?}",
@@ -1150,6 +1153,7 @@ impl Session {
state: Mutex::new(state),
managed_network_proxy_refresh_lock: Semaphore::new(/*permits*/ 1),
features: config.features.clone(),
windows_sandbox_proxy_settings_mode,
multi_agent_version,
mcp_refresh_pending: std::sync::atomic::AtomicBool::new(false),
mcp_refresh_lock: Semaphore::new(/*permits*/ 1),
+7
View File
@@ -5288,6 +5288,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh() {
/*external_time_provider*/ None,
Some(config.multi_agent_version_from_features()),
GitEnrichmentPolicy::Fresh,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
)
.await;
@@ -5539,6 +5540,8 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
state: Mutex::new(state),
managed_network_proxy_refresh_lock: Semaphore::new(/*permits*/ 1),
features: config.features.clone(),
windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
multi_agent_version: OnceLock::from(config.multi_agent_version_from_features()),
mcp_refresh_pending: std::sync::atomic::AtomicBool::new(true),
mcp_refresh_lock: Semaphore::new(/*permits*/ 1),
@@ -5673,6 +5676,7 @@ async fn make_session_with_config_and_rx(
/*external_time_provider*/ None,
Some(config.multi_agent_version_from_features()),
GitEnrichmentPolicy::Fresh,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
)
.await?;
@@ -5788,6 +5792,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
/*external_time_provider*/ None,
Some(config.multi_agent_version_from_features()),
GitEnrichmentPolicy::Fresh,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
)
.await?;
@@ -7702,6 +7707,8 @@ where
state: Mutex::new(state),
managed_network_proxy_refresh_lock: Semaphore::new(/*permits*/ 1),
features: config.features.clone(),
windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
multi_agent_version: OnceLock::from(config.multi_agent_version_from_features()),
mcp_refresh_pending: std::sync::atomic::AtomicBool::new(true),
mcp_refresh_lock: Semaphore::new(/*permits*/ 1),
@@ -766,6 +766,8 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
external_time_provider: None,
inherited_multi_agent_version: None,
git_enrichment_policy: GitEnrichmentPolicy::Skip,
windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve,
})
.await
.expect("spawn guardian subagent");
@@ -360,6 +360,7 @@ impl TurnContext {
.config
.permissions
.windows_sandbox_private_desktop,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: self.config.features.use_legacy_landlock(),
}
}
+2
View File
@@ -1676,6 +1676,8 @@ impl ThreadManagerState {
external_time_provider: self.external_time_provider.clone(),
inherited_multi_agent_version: multi_agent_version,
git_enrichment_policy: GitEnrichmentPolicy::Fresh,
windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
}))
.await?;
let new_thread = self
@@ -99,6 +99,7 @@ impl ApplyPatchRuntime {
workspace_roots: attempt.workspace_roots.to_vec(),
windows_sandbox_level: attempt.windows_sandbox_level,
windows_sandbox_private_desktop: attempt.windows_sandbox_private_desktop,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: attempt.use_legacy_landlock,
})
}
@@ -302,6 +302,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
ctx: &ToolCtx,
) -> Result<UnifiedExecProcess, ToolError> {
let base_command = &req.command;
let windows_sandbox_proxy_settings_mode = ctx.session.windows_sandbox_proxy_settings_mode;
let session_shell = ctx.session.user_shell();
let shell = req
.turn_environment
@@ -464,6 +465,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
.open_session_with_prepared_exec_env(
req.process_id,
&prepared.exec_request,
windows_sandbox_proxy_settings_mode,
req.tty,
prepared.spawn_lifecycle,
req.turn_environment.environment.as_ref(),
@@ -510,6 +512,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
network_proxy_launch,
/*environment_id*/ Some(&req.turn_environment.environment_id),
req.exec_server_env_config.clone(),
windows_sandbox_proxy_settings_mode,
req.tty,
Box::new(NoopSpawnLifecycle),
req.turn_environment.environment.as_ref(),
+1
View File
@@ -507,6 +507,7 @@ impl<'a> SandboxAttempt<'a> {
workspace_roots: self.workspace_roots.to_vec(),
windows_sandbox_level: self.windows_sandbox_level,
windows_sandbox_private_desktop: self.windows_sandbox_private_desktop,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: self.use_legacy_landlock,
});
exec_request.exec_server_enforce_managed_network = self.enforce_managed_network;
@@ -268,6 +268,7 @@ fn exec_server_env_keeps_command_native_and_carries_sandbox_context() {
workspace_roots: vec![cwd_uri.clone()],
windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: false,
})
);
@@ -113,6 +113,7 @@ async fn exec_command_with_tty(
.open_session_with_prepared_exec_env(
process_id,
&request,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
tty,
Box::new(NoopSpawnLifecycle),
turn.environments
@@ -753,6 +754,7 @@ async fn completed_pipe_commands_preserve_exit_code() -> anyhow::Result<()> {
.open_session_with_prepared_exec_env(
/*process_id*/ 1234,
&request,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
/*tty*/ false,
Box::new(NoopSpawnLifecycle),
&environment,
@@ -793,6 +795,7 @@ async fn unified_exec_uses_remote_exec_server_when_configured() -> anyhow::Resul
.open_session_with_prepared_exec_env(
/*process_id*/ 1234,
&request,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
/*tty*/ true,
Box::new(NoopSpawnLifecycle),
remote_test_env.environment(),
@@ -851,6 +854,7 @@ async fn remote_exec_server_rejects_inherited_fd_launches() -> anyhow::Result<()
.open_session_with_prepared_exec_env(
/*process_id*/ 1234,
&request,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
/*tty*/ true,
Box::new(TestSpawnLifecycle {
inherited_fds: vec![42],
@@ -177,9 +177,14 @@ fn exec_server_env_for_request(
fn exec_server_params_for_request(
process_id: i32,
request: &ExecRequest,
windows_sandbox_proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode,
tty: bool,
) -> codex_exec_server::ExecParams {
let (env_policy, env) = exec_server_env_for_request(request);
let sandbox = request.exec_server_sandbox.clone().map(|mut sandbox| {
sandbox.windows_sandbox_proxy_settings_mode = Some(windows_sandbox_proxy_settings_mode);
sandbox
});
// Sandbox retries reuse the unified-exec ID but start a distinct executor process.
let exec_server_process_id = if request.exec_server_sandbox.is_some() {
format!("{process_id}-{}", Uuid::new_v4())
@@ -195,7 +200,7 @@ fn exec_server_params_for_request(
tty,
pipe_stdin: false,
arg0: request.arg0.clone(),
sandbox: request.exec_server_sandbox.clone(),
sandbox,
enforce_managed_network: request.exec_server_enforce_managed_network,
managed_network: request.exec_server_managed_network.clone(),
network_proxy: request.exec_server_network_proxy.clone(),
@@ -1003,6 +1008,7 @@ impl UnifiedExecProcessManager {
network_proxy_launch: Option<codex_network_proxy::RemoteNetworkProxyLaunchConfig>,
environment_id: Option<&str>,
exec_server_env_config: Option<ExecServerEnvConfig>,
windows_sandbox_proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode,
tty: bool,
spawn_lifecycle: SpawnLifecycleHandle,
environment: &codex_exec_server::Environment,
@@ -1018,6 +1024,7 @@ impl UnifiedExecProcessManager {
self.open_session_with_prepared_exec_env(
process_id,
&request,
windows_sandbox_proxy_settings_mode,
tty,
spawn_lifecycle,
environment,
@@ -1038,6 +1045,7 @@ impl UnifiedExecProcessManager {
&self,
process_id: i32,
request: &ExecRequest,
windows_sandbox_proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode,
tty: bool,
mut spawn_lifecycle: SpawnLifecycleHandle,
environment: &codex_exec_server::Environment,
@@ -1053,7 +1061,12 @@ impl UnifiedExecProcessManager {
let started = environment
.get_exec_backend()
.start(exec_server_params_for_request(process_id, request, tty))
.start(exec_server_params_for_request(
process_id,
request,
windows_sandbox_proxy_settings_mode,
tty,
))
.await
.map_err(|err| UnifiedExecError::create_process(err.to_string()))?;
spawn_lifecycle.after_spawn();
@@ -1100,22 +1113,21 @@ impl UnifiedExecProcessManager {
None::<String>
}
};
let windows_sandbox = if request.sandbox
== codex_sandboxing::SandboxType::WindowsRestrictedToken
{
Some(codex_sandboxing::WindowsSandboxSpawnRequest {
permission_profile: &request.permission_profile,
workspace_roots: &request.windows_sandbox_workspace_roots,
windows_sandbox_level: request.windows_sandbox_level,
proxy_enforced: request.network.is_some(),
network_proxy_restricting_sid: network_proxy_restricting_sid.as_deref(),
proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
filesystem_overrides: request.windows_sandbox_filesystem_overrides.as_ref(),
use_private_desktop: request.windows_sandbox_private_desktop,
})
} else {
None
};
let windows_sandbox =
if request.sandbox == codex_sandboxing::SandboxType::WindowsRestrictedToken {
Some(codex_sandboxing::WindowsSandboxSpawnRequest {
permission_profile: &request.permission_profile,
workspace_roots: &request.windows_sandbox_workspace_roots,
windows_sandbox_level: request.windows_sandbox_level,
proxy_enforced: request.network.is_some(),
network_proxy_restricting_sid: network_proxy_restricting_sid.as_deref(),
proxy_settings_mode: windows_sandbox_proxy_settings_mode,
filesystem_overrides: request.windows_sandbox_filesystem_overrides.as_ref(),
use_private_desktop: request.windows_sandbox_private_desktop,
})
} else {
None
};
let spawn_result = codex_sandboxing::spawn_process(codex_sandboxing::SpawnRequest {
command: &request.command,
cwd: native_cwd.as_path(),
@@ -177,8 +177,16 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() {
exec_server_network_proxy: None,
};
let params =
exec_server_params_for_request(/*process_id*/ 123, &request, /*tty*/ true);
let proxy_settings_mode = codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve;
let params_for_request = |request: &ExecRequest| {
exec_server_params_for_request(
/*process_id*/ 123,
request,
proxy_settings_mode,
/*tty*/ true,
)
};
let params = params_for_request(&request);
assert_eq!(params.process_id.as_str(), "123");
assert_eq!(params.cwd, request.cwd);
@@ -200,10 +208,15 @@ fn exec_server_params_use_path_uri_and_env_policy_overlay_contract() {
request.exec_server_sandbox = Some(
codex_exec_server::FileSystemSandboxContext::from_permission_profile(permission_profile),
);
let first =
exec_server_params_for_request(/*process_id*/ 123, &request, /*tty*/ true);
let second =
exec_server_params_for_request(/*process_id*/ 123, &request, /*tty*/ true);
let first = params_for_request(&request);
let second = params_for_request(&request);
assert_eq!(
first
.sandbox
.as_ref()
.and_then(|sandbox| sandbox.windows_sandbox_proxy_settings_mode),
Some(codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve)
);
assert!(first.process_id.as_str().starts_with("123-"));
assert!(second.process_id.as_str().starts_with("123-"));
assert_ne!(first.process_id, second.process_id);
@@ -743,6 +743,7 @@ mod tests {
use codex_network_proxy::NetworkProxyConfig;
use codex_network_proxy::RemoteNetworkProxyConfig;
use codex_network_proxy::RemoteNetworkProxyLaunchConfig;
use codex_protocol::config_types::WindowsSandboxProxySettingsMode;
use codex_protocol::models::ManagedFileSystemPermissions;
use codex_protocol::models::PermissionProfile;
use codex_protocol::permissions::FileSystemAccessMode;
@@ -938,6 +939,17 @@ mod tests {
.expect("deserialize sandbox"),
sandbox
);
let preserve = FileSystemSandboxContext {
windows_sandbox_proxy_settings_mode: Some(WindowsSandboxProxySettingsMode::Preserve),
..sandbox
};
let serialized = serde_json::to_value(&preserve).expect("serialize preserve mode");
assert_eq!(serialized["windowsSandboxProxySettingsMode"], "preserve");
assert_eq!(
serde_json::from_value::<FileSystemSandboxContext>(serialized)
.expect("deserialize preserve mode"),
preserve
);
}
#[test]
+7 -3
View File
@@ -52,6 +52,7 @@ struct PreparedWindowsSandboxRequest {
windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel,
proxy_enforced: bool,
network_proxy_restricting_sid: Option<String>,
proxy_settings_mode: WindowsSandboxProxySettingsMode,
filesystem_overrides: Option<WindowsSandboxFilesystemOverrides>,
use_private_desktop: bool,
}
@@ -66,7 +67,7 @@ impl PreparedExecRequest {
windows_sandbox_level: request.windows_sandbox_level,
proxy_enforced: request.proxy_enforced,
network_proxy_restricting_sid: request.network_proxy_restricting_sid.as_deref(),
proxy_settings_mode: WindowsSandboxProxySettingsMode::Reconcile,
proxy_settings_mode: request.proxy_settings_mode,
filesystem_overrides: request.filesystem_overrides.as_ref(),
use_private_desktop: request.use_private_desktop,
})
@@ -114,6 +115,9 @@ pub(crate) async fn prepare_exec_request(
windows_sandbox: None,
});
};
let windows_sandbox_proxy_settings_mode = sandbox_context
.windows_sandbox_proxy_settings_mode
.unwrap_or_default();
let runtime_paths = runtime_paths
.ok_or_else(|| invalid_params("sandbox runtime paths are not configured".to_string()))?;
// TODO(jif): Transport permissions before orchestrator-local paths are materialized,
@@ -212,8 +216,7 @@ pub(crate) async fn prepare_exec_request(
let (program, args) = (program.into(), args.to_vec());
let transform_request = SandboxDirectSpawnTransformRequest {
workspace_roots,
windows_sandbox_proxy_settings_mode:
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
windows_sandbox_proxy_settings_mode,
transform: SandboxTransformRequest {
command: SandboxCommand {
program,
@@ -271,6 +274,7 @@ pub(crate) async fn prepare_exec_request(
windows_sandbox_level: sandbox_context.windows_sandbox_level,
proxy_enforced,
network_proxy_restricting_sid,
proxy_settings_mode: windows_sandbox_proxy_settings_mode,
filesystem_overrides,
use_private_desktop: sandbox_context.windows_sandbox_private_desktop,
})
@@ -394,6 +394,8 @@ async fn managed_network_selects_elevated_windows_spawn() {
cwd_uri.clone(),
);
sandbox.windows_sandbox_level = WindowsSandboxLevel::RestrictedToken;
sandbox.windows_sandbox_proxy_settings_mode =
Some(codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve);
let proxy_config = RemoteNetworkProxyConfig::from_effective_config(&NetworkProxyConfig {
enabled: true,
enable_socks5: false,
@@ -434,6 +436,10 @@ async fn managed_network_selects_elevated_windows_spawn() {
);
assert!(spawn.proxy_enforced);
assert!(spawn.network_proxy_restricting_sid.is_some());
assert_eq!(
spawn.proxy_settings_mode,
codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve
);
assert_eq!(spawn.permission_profile, &permissions);
assert_eq!(spawn.workspace_roots, std::slice::from_ref(&cwd));
}
+4
View File
@@ -2,6 +2,7 @@ mod find_up;
use bytes::Bytes;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::config_types::WindowsSandboxProxySettingsMode;
use codex_protocol::models::ManagedFileSystemPermissions;
use codex_protocol::models::PermissionProfile;
use codex_protocol::models::SandboxEnforcement;
@@ -291,6 +292,8 @@ pub struct FileSystemSandboxContext {
pub windows_sandbox_level: WindowsSandboxLevel,
#[serde(default)]
pub windows_sandbox_private_desktop: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub windows_sandbox_proxy_settings_mode: Option<WindowsSandboxProxySettingsMode>,
#[serde(default)]
pub use_legacy_landlock: bool,
}
@@ -332,6 +335,7 @@ impl FileSystemSandboxContext {
workspace_roots,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: false,
}
}
+10
View File
@@ -283,6 +283,16 @@ pub enum WindowsSandboxLevel {
Elevated,
}
/// Controls whether a Windows sandbox launch reconciles persistent proxy settings or preserves
/// the settings established by another launch.
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum WindowsSandboxProxySettingsMode {
#[default]
Reconcile,
Preserve,
}
#[derive(
Debug,
Serialize,
@@ -371,4 +371,36 @@ mod tests {
vec![8080]
);
}
#[test]
fn guardian_preserve_mode_does_not_churn_marker_with_empty_proxy_ports() {
let marker = SetupMarker {
version: crate::setup::SETUP_VERSION,
offline_username: "offline".to_string(),
online_username: "online".to_string(),
created_at: None,
proxy_ports: vec![3128, 8081],
allow_local_binding: true,
};
let env_map = HashMap::new();
let reconciled = desired_offline_proxy_settings(
Some(&marker),
WindowsSandboxProxySettingsMode::Reconcile,
&env_map,
SandboxNetworkIdentity::Offline,
);
assert_eq!(reconciled.proxy_ports, Vec::<u16>::new());
let desired = desired_offline_proxy_settings(
Some(&marker),
WindowsSandboxProxySettingsMode::Preserve,
&env_map,
SandboxNetworkIdentity::Offline,
);
assert_eq!(desired, marker.offline_proxy_settings());
assert_eq!(
marker.request_mismatch_reason(SandboxNetworkIdentity::Offline, &desired),
None
);
}
}
+1 -8
View File
@@ -35,14 +35,7 @@ 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,
}
pub use codex_protocol::config_types::WindowsSandboxProxySettingsMode;
/// Network settings installed by an administrator during managed Windows sandbox setup.
#[derive(Clone, Debug, Default, PartialEq, Eq)]