diff --git a/codex-rs/config/src/permissions_toml.rs b/codex-rs/config/src/permissions_toml.rs index 98fd3534d6..48c54ef71c 100644 --- a/codex-rs/config/src/permissions_toml.rs +++ b/codex-rs/config/src/permissions_toml.rs @@ -493,7 +493,7 @@ impl NetworkToml { config.dangerously_allow_non_loopback_proxy = dangerously_allow_non_loopback_proxy; } if let Some(dangerously_allow_all_unix_sockets) = self.dangerously_allow_all_unix_sockets { - config.dangerously_allow_all_unix_sockets = dangerously_allow_all_unix_sockets; + config.dangerously_allow_all_unix_sockets = Some(dangerously_allow_all_unix_sockets); } if let Some(mode) = self.mode { config.mode = mode; @@ -512,8 +512,7 @@ impl NetworkToml { }; proxy_unix_sockets.entries.insert(path.clone(), permission); } - config.unix_sockets = - (!proxy_unix_sockets.entries.is_empty()).then_some(proxy_unix_sockets); + config.unix_sockets = Some(proxy_unix_sockets); } if let Some(allow_local_binding) = self.allow_local_binding { config.allow_local_binding = allow_local_binding; diff --git a/codex-rs/core/src/config/network_proxy_spec.rs b/codex-rs/core/src/config/network_proxy_spec.rs index f29beb47e9..a195ff5f44 100644 --- a/codex-rs/core/src/config/network_proxy_spec.rs +++ b/codex-rs/core/src/config/network_proxy_spec.rs @@ -266,7 +266,7 @@ impl NetworkProxySpec { NetworkProxyConfig { enabled: true, // Without a controller, the owner supplies the entire permission ceiling. - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), allow_local_binding: true, ..NetworkProxyConfig::default() }, @@ -308,6 +308,13 @@ impl NetworkProxySpec { format!("environment network policy violates managed requirements: {error}"), ) })?; + tracing::debug!( + controller_policy = ?controller.map(Self::environment_policy), + controller_allow_all_unix_sockets = ?controller.and_then(|spec| spec.config.dangerously_allow_all_unix_sockets), + attachment_policy = ?policy, + effective_policy = ?spec.environment_policy(), + "resolved environment network policy" + ); Ok(spec) } @@ -394,7 +401,7 @@ impl NetworkProxySpec { if let Some(dangerously_allow_all_unix_sockets) = requirements.dangerously_allow_all_unix_sockets { - config.dangerously_allow_all_unix_sockets = dangerously_allow_all_unix_sockets; + config.dangerously_allow_all_unix_sockets = Some(dangerously_allow_all_unix_sockets); constraints.dangerously_allow_all_unix_sockets = Some(dangerously_allow_all_unix_sockets); } 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 0f3506cac0..b4a2f55be2 100644 --- a/codex-rs/core/src/config/network_proxy_spec_tests.rs +++ b/codex-rs/core/src/config/network_proxy_spec_tests.rs @@ -24,6 +24,134 @@ fn domain_permissions( } } +#[tokio::test] +async fn attachment_socket_grants_respect_configured_restrictions_at_remote_launch() +-> anyhow::Result<()> { + let profile = PermissionProfile::workspace_write(); + let owner = EnvironmentNetworkPolicy::from_config( + &NetworkProxyConfig { + dangerously_allow_all_unix_sockets: Some(true), + ..Default::default() + }, + /*managed_allowed_domains_only*/ false, + ); + for (name, toml, required, expected) in [ + ("omitted", "", None, true), + ( + "explicit_deny", + "dangerously_allow_all_unix_sockets = false", + None, + false, + ), + ( + "explicit_allow", + "dangerously_allow_all_unix_sockets = true", + None, + true, + ), + ( + "finite", + "unix_sockets = { '/tmp/allowed.sock' = 'allow', '/tmp/denied.sock' = 'deny' }", + None, + false, + ), + ("empty", "unix_sockets = {}", None, false), + ( + "managed_deny", + "dangerously_allow_all_unix_sockets = true", + Some(false), + false, + ), + ] { + let configured: codex_config::permissions_toml::NetworkToml = toml::from_str(toml)?; + let controller = NetworkProxySpec::from_config_and_constraints( + configured.to_network_proxy_config(), + Some(NetworkConstraints { + enabled: Some(true), + dangerously_allow_all_unix_sockets: required, + ..Default::default() + }), + &profile, + )?; + let composed = NetworkProxySpec::for_environment( + Some(&controller), + &owner, + &profile, + &Policy::empty(), + )?; + assert_eq!( + composed.config.dangerously_allow_all_unix_sockets, + Some(expected), + "{name}" + ); + let state = Arc::new(controller.build_state_with_audit_metadata(Default::default())?); + let proxy = NetworkProxy::builder() + .state(Arc::clone(&state)) + .managed_by_codex(false) + .build() + .await?; + let scoped = proxy.for_execution( + "socket-test", + name, + format!("socket-{name}"), + Some(composed.environment_policy()), + /*fallback_policy_decider*/ None, + )?; + let launch = scoped.remote_launch_config().await?; + assert_eq!( + launch.proxy.dangerously_allow_all_unix_sockets, expected, + "{name}" + ); + assert_eq!( + launch.proxy.unix_sockets, composed.config.unix_sockets, + "{name}" + ); + if name == "finite" { + assert_eq!(launch.proxy.unix_sockets, controller.config.unix_sockets); + } + if name == "omitted" { + // Inheritance must not grant sockets to ordinary controller-only commands. + assert!( + !proxy + .remote_launch_config() + .await? + .proxy + .dangerously_allow_all_unix_sockets + ); + state.add_allowed_domain("granted.example").await?; + assert!( + scoped + .remote_launch_config() + .await? + .proxy + .dangerously_allow_all_unix_sockets + ); + + // A live handle must also honor a subsequently installed explicit restriction. + let restricted = NetworkProxySpec::from_config_and_constraints( + NetworkProxyConfig { + enabled: true, + dangerously_allow_all_unix_sockets: Some(false), + ..Default::default() + }, + /*requirements*/ None, + &profile, + )?; + proxy + .replace_config_state(restricted.build_config_state_for_spec()?) + .await?; + assert!( + !scoped + .remote_launch_config() + .await? + .proxy + .dangerously_allow_all_unix_sockets + ); + } + } + Ok(()) +} + #[test] fn build_state_with_audit_metadata_threads_metadata_to_state() { let spec = NetworkProxySpec { @@ -119,7 +247,7 @@ fn environment_policy_replaces_soft_controller_allowlist_and_preserves_denials() "/private/tmp/controller.sock".to_string(), "/tmp/allowed.sock".to_string(), ]); - owner.dangerously_allow_all_unix_sockets = true; + owner.dangerously_allow_all_unix_sockets = Some(true); owner.allow_local_binding = true; let owner_policy = EnvironmentNetworkPolicy::from_config(&owner, /*managed_allowed_domains_only*/ false); @@ -162,7 +290,7 @@ fn environment_policy_replaces_soft_controller_allowlist_and_preserves_denials() ); owner.unix_sockets.clone_from(&spec.config.unix_sockets); owner.allow_upstream_proxy = false; - owner.dangerously_allow_all_unix_sockets = false; + owner.dangerously_allow_all_unix_sockets = Some(false); owner.allow_local_binding = false; assert_eq!( restricted.environment_policy(), diff --git a/codex-rs/core/tests/suite/remote_env.rs b/codex-rs/core/tests/suite/remote_env.rs index 78c3d5ed3b..f305233450 100644 --- a/codex-rs/core/tests/suite/remote_env.rs +++ b/codex-rs/core/tests/suite/remote_env.rs @@ -2383,6 +2383,17 @@ async fn deferred_executor_spawn_agent_inherits_ready_step_environments( ], ) .await; + // If the child finishes after the parent's last request, its completion + // notification triggers one more parent request. Allow either ordering. + mount_sse_once( + &server, + sse(vec![ + ev_response_created("resp-child-completion"), + ev_assistant_message("msg-child-completion", "done"), + ev_completed("resp-child-completion"), + ]), + ) + .await; let mut builder = test_codex() .with_exec_server_url(format!("ws://{}", listener.local_addr()?)) .with_config(move |config| { diff --git a/codex-rs/linux-sandbox/tests/suite/managed_proxy_unix_sockets_tests.rs b/codex-rs/linux-sandbox/tests/suite/managed_proxy_unix_sockets_tests.rs index 24b4b748fe..f8f26ca3c7 100644 --- a/codex-rs/linux-sandbox/tests/suite/managed_proxy_unix_sockets_tests.rs +++ b/codex-rs/linux-sandbox/tests/suite/managed_proxy_unix_sockets_tests.rs @@ -134,7 +134,7 @@ for family in (socket.AF_NETLINK, getattr(socket, 'AF_VSOCK', 40)): let mut config = NetworkProxyConfig { enabled: true, proxy_url: "http://127.0.0.1:9".to_string(), - dangerously_allow_all_unix_sockets, + dangerously_allow_all_unix_sockets: Some(dangerously_allow_all_unix_sockets), ..Default::default() }; if allow_path { diff --git a/codex-rs/network-proxy/src/config.rs b/codex-rs/network-proxy/src/config.rs index 0a880282ed..587318a845 100644 --- a/codex-rs/network-proxy/src/config.rs +++ b/codex-rs/network-proxy/src/config.rs @@ -126,8 +126,9 @@ pub struct NetworkProxyConfig { pub allow_upstream_proxy: bool, #[serde(default)] pub dangerously_allow_non_loopback_proxy: bool, - #[serde(default)] - pub dangerously_allow_all_unix_sockets: bool, + /// When no socket map is set, omission defers to attachment policy; execution defaults to false. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub dangerously_allow_all_unix_sockets: Option, #[serde(default)] pub mode: NetworkMode, #[serde(default)] @@ -166,7 +167,7 @@ impl Default for NetworkProxyConfig { enable_socks5_udp: true, allow_upstream_proxy: true, dangerously_allow_non_loopback_proxy: false, - dangerously_allow_all_unix_sockets: false, + dangerously_allow_all_unix_sockets: None, mode: NetworkMode::default(), domains: None, unix_sockets: None, @@ -345,7 +346,7 @@ impl NetworkProxyConfig { for entry in entries { unix_sockets.entries.insert(entry, permission); } - self.unix_sockets = (!unix_sockets.entries.is_empty()).then_some(unix_sockets); + self.unix_sockets = Some(unix_sockets); } } @@ -428,7 +429,9 @@ pub(crate) fn clamp_bind_addrs( "SOCKS5 proxy", "dangerously_allow_non_loopback_proxy", ); - if cfg.allow_unix_sockets().is_empty() && !cfg.dangerously_allow_all_unix_sockets { + if cfg.allow_unix_sockets().is_empty() + && !cfg.dangerously_allow_all_unix_sockets.unwrap_or(false) + { return (http_addr, socks_addr); } @@ -694,7 +697,7 @@ mod tests { enable_socks5_udp: true, allow_upstream_proxy: true, dangerously_allow_non_loopback_proxy: false, - dangerously_allow_all_unix_sockets: false, + dangerously_allow_all_unix_sockets: None, mode: NetworkMode::Full, domains: None, unix_sockets: None, @@ -888,7 +891,6 @@ mod tests { "enable_socks5_udp": true, "allow_upstream_proxy": true, "dangerously_allow_non_loopback_proxy": false, - "dangerously_allow_all_unix_sockets": false, "mode": "full", "domains": { "example.com": "deny", @@ -1070,7 +1072,7 @@ mod tests { fn clamp_bind_addrs_forces_loopback_when_all_unix_sockets_enabled() { let cfg = NetworkProxyConfig { dangerously_allow_non_loopback_proxy: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..Default::default() }; let http_addr = "0.0.0.0:3128".parse::().unwrap(); diff --git a/codex-rs/network-proxy/src/environment_policy.rs b/codex-rs/network-proxy/src/environment_policy.rs index 365f7b2690..c375a90553 100644 --- a/codex-rs/network-proxy/src/environment_policy.rs +++ b/codex-rs/network-proxy/src/environment_policy.rs @@ -27,7 +27,9 @@ impl EnvironmentNetworkPolicy { domains: config.domains.clone(), unix_sockets: config.unix_sockets.clone(), allow_upstream_proxy: config.allow_upstream_proxy, - dangerously_allow_all_unix_sockets: config.dangerously_allow_all_unix_sockets, + dangerously_allow_all_unix_sockets: config + .dangerously_allow_all_unix_sockets + .unwrap_or(false), allow_local_binding: config.allow_local_binding, managed_allowed_domains_only, } @@ -45,11 +47,16 @@ impl EnvironmentNetworkPolicy { crate::normalize_host, ); } + // An omitted controller policy leaves socket permissions to the attachment; + // an explicitly empty socket map still supplies a restrictive ceiling. + let inherited_allow_all = config + .dangerously_allow_all_unix_sockets + .unwrap_or(config.unix_sockets.is_none()); let inherited_sockets = config.unix_sockets.take().unwrap_or_default(); let mut effective_sockets = self.unix_sockets.clone().unwrap_or_default(); // "Allow all" cannot override a socket denied by either policy. - let inherited_permits_all = config.dangerously_allow_all_unix_sockets + let inherited_permits_all = inherited_allow_all && !inherited_sockets .entries .values() @@ -77,7 +84,8 @@ impl EnvironmentNetworkPolicy { // Enable permissions only when both controller and owner allow them. config.unix_sockets = (!effective_sockets.entries.is_empty()).then_some(effective_sockets); - config.dangerously_allow_all_unix_sockets = inherited_permits_all && owner_permits_all; + config.dangerously_allow_all_unix_sockets = + Some(inherited_permits_all && owner_permits_all); config.allow_upstream_proxy &= self.allow_upstream_proxy; config.allow_local_binding &= self.allow_local_binding; } diff --git a/codex-rs/network-proxy/src/proxy.rs b/codex-rs/network-proxy/src/proxy.rs index e8dc40864d..ab7d398b41 100644 --- a/codex-rs/network-proxy/src/proxy.rs +++ b/codex-rs/network-proxy/src/proxy.rs @@ -228,7 +228,7 @@ impl NetworkProxyBuilder { #[cfg(target_os = "windows")] let (current_cfg, runtime_settings, mut windows_ingress) = { let current_cfg = config::NetworkProxyConfig { - dangerously_allow_all_unix_sockets: false, + dangerously_allow_all_unix_sockets: Some(false), unix_sockets: None, ..current_cfg }; @@ -461,7 +461,7 @@ impl NetworkProxyRuntimeSettings { config.allow_unix_sockets().into() }, dangerously_allow_all_unix_sockets: !cfg!(target_os = "windows") - && config.dangerously_allow_all_unix_sockets, + && config.dangerously_allow_all_unix_sockets.unwrap_or(false), mitm_ca_trust_bundle, }) } @@ -940,6 +940,20 @@ impl NetworkProxy { }; broker_only_config.set_credential_broker_enabled(/*enabled*/ true); broker_only_config.set_allowed_domains(vec!["*".to_string()]); + // Omission and explicit false have the same effective broker-only permissions. + if !config.dangerously_allow_all_unix_sockets.unwrap_or(false) { + broker_only_config.dangerously_allow_all_unix_sockets = + config.dangerously_allow_all_unix_sockets; + } + if config + .unix_sockets + .as_ref() + .is_some_and(|sockets| sockets.entries.is_empty()) + { + broker_only_config + .unix_sockets + .clone_from(&config.unix_sockets); + } let broker_only = brokerage_created_default_allowlist && config == broker_only_config; let environment_policy = self @@ -962,6 +976,7 @@ impl NetworkProxy { "environment network policy requires an enabled executor proxy" ); let proxy = crate::RemoteNetworkProxyConfig::from_effective_config(&config)?; + tracing::debug!(network_config = ?proxy, "resolved remote execution network configuration"); let (environment_id, execution_id) = self .execution_scope .as_ref() @@ -1774,7 +1789,7 @@ mod tests { proxy_url: "http://0.0.0.0:3128".to_string(), socks_url: "http://0.0.0.0:8081".to_string(), dangerously_allow_non_loopback_proxy: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), unix_sockets: Some(unix_sockets.clone()), ..NetworkProxyConfig::default() }; @@ -2153,7 +2168,7 @@ mod tests { .await?; for allow_all in [false, true] { - config.dangerously_allow_all_unix_sockets = allow_all; + config.dangerously_allow_all_unix_sockets = Some(allow_all); let replacement = crate::state::build_config_state(config.clone(), Default::default())?; proxy.replace_config_state(replacement).await?; let prepared = proxy @@ -2310,8 +2325,10 @@ mod tests { let _permit = WINDOWS_INGRESS_TEST_LOCK.acquire().await.unwrap(); let mut config = NetworkProxyConfig { dangerously_allow_plaintext_credential_injection: true, + dangerously_allow_all_unix_sockets: Some(false), ..NetworkProxyConfig::default() }; + config.set_allow_unix_sockets(Vec::new()); config.set_credential_broker_enabled(/*enabled*/ true); config.configure_credential_broker_environment(&HashMap::from([( "GH_HOST".to_string(), diff --git a/codex-rs/network-proxy/src/remote_config.rs b/codex-rs/network-proxy/src/remote_config.rs index 3bb5101a61..a230699489 100644 --- a/codex-rs/network-proxy/src/remote_config.rs +++ b/codex-rs/network-proxy/src/remote_config.rs @@ -87,7 +87,9 @@ impl RemoteNetworkProxyConfig { enable_socks5: config.enable_socks5, enable_socks5_udp: config.enable_socks5_udp, allow_upstream_proxy: config.allow_upstream_proxy, - dangerously_allow_all_unix_sockets: config.dangerously_allow_all_unix_sockets, + dangerously_allow_all_unix_sockets: config + .dangerously_allow_all_unix_sockets + .unwrap_or(false), mode: config.mode, domains: config.domains.clone(), unix_sockets: config.unix_sockets.clone(), @@ -101,7 +103,7 @@ impl RemoteNetworkProxyConfig { enable_socks5: self.enable_socks5, enable_socks5_udp: self.enable_socks5_udp, allow_upstream_proxy: self.allow_upstream_proxy, - dangerously_allow_all_unix_sockets: self.dangerously_allow_all_unix_sockets, + dangerously_allow_all_unix_sockets: Some(self.dangerously_allow_all_unix_sockets), mode: self.mode, domains: self.domains, unix_sockets: self.unix_sockets, diff --git a/codex-rs/network-proxy/src/remote_config_tests.rs b/codex-rs/network-proxy/src/remote_config_tests.rs index 5094acfaad..6661ec81a1 100644 --- a/codex-rs/network-proxy/src/remote_config_tests.rs +++ b/codex-rs/network-proxy/src/remote_config_tests.rs @@ -8,6 +8,36 @@ use crate::NetworkProxyAuditMetadata; use crate::NetworkProxyConfig; use crate::NetworkProxyState; +#[test] +fn optional_socket_policy_preserves_input_and_resolves_at_remote_boundary() { + for allow_all in [None, Some(false), Some(true)] { + let mut config = NetworkProxyConfig { + dangerously_allow_all_unix_sockets: allow_all, + ..NetworkProxyConfig::default() + }; + config.set_allow_unix_sockets(Vec::new()); + let serialized = serde_json::to_value(&config).expect("serialize config"); + assert_eq!( + serialized.get("dangerously_allow_all_unix_sockets"), + allow_all.map(serde_json::Value::Bool).as_ref() + ); + assert_eq!(serialized["unix_sockets"], serde_json::json!({})); + assert_eq!( + serde_json::from_value::(serialized).expect("deserialize config"), + config + ); + + let remote = RemoteNetworkProxyConfig::from_effective_config(&config) + .expect("supported remote config"); + assert_eq!( + remote.dangerously_allow_all_unix_sockets, + allow_all.unwrap_or(false) + ); + config.dangerously_allow_all_unix_sockets = Some(allow_all.unwrap_or(false)); + assert_eq!(remote.into_network_proxy_config(), config); + } +} + #[test] fn round_trip_preserves_supported_effective_settings() { let mut config = NetworkProxyConfig { @@ -15,7 +45,7 @@ fn round_trip_preserves_supported_effective_settings() { enable_socks5: false, enable_socks5_udp: false, allow_upstream_proxy: false, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), mode: NetworkMode::Limited, allow_local_binding: true, ..NetworkProxyConfig::default() diff --git a/codex-rs/network-proxy/src/runtime.rs b/codex-rs/network-proxy/src/runtime.rs index dad445d622..4ffe48d349 100644 --- a/codex-rs/network-proxy/src/runtime.rs +++ b/codex-rs/network-proxy/src/runtime.rs @@ -786,7 +786,11 @@ impl NetworkProxyState { } let guard = self.state.read().await; - if guard.config.dangerously_allow_all_unix_sockets { + if guard + .config + .dangerously_allow_all_unix_sockets + .unwrap_or(false) + { return Ok(true); } @@ -2038,7 +2042,7 @@ mod tests { let config = NetworkProxyConfig { enabled: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..NetworkProxyConfig::default() }; @@ -2055,7 +2059,7 @@ mod tests { let config = NetworkProxyConfig { enabled: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..NetworkProxyConfig::default() }; @@ -2071,7 +2075,7 @@ mod tests { let config = NetworkProxyConfig { enabled: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..NetworkProxyConfig::default() }; @@ -2084,7 +2088,7 @@ mod tests { let config = NetworkProxyConfig { enabled: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..NetworkProxyConfig::default() }; @@ -2244,7 +2248,7 @@ mod tests { async fn unix_socket_allow_all_flag_bypasses_allowlist() { let state = network_proxy_state_for_policy({ let mut network = network_settings(&["example.com"], &[]); - network.dangerously_allow_all_unix_sockets = true; + network.dangerously_allow_all_unix_sockets = Some(true); network }); @@ -2262,7 +2266,7 @@ mod tests { &[], std::slice::from_ref(&socket_path), ); - network.dangerously_allow_all_unix_sockets = true; + network.dangerously_allow_all_unix_sockets = Some(true); network }); diff --git a/codex-rs/network-proxy/src/state.rs b/codex-rs/network-proxy/src/state.rs index 90731a8b4e..d5a1f513b4 100644 --- a/codex-rs/network-proxy/src/state.rs +++ b/codex-rs/network-proxy/src/state.rs @@ -209,7 +209,7 @@ pub fn validate_policy_against_constraints( .dangerously_allow_all_unix_sockets .unwrap_or(constraints.allow_unix_sockets.is_none()); validate( - config.dangerously_allow_all_unix_sockets, + config.dangerously_allow_all_unix_sockets.unwrap_or(false), move |candidate| { if *candidate && !allow_all_unix_sockets { Err(invalid_value( diff --git a/codex-rs/sandboxing/src/manager_tests.rs b/codex-rs/sandboxing/src/manager_tests.rs index 149c741a3c..5bf8736fc7 100644 --- a/codex-rs/sandboxing/src/manager_tests.rs +++ b/codex-rs/sandboxing/src/manager_tests.rs @@ -520,7 +520,7 @@ async fn linux_unix_socket_grant_uses_effective_managed_policy() -> anyhow::Resu let state = build_config_state( NetworkProxyConfig { enabled: true, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..Default::default() }, NetworkProxyConstraints::default(), diff --git a/codex-rs/sandboxing/src/seatbelt_tests.rs b/codex-rs/sandboxing/src/seatbelt_tests.rs index 4b2a36f670..824e83af6a 100644 --- a/codex-rs/sandboxing/src/seatbelt_tests.rs +++ b/codex-rs/sandboxing/src/seatbelt_tests.rs @@ -813,7 +813,7 @@ async fn prepared_managed_network_context_takes_precedence_over_live_proxy_socke let network_config = NetworkProxyConfig { enabled: true, mode: NetworkMode::Full, - dangerously_allow_all_unix_sockets: true, + dangerously_allow_all_unix_sockets: Some(true), ..Default::default() }; let state = build_config_state(network_config, NetworkProxyConstraints::default())?; diff --git a/codex-rs/tui/src/app/agents_overview_tests.rs b/codex-rs/tui/src/app/agents_overview_tests.rs index a045d8d613..f1ebf9250a 100644 --- a/codex-rs/tui/src/app/agents_overview_tests.rs +++ b/codex-rs/tui/src/app/agents_overview_tests.rs @@ -1787,7 +1787,8 @@ async fn overview_cold_resume_honors_working_directory_selection() -> Result<()> ("session", true, true), ("session", false, false), ] { - let mut app = make_test_app().await; + // Keep the large setup and cold-resume futures off the Windows test stack. + let mut app = Box::pin(make_test_app()).await; trust_fixture_folders(&mut app); let chosen = app.config.codex_home.join("chosen"); let overridden = app.config.codex_home.join("overridden"); @@ -1814,7 +1815,8 @@ async fn overview_cold_resume_honors_working_directory_selection() -> Result<()> ) .expect("create historical session"), )?; - let mut app_server = crate::start_embedded_app_server_for_picker(&app.config).await?; + let mut app_server = + Box::pin(crate::start_embedded_app_server_for_picker(&app.config)).await?; app.launch_cwd = chosen.to_path_buf(); app.harness_overrides.cwd = cli_cwd.then(|| { if runtime_cwd { @@ -1838,8 +1840,7 @@ async fn overview_cold_resume_honors_working_directory_selection() -> Result<()> drop(selection); let pending_loading = crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal).clone(); - app.select_agents_overview_thread(&mut tui, &mut app_server, thread_id) - .await?; + Box::pin(app.select_agents_overview_thread(&mut tui, &mut app_server, thread_id)).await?; // The widget replacement clears the terminal; feedback must remain until the next draw. let loading = crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal).clone(); @@ -1858,21 +1859,19 @@ async fn overview_cold_resume_honors_working_directory_selection() -> Result<()> insta::allow_duplicates! { insta::assert_snapshot!(loading_text.trim_end(), @"Loading task…"); } - app.handle_tui_event(&mut tui, &mut app_server, TuiEvent::Draw) - .await?; + Box::pin(app.handle_tui_event(&mut tui, &mut app_server, TuiEvent::Draw)).await?; assert_ne!( crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal), &loading, ); - let observed = app_server - .resume_thread( - &app.local_settings, - app.config.clone(), - thread_id, - crate::app_server_session::ResumeModelSettings::PreserveExistingThread, - ) - .await? - .session; + let observed = Box::pin(app_server.resume_thread( + &app.local_settings, + app.config.clone(), + thread_id, + crate::app_server_session::ResumeModelSettings::PreserveExistingThread, + )) + .await? + .session; assert_eq!( (app.config.cwd.clone(), observed.cwd), (expected_cwd.clone(), expected_cwd),