Preserve Windows proxy settings in Guardian sessions (#40641)

## Why

Guardian sessions can run alongside another Windows sandbox launch and should not reconcile the persistent proxy settings established by that launch.

## What changed

- Start internal Guardian sessions with `WindowsSandboxProxySettingsMode::Preserve`.
- Continue using `Reconcile` for other sessions.

## Testing

Added a thread manager test that verifies a parent session reconciles proxy settings while its internal Guardian session preserves them.

GitOrigin-RevId: c6a31637ecdf828548cfd7153da7e9405abe34fa
This commit is contained in:
Won Park
2026-08-25 16:53:47 +00:00
committed by copyberry
parent 5ce04789fb
commit da4cf1cdea
2 changed files with 55 additions and 2 deletions
+10 -2
View File
@@ -55,6 +55,7 @@ use codex_protocol::mcp::OPENAI_STANDARD_FORM_INPUT_EXTENSION_ID;
use codex_protocol::openai_models::ModelPreset;
use codex_protocol::protocol::Event;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::InternalSessionSource;
use codex_protocol::protocol::MultiAgentVersion;
use codex_protocol::protocol::Op;
use codex_protocol::protocol::SessionConfiguredEvent;
@@ -1938,6 +1939,14 @@ impl ThreadManagerState {
starting.retain(|runtime| runtime.strong_count() != 0);
starting.push(Arc::downgrade(&source_changed_during_startup));
}
let windows_sandbox_proxy_settings_mode = if matches!(
&session_source,
SessionSource::Internal(InternalSessionSource::Guardian)
) {
codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve
} else {
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile
};
let (session, io) = Box::pin(Session::spawn(SessionSpawnArgs {
config,
allow_provider_model_fallback,
@@ -1977,8 +1986,7 @@ 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,
windows_sandbox_proxy_settings_mode,
}))
.await?;
// Enable Full Access form input only after session startup so a required MCP server cannot
+45
View File
@@ -878,6 +878,51 @@ async fn start_thread_keeps_internal_threads_hidden_from_normal_lookups() {
assert!(manager.list_thread_ids().await.is_empty());
}
#[tokio::test]
async fn spawn_internal_guardian_session_preserves_windows_sandbox_proxy_settings() {
let temp_dir = tempdir().expect("tempdir");
let mut config = test_config().await;
config.codex_home = temp_dir.path().join("codex-home").abs();
config.cwd = config.codex_home.abs();
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
let manager = ThreadManager::with_models_provider_and_home_for_tests(
CodexAuth::from_api_key("dummy"),
config.model_provider.clone(),
config.codex_home.to_path_buf(),
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
);
let parent = manager
.start_thread(StartThreadOptions::new(config.clone()))
.await
.expect("start parent thread");
let reviewer = manager
.spawn_internal_session(
parent.thread_id,
StartThreadOptions {
session_source: Some(SessionSource::Internal(InternalSessionSource::Guardian)),
..StartThreadOptions::new(config)
},
)
.await
.expect("start internal reviewer");
assert_eq!(
(
parent.thread.session.windows_sandbox_proxy_settings_mode,
reviewer.thread.session.windows_sandbox_proxy_settings_mode,
),
(
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,
codex_sandboxing::WindowsSandboxProxySettingsMode::Preserve,
)
);
manager
.shutdown_all_threads_bounded(Duration::from_secs(10))
.await;
}
#[tokio::test]
async fn spawn_internal_session_preserves_parent_lineage_without_forking_history() {
struct ParentLifecycleContributor {