diff --git a/codex-rs/network-proxy/src/proxy.rs b/codex-rs/network-proxy/src/proxy.rs index 2918e8e8c2..5c37ef15c1 100644 --- a/codex-rs/network-proxy/src/proxy.rs +++ b/codex-rs/network-proxy/src/proxy.rs @@ -201,9 +201,15 @@ impl NetworkProxyBuilder { .await; let current_cfg = state.current_cfg().await?; #[cfg(target_os = "windows")] - let runtime_settings = NetworkProxyRuntimeSettings::from_config(¤t_cfg)?; - #[cfg(target_os = "windows")] - let mut windows_ingress = None; + let (current_cfg, runtime_settings, mut windows_ingress) = { + let current_cfg = config::NetworkProxyConfig { + dangerously_allow_all_unix_sockets: false, + unix_sockets: None, + ..current_cfg + }; + let runtime_settings = NetworkProxyRuntimeSettings::from_config(¤t_cfg)?; + (current_cfg, runtime_settings, None) + }; let (requested_http_addr, requested_socks_addr, reserved_listeners) = if self .managed_by_codex { @@ -390,8 +396,13 @@ impl NetworkProxyRuntimeSettings { }; Ok(Self { allow_local_binding: config.allow_local_binding, - allow_unix_sockets: config.allow_unix_sockets().into(), - dangerously_allow_all_unix_sockets: config.dangerously_allow_all_unix_sockets, + allow_unix_sockets: if cfg!(target_os = "windows") { + Arc::default() + } else { + config.allow_unix_sockets().into() + }, + dangerously_allow_all_unix_sockets: !cfg!(target_os = "windows") + && config.dangerously_allow_all_unix_sockets, mitm_ca_trust_bundle, }) } @@ -1268,7 +1279,7 @@ impl NetworkProxy { return Ok(NetworkProxyHandle::noop()); } - if !unix_socket_permissions_supported() { + if !cfg!(target_os = "windows") && !unix_socket_permissions_supported() { warn!( "allowUnixSockets and dangerouslyAllowAllUnixSockets are macOS-only; requests will be rejected on this platform" ); @@ -1546,6 +1557,91 @@ mod tests { }) } + #[tokio::test] + async fn proxy_startup_ignores_macos_unix_socket_permissions_on_windows() -> Result<()> { + let unix_sockets = crate::config::NetworkUnixSocketPermissions { + entries: [ + ( + "/tmp/allowed.sock".to_string(), + crate::config::NetworkUnixSocketPermission::Allow, + ), + ( + "/tmp/denied.sock".to_string(), + crate::config::NetworkUnixSocketPermission::Deny, + ), + ] + .into_iter() + .collect(), + }; + let config = NetworkProxyConfig { + enabled: true, + 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, + unix_sockets: Some(unix_sockets.clone()), + ..NetworkProxyConfig::default() + }; + let state = Arc::new(network_proxy_state_for_policy(config.clone())); + + let (result, events) = crate::network_policy::test_support::capture_events(|| async { + NetworkProxy::builder() + .state(state) + .managed_by_codex(/*managed_by_codex*/ false) + .build() + .await + }) + .await; + let proxy = result?; + let expected_bind_host = if cfg!(target_os = "windows") { + "0.0.0.0" + } else { + "127.0.0.1" + }; + + assert_eq!( + (proxy.http_addr, proxy.socks_addr), + ( + format!("{expected_bind_host}:3128").parse::()?, + format!("{expected_bind_host}:8081").parse::()?, + ) + ); + let replacement = crate::state::build_config_state(config.clone(), Default::default())?; + proxy.replace_config_state(replacement).await?; + let expected_unix_sockets = if cfg!(target_os = "windows") { + Vec::new() + } else { + vec!["/tmp/allowed.sock".to_string()] + }; + assert_eq!( + proxy.allow_unix_sockets().as_ref(), + expected_unix_sockets.as_slice() + ); + assert_eq!( + proxy.dangerously_allow_all_unix_sockets(), + !cfg!(target_os = "windows") + ); + assert_eq!(proxy.current_cfg().await?, config); + + let remote = proxy.remote_launch_config().await?; + assert_eq!( + ( + remote.proxy.unix_sockets, + remote.proxy.dangerously_allow_all_unix_sockets, + ), + (Some(unix_sockets), true) + ); + let emitted_unix_socket_warning = events.iter().any(|event| { + event.field("message").is_some_and(|message| { + message.contains("unix socket proxying is enabled") + || message.contains("allowUnixSockets") + }) + }); + assert_eq!(emitted_unix_socket_warning, !cfg!(target_os = "windows")); + + Ok(()) + } + #[tokio::test] async fn remote_policy_decider_rechecks_live_policy_and_restores_attribution() -> Result<()> { let captured = Arc::new(Mutex::new(None)); @@ -1685,7 +1781,15 @@ mod tests { assert_eq!(proxy.http_addr, http_addr); assert_eq!(proxy.socks_addr, socks_addr); assert_eq!(proxy.network_proxy_restricting_sid(None), None); - let handle = proxy.run().await.expect("start stable ingress route"); + let (result, events) = + crate::network_policy::test_support::capture_events(|| async { proxy.run().await }) + .await; + let handle = result.expect("start stable ingress route"); + assert!(!events.iter().any(|event| { + event + .field("message") + .is_some_and(|message| message.contains("allowUnixSockets")) + })); let second_state = Arc::new(network_proxy_state_for_policy(NetworkProxyConfig { enabled: true, proxy_url: format!("http://{http_addr}"),