From 72f161e41c2376d898610a1fbc47b175496a3afe Mon Sep 17 00:00:00 2001 From: Amruth Venkatraman Date: Wed, 17 Jun 2026 19:12:58 +0000 Subject: [PATCH] Probe bubblewrap for active network proxies --- codex-rs/app-server/src/lib.rs | 2 +- codex-rs/core/src/config/config_tests.rs | 1 + codex-rs/exec/src/lib.rs | 2 +- codex-rs/sandboxing/src/bwrap.rs | 27 ++++++++++++++------- codex-rs/sandboxing/src/bwrap_tests.rs | 31 +++++++++++++++--------- codex-rs/sandboxing/src/lib.rs | 2 +- codex-rs/tui/src/app/startup_prompts.rs | 2 +- 7 files changed, 42 insertions(+), 25 deletions(-) diff --git a/codex-rs/app-server/src/lib.rs b/codex-rs/app-server/src/lib.rs index f3f3428169..d20257db8e 100644 --- a/codex-rs/app-server/src/lib.rs +++ b/codex-rs/app-server/src/lib.rs @@ -631,7 +631,7 @@ pub async fn run_main_with_transport_options( } if let Some(warning) = codex_core::config::system_bwrap_warning( config.permissions.permission_profile(), - config.managed_network_requirements_enabled(), + config.permissions.network.is_some(), ) { config_warnings.push(ConfigWarningNotification { summary: warning, diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 38f04d23b6..8c8c59c742 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -1436,6 +1436,7 @@ async fn network_proxy_feature_uses_profile_network_proxy_settings() -> std::io: config.permissions.network_sandbox_policy(), NetworkSandboxPolicy::Enabled ); + assert!(!config.managed_network_requirements_enabled()); let network = config .permissions .network diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 7acf94f1b8..e94c227012 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -847,7 +847,7 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> { if !json_mode && let Some(message) = codex_core::config::system_bwrap_warning( config.permissions.permission_profile(), - config.managed_network_requirements_enabled(), + config.permissions.network.is_some(), ) { event_processor.process_warning(message); diff --git a/codex-rs/sandboxing/src/bwrap.rs b/codex-rs/sandboxing/src/bwrap.rs index 0690512f43..6ca6983ee7 100644 --- a/codex-rs/sandboxing/src/bwrap.rs +++ b/codex-rs/sandboxing/src/bwrap.rs @@ -54,21 +54,30 @@ enum SystemBwrapProbeResult { pub fn system_bwrap_warning( permission_profile: &PermissionProfile, - has_managed_network_requirements: bool, + managed_network_active: bool, +) -> Option { + let system_bwrap_path = find_system_bwrap_in_path(); + system_bwrap_warning_with_path( + permission_profile, + managed_network_active, + system_bwrap_path.as_deref(), + ) +} + +fn system_bwrap_warning_with_path( + permission_profile: &PermissionProfile, + managed_network_active: bool, + system_bwrap_path: Option<&Path>, ) -> Option { let (file_system_policy, network_policy) = permission_profile.to_runtime_permissions(); - if !should_require_platform_sandbox( - &file_system_policy, - network_policy, - has_managed_network_requirements, - ) { + if !should_require_platform_sandbox(&file_system_policy, network_policy, managed_network_active) + { return None; } - let system_bwrap_path = find_system_bwrap_in_path(); system_bwrap_warning_for_path( - system_bwrap_path.as_deref(), - /*unshare_network*/ !network_policy.is_enabled() || has_managed_network_requirements, + system_bwrap_path, + /*unshare_network*/ !network_policy.is_enabled() || managed_network_active, ) } diff --git a/codex-rs/sandboxing/src/bwrap_tests.rs b/codex-rs/sandboxing/src/bwrap_tests.rs index 39c931f6c7..a09dbd19c7 100644 --- a/codex-rs/sandboxing/src/bwrap_tests.rs +++ b/codex-rs/sandboxing/src/bwrap_tests.rs @@ -1,4 +1,6 @@ use super::*; +use codex_protocol::permissions::FileSystemSandboxPolicy; +use codex_protocol::permissions::NetworkSandboxPolicy; use pretty_assertions::assert_eq; use std::path::Path; use std::path::PathBuf; @@ -140,34 +142,39 @@ exit 1 } #[test] -fn system_bwrap_probe_only_unshares_network_when_required() { +fn active_managed_proxy_probes_network_for_network_enabled_profile() { let fake_bwrap = write_fake_bwrap( r#"#!/bin/sh for arg in "$@"; do if [ "$arg" = "--unshare-net" ]; then - exit 17 + echo 'loopback: Failed RTM_NEWLINK' >&2 + exit 1 fi done exit 0 "#, ); + let permission_profile = PermissionProfile::from_runtime_permissions( + &FileSystemSandboxPolicy::unrestricted(), + NetworkSandboxPolicy::Enabled, + ); let fake_bwrap_path: &Path = fake_bwrap.as_ref(); assert_eq!( - probe_system_bwrap( - fake_bwrap_path, - SYSTEM_BWRAP_PROBE_TIMEOUT, - /*unshare_network*/ false, + system_bwrap_warning_with_path( + &permission_profile, + /*managed_network_active*/ false, + Some(fake_bwrap_path), ), - SystemBwrapProbeResult::Available + None ); assert_eq!( - probe_system_bwrap( - fake_bwrap_path, - SYSTEM_BWRAP_PROBE_TIMEOUT, - /*unshare_network*/ true, + system_bwrap_warning_with_path( + &permission_profile, + /*managed_network_active*/ true, + Some(fake_bwrap_path), ), - SystemBwrapProbeResult::Failed + Some(USER_NAMESPACE_WARNING.to_string()) ); } diff --git a/codex-rs/sandboxing/src/lib.rs b/codex-rs/sandboxing/src/lib.rs index a9a5c7924b..68d5c258c4 100644 --- a/codex-rs/sandboxing/src/lib.rs +++ b/codex-rs/sandboxing/src/lib.rs @@ -26,7 +26,7 @@ use codex_protocol::error::CodexErr; #[cfg(not(target_os = "linux"))] pub fn system_bwrap_warning( _permission_profile: &codex_protocol::models::PermissionProfile, - _has_managed_network_requirements: bool, + _managed_network_active: bool, ) -> Option { None } diff --git a/codex-rs/tui/src/app/startup_prompts.rs b/codex-rs/tui/src/app/startup_prompts.rs index 9ad5866e8b..8a56bd4937 100644 --- a/codex-rs/tui/src/app/startup_prompts.rs +++ b/codex-rs/tui/src/app/startup_prompts.rs @@ -107,7 +107,7 @@ pub(super) fn emit_project_config_warnings(app_event_tx: &AppEventSender, config pub(super) fn emit_system_bwrap_warning(app_event_tx: &AppEventSender, config: &Config) { let Some(message) = codex_sandboxing::system_bwrap_warning( config.permissions.permission_profile(), - config.managed_network_requirements_enabled(), + config.permissions.network.is_some(), ) else { return; };