From e29a8a4de6972c917c0d5044549b5b6eba11877a Mon Sep 17 00:00:00 2001 From: Winston Howes Date: Tue, 26 May 2026 16:30:59 -0700 Subject: [PATCH] Preserve Linux CA bundles for MITM trust --- codex-rs/cli/src/debug_sandbox.rs | 2 +- codex-rs/core/src/landlock.rs | 4 +- codex-rs/linux-sandbox/src/bwrap.rs | 156 +++++++++++++------ codex-rs/linux-sandbox/src/linux_run_main.rs | 26 ++-- codex-rs/network-proxy/README.md | 4 +- codex-rs/network-proxy/src/certs.rs | 4 + codex-rs/network-proxy/src/proxy.rs | 22 ++- codex-rs/sandboxing/src/landlock.rs | 20 +-- codex-rs/sandboxing/src/landlock_tests.rs | 21 +-- codex-rs/sandboxing/src/manager.rs | 5 +- 10 files changed, 169 insertions(+), 95 deletions(-) diff --git a/codex-rs/cli/src/debug_sandbox.rs b/codex-rs/cli/src/debug_sandbox.rs index d68f0f5215..8aa6734837 100644 --- a/codex-rs/cli/src/debug_sandbox.rs +++ b/codex-rs/cli/src/debug_sandbox.rs @@ -300,7 +300,7 @@ async fn run_command_under_sandbox( sandbox_policy_cwd.as_path(), use_legacy_landlock, allow_network_for_proxy(managed_network_requirements_enabled), - /*mitm_ca_trust_bundle_path*/ None, + /*mitm_ca_cert_path*/ None, ); spawn_debug_sandbox_child( codex_linux_sandbox_exe, diff --git a/codex-rs/core/src/landlock.rs b/codex-rs/core/src/landlock.rs index 1beba39192..79048a78e0 100644 --- a/codex-rs/core/src/landlock.rs +++ b/codex-rs/core/src/landlock.rs @@ -34,7 +34,7 @@ where P: AsRef, { let network_sandbox_policy = permission_profile.network_sandbox_policy(); - let mitm_ca_trust_bundle_path = network.and_then(NetworkProxy::mitm_ca_trust_bundle_path); + let mitm_ca_cert_path = network.and_then(NetworkProxy::mitm_ca_cert_path); let args = create_linux_sandbox_command_args_for_permission_profile( command, command_cwd.as_path(), @@ -42,7 +42,7 @@ where sandbox_policy_cwd, use_legacy_landlock, allow_network_for_proxy(/*enforce_managed_network*/ false), - mitm_ca_trust_bundle_path.as_deref(), + mitm_ca_cert_path.as_deref(), ); let codex_linux_sandbox_exe = codex_linux_sandbox_exe.as_ref(); // Preserve the helper alias when we already have it; otherwise force argv0 diff --git a/codex-rs/linux-sandbox/src/bwrap.rs b/codex-rs/linux-sandbox/src/bwrap.rs index 911c8cdfbd..70d79327b0 100644 --- a/codex-rs/linux-sandbox/src/bwrap.rs +++ b/codex-rs/linux-sandbox/src/bwrap.rs @@ -12,12 +12,17 @@ use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashSet; +use std::ffi::CString; use std::ffi::OsString; use std::fs; use std::fs::File; use std::fs::Metadata; use std::io; +use std::io::Seek; +use std::io::SeekFrom; +use std::io::Write; use std::os::fd::AsRawFd; +use std::os::fd::FromRawFd; use std::os::unix::ffi::OsStringExt; use std::os::unix::fs::MetadataExt; use std::path::Path; @@ -78,8 +83,8 @@ pub(crate) struct BwrapOptions { /// Keep this uncapped by default so existing nested deny-read matches are /// masked before the sandboxed command starts. pub glob_scan_max_depth: Option, - /// Managed MITM CA bundle to materialize at common Linux trust-store paths. - pub mitm_ca_trust_bundle_path: Option, + /// Managed MITM CA cert to append to common Linux trust-store paths. + pub mitm_ca_cert_path: Option, } impl Default for BwrapOptions { @@ -88,7 +93,7 @@ impl Default for BwrapOptions { mount_proc: true, network_mode: BwrapNetworkMode::FullAccess, glob_scan_max_depth: None, - mitm_ca_trust_bundle_path: None, + mitm_ca_cert_path: None, } } } @@ -255,7 +260,7 @@ pub(crate) fn create_bwrap_command_args( // need concrete bwrap masks for the matches expanded below. if file_system_sandbox_policy.has_full_disk_write_access() && unreadable_globs.is_empty() { return if options.network_mode == BwrapNetworkMode::FullAccess - && options.mitm_ca_trust_bundle_path.is_none() + && options.mitm_ca_cert_path.is_none() { Ok(BwrapArgs { args: command, @@ -298,10 +303,7 @@ fn create_bwrap_flags_full_filesystem( synthetic_mount_targets: Vec::new(), protected_create_targets: Vec::new(), }; - append_mitm_ca_trust_bundle_args( - &mut bwrap_args, - options.mitm_ca_trust_bundle_path.as_deref(), - )?; + append_mitm_ca_trust_bundle_args(&mut bwrap_args, options.mitm_ca_cert_path.as_deref())?; if options.network_mode.should_unshare_network() { bwrap_args.args.push("--unshare-net".to_string()); } @@ -345,10 +347,7 @@ fn create_bwrap_flags( synthetic_mount_targets, protected_create_targets, }; - append_mitm_ca_trust_bundle_args( - &mut bwrap_args, - options.mitm_ca_trust_bundle_path.as_deref(), - )?; + append_mitm_ca_trust_bundle_args(&mut bwrap_args, options.mitm_ca_cert_path.as_deref())?; // Request a user namespace explicitly rather than relying on bubblewrap's // auto-enable behavior, which is skipped when the caller runs as uid 0. bwrap_args.args.push("--unshare-user".to_string()); @@ -378,31 +377,89 @@ fn create_bwrap_flags( fn append_mitm_ca_trust_bundle_args( bwrap_args: &mut BwrapArgs, - mitm_ca_trust_bundle_path: Option<&Path>, + mitm_ca_cert_path: Option<&Path>, ) -> Result<()> { - let Some(mitm_ca_trust_bundle_path) = mitm_ca_trust_bundle_path else { + let bundle_paths = LINUX_CA_BUNDLE_PATHS.map(Path::new); + append_mitm_ca_trust_bundle_args_for_paths(bwrap_args, mitm_ca_cert_path, &bundle_paths) +} + +fn append_mitm_ca_trust_bundle_args_for_paths( + bwrap_args: &mut BwrapArgs, + mitm_ca_cert_path: Option<&Path>, + bundle_paths: &[&Path], +) -> Result<()> { + let Some(mitm_ca_cert_path) = mitm_ca_cert_path else { return Ok(()); }; + let managed_ca_cert = fs::read(mitm_ca_cert_path).map_err(|err| { + CodexErr::Fatal(format!( + "failed to read managed MITM CA cert {}: {err}", + mitm_ca_cert_path.display() + )) + })?; - for bundle_path in LINUX_CA_BUNDLE_PATHS { - let bundle_file = File::open(mitm_ca_trust_bundle_path).map_err(|err| { - CodexErr::Fatal(format!( - "failed to open managed MITM CA trust bundle {}: {err}", - mitm_ca_trust_bundle_path.display() - )) - })?; + for bundle_path in bundle_paths { + // Only overlay trust-store files the sandbox would already have seen. + let Ok(system_bundle) = fs::read(bundle_path) else { + continue; + }; + let bundle_file = preserved_file_from_bytes(build_mitm_ca_bundle_overlay( + system_bundle, + &managed_ca_cert, + ))?; let bundle_fd = bundle_file.as_raw_fd().to_string(); bwrap_args.preserved_files.push(bundle_file); bwrap_args.args.push("--perms".to_string()); bwrap_args.args.push("444".to_string()); bwrap_args.args.push("--ro-bind-data".to_string()); bwrap_args.args.push(bundle_fd); - bwrap_args.args.push(bundle_path.to_string()); + bwrap_args.args.push(path_to_string(bundle_path)); } Ok(()) } +fn build_mitm_ca_bundle_overlay(mut system_bundle: Vec, managed_ca_cert: &[u8]) -> Vec { + append_pem_bytes(&mut system_bundle, managed_ca_cert); + system_bundle +} + +fn append_pem_bytes(bundle: &mut Vec, pem: &[u8]) { + if !bundle.is_empty() && !bundle.ends_with(b"\n") { + bundle.push(b'\n'); + } + bundle.extend_from_slice(pem); + if !bundle.ends_with(b"\n") { + bundle.push(b'\n'); + } +} + +fn preserved_file_from_bytes(contents: Vec) -> Result { + let memfd_name = CString::new("codex-mitm-ca-bundle").expect("static memfd name"); + // SAFETY: `memfd_name` is a valid NUL-terminated C string and the flags are valid. + let fd = unsafe { libc::memfd_create(memfd_name.as_ptr(), libc::MFD_CLOEXEC) }; + if fd < 0 { + return Err(CodexErr::Fatal(format!( + "failed to create managed MITM CA bundle memfd: {}", + io::Error::last_os_error() + ))); + } + + // SAFETY: `fd` is a newly created owned file descriptor from `memfd_create`. + let mut file = unsafe { File::from_raw_fd(fd) }; + file.write_all(&contents).map_err(|err| { + CodexErr::Fatal(format!( + "failed to write managed MITM CA bundle memfd: {err}" + )) + })?; + file.seek(SeekFrom::Start(0)).map_err(|err| { + CodexErr::Fatal(format!( + "failed to rewind managed MITM CA bundle memfd: {err}" + )) + })?; + Ok(file) +} + /// Build the bubblewrap filesystem mounts for a given filesystem policy. /// /// The mount order is important: @@ -1400,8 +1457,8 @@ mod tests { } #[test] - fn default_mitm_ca_trust_bundle_path_is_unset() { - assert_eq!(BwrapOptions::default().mitm_ca_trust_bundle_path, None); + fn default_mitm_ca_cert_path_is_unset() { + assert_eq!(BwrapOptions::default().mitm_ca_cert_path, None); } fn unreadable_glob_entry(pattern: String) -> FileSystemSandboxEntry { @@ -1472,32 +1529,39 @@ mod tests { } #[test] - fn mitm_ca_trust_bundle_overlays_common_linux_bundle_paths() { + fn mitm_ca_cert_appends_to_existing_linux_bundle_paths() { let temp_dir = TempDir::new().expect("tempdir"); - let mitm_ca_trust_bundle_path = temp_dir.path().join("ca-bundle.pem"); - fs::write(&mitm_ca_trust_bundle_path, "managed bundle").expect("write bundle"); + let mitm_ca_cert_path = temp_dir.path().join("ca.pem"); + fs::write(&mitm_ca_cert_path, "managed ca").expect("write managed CA"); + let system_bundle_path = temp_dir.path().join("ca-certificates.crt"); + fs::write(&system_bundle_path, "system bundle").expect("write system bundle"); + let missing_bundle_path = temp_dir.path().join("missing-bundle.crt"); + let mut args = BwrapArgs { + args: Vec::new(), + preserved_files: Vec::new(), + synthetic_mount_targets: Vec::new(), + protected_create_targets: Vec::new(), + }; - let args = create_bwrap_command_args( - vec!["/bin/true".to_string()], - &FileSystemSandboxPolicy::unrestricted(), - Path::new("/"), - Path::new("/"), - BwrapOptions { - mitm_ca_trust_bundle_path: Some(mitm_ca_trust_bundle_path), - ..Default::default() - }, + append_mitm_ca_trust_bundle_args_for_paths( + &mut args, + Some(&mitm_ca_cert_path), + &[&system_bundle_path, &missing_bundle_path], ) - .expect("create bwrap args"); + .expect("append MITM CA trust bundle args"); - assert_eq!(args.preserved_files.len(), LINUX_CA_BUNDLE_PATHS.len()); - for bundle_path in LINUX_CA_BUNDLE_PATHS { - assert!(args.args.windows(5).any(|window| { - window[0] == "--perms" - && window[1] == "444" - && window[2] == "--ro-bind-data" - && window[4] == bundle_path - })); - } + assert_eq!(args.preserved_files.len(), 1); + let system_bundle_path = path_to_string(&system_bundle_path); + assert!(args.args.windows(5).any(|window| { + window[0] == "--perms" + && window[1] == "444" + && window[2] == "--ro-bind-data" + && window[4] == system_bundle_path + })); + let mut overlay_contents = String::new(); + std::io::Read::read_to_string(&mut args.preserved_files[0], &mut overlay_contents) + .expect("read overlay contents"); + assert_eq!(overlay_contents, "system bundle\nmanaged ca\n"); } #[test] diff --git a/codex-rs/linux-sandbox/src/linux_run_main.rs b/codex-rs/linux-sandbox/src/linux_run_main.rs index cf1ba221c8..0cd88a89c1 100644 --- a/codex-rs/linux-sandbox/src/linux_run_main.rs +++ b/codex-rs/linux-sandbox/src/linux_run_main.rs @@ -126,9 +126,9 @@ pub struct LandlockCommand { #[arg(long = "proxy-route-spec", hide = true)] pub proxy_route_spec: Option, - /// Internal managed MITM CA bundle to materialize in bubblewrap sandboxes. - #[arg(long = "mitm-ca-trust-bundle", hide = true)] - pub mitm_ca_trust_bundle_path: Option, + /// Internal managed MITM CA cert to add to bubblewrap trust bundles. + #[arg(long = "mitm-ca-cert", hide = true)] + pub mitm_ca_cert_path: Option, /// When set, skip mounting a fresh `/proc` even though PID isolation is /// still enabled. This is primarily intended for restrictive container @@ -157,7 +157,7 @@ pub fn run_main() -> ! { apply_seccomp_then_exec, allow_network_for_proxy, proxy_route_spec, - mitm_ca_trust_bundle_path, + mitm_ca_cert_path, no_proc, command, } = LandlockCommand::parse(); @@ -204,7 +204,7 @@ pub fn run_main() -> ! { if file_system_sandbox_policy.has_full_disk_write_access() && !allow_network_for_proxy - && mitm_ca_trust_bundle_path.is_none() + && mitm_ca_cert_path.is_none() { if let Err(e) = apply_permission_profile_to_current_thread( &permission_profile, @@ -246,7 +246,7 @@ pub fn run_main() -> ! { inner, !no_proc, allow_network_for_proxy, - mitm_ca_trust_bundle_path.as_deref(), + mitm_ca_cert_path.as_deref(), ); } @@ -331,7 +331,7 @@ fn run_bwrap_with_proc_fallback( inner: Vec, mount_proc: bool, allow_network_for_proxy: bool, - mitm_ca_trust_bundle_path: Option<&Path>, + mitm_ca_cert_path: Option<&Path>, ) -> ! { let network_mode = bwrap_network_mode(network_sandbox_policy, allow_network_for_proxy); let mut mount_proc = mount_proc; @@ -343,7 +343,7 @@ fn run_bwrap_with_proc_fallback( command_cwd, file_system_sandbox_policy, network_mode, - mitm_ca_trust_bundle_path, + mitm_ca_cert_path, ) .unwrap_or_else(|err| exit_with_bwrap_build_error(err)) { @@ -355,7 +355,7 @@ fn run_bwrap_with_proc_fallback( let options = BwrapOptions { mount_proc, network_mode, - mitm_ca_trust_bundle_path: mitm_ca_trust_bundle_path.map(Path::to_path_buf), + mitm_ca_cert_path: mitm_ca_cert_path.map(Path::to_path_buf), ..Default::default() }; let mut bwrap_args = build_bwrap_argv( @@ -458,14 +458,14 @@ fn preflight_proc_mount_support( command_cwd: &Path, file_system_sandbox_policy: &FileSystemSandboxPolicy, network_mode: BwrapNetworkMode, - mitm_ca_trust_bundle_path: Option<&Path>, + mitm_ca_cert_path: Option<&Path>, ) -> CodexResult { let preflight_argv = build_preflight_bwrap_argv( sandbox_policy_cwd, command_cwd, file_system_sandbox_policy, network_mode, - mitm_ca_trust_bundle_path, + mitm_ca_cert_path, )?; let stderr = run_bwrap_in_child_capture_stderr(preflight_argv); Ok(!is_proc_mount_failure(stderr.as_str())) @@ -476,7 +476,7 @@ fn build_preflight_bwrap_argv( command_cwd: &Path, file_system_sandbox_policy: &FileSystemSandboxPolicy, network_mode: BwrapNetworkMode, - mitm_ca_trust_bundle_path: Option<&Path>, + mitm_ca_cert_path: Option<&Path>, ) -> CodexResult { let preflight_command = vec![resolve_true_command()]; build_bwrap_argv( @@ -487,7 +487,7 @@ fn build_preflight_bwrap_argv( BwrapOptions { mount_proc: true, network_mode, - mitm_ca_trust_bundle_path: mitm_ca_trust_bundle_path.map(Path::to_path_buf), + mitm_ca_cert_path: mitm_ca_cert_path.map(Path::to_path_buf), ..Default::default() }, ) diff --git a/codex-rs/network-proxy/README.md b/codex-rs/network-proxy/README.md index cbe64f5dd2..58c8b360de 100644 --- a/codex-rs/network-proxy/README.md +++ b/codex-rs/network-proxy/README.md @@ -37,8 +37,8 @@ mode = "full" # default when unset; use "limited" for read-only mode # CA cert/key are managed internally under $CODEX_HOME/proxy/ (ca.pem + ca.key). # When MITM is active, spawned commands receive CA bundle env vars pointing at # $CODEX_HOME/proxy/ca-bundle.pem so common HTTPS clients trust the managed CA. -# Linux bubblewrap sandboxes also overlay that bundle onto common system CA -# bundle paths inside the sandbox namespace. +# Linux bubblewrap sandboxes also append the managed CA cert to common system +# CA bundle paths inside the sandbox namespace. # If false, local/private networking is rejected. Explicit allowlisting of local IP literals # (or `localhost`) is required to permit them. diff --git a/codex-rs/network-proxy/src/certs.rs b/codex-rs/network-proxy/src/certs.rs index 60502092f5..46366228d0 100644 --- a/codex-rs/network-proxy/src/certs.rs +++ b/codex-rs/network-proxy/src/certs.rs @@ -125,6 +125,10 @@ fn managed_ca_paths() -> Result<(PathBuf, PathBuf)> { )) } +pub(crate) fn managed_ca_cert_path() -> Result { + managed_ca_paths().map(|(cert_path, _)| cert_path) +} + pub(crate) fn managed_ca_trust_bundle_path(env: &HashMap) -> Result { let (cert_path, _) = managed_ca_paths()?; let trust_bundle_path = cert_path diff --git a/codex-rs/network-proxy/src/proxy.rs b/codex-rs/network-proxy/src/proxy.rs index bb49d1f571..04b717fe61 100644 --- a/codex-rs/network-proxy/src/proxy.rs +++ b/codex-rs/network-proxy/src/proxy.rs @@ -301,20 +301,26 @@ struct NetworkProxyRuntimeSettings { allow_local_binding: bool, allow_unix_sockets: Arc<[String]>, dangerously_allow_all_unix_sockets: bool, + mitm_ca_cert_path: Option, mitm_ca_trust_bundle_path: Option, } impl NetworkProxyRuntimeSettings { fn from_config(config: &config::NetworkProxyConfig) -> Result { - let mitm_ca_trust_bundle_path = config - .network - .mitm - .then(|| crate::certs::managed_ca_trust_bundle_path(&std::env::vars().collect())) - .transpose()?; + let (mitm_ca_cert_path, mitm_ca_trust_bundle_path) = if config.network.mitm { + let env = std::env::vars().collect(); + ( + Some(crate::certs::managed_ca_cert_path()?), + Some(crate::certs::managed_ca_trust_bundle_path(&env)?), + ) + } else { + (None, None) + }; Ok(Self { allow_local_binding: config.network.allow_local_binding, allow_unix_sockets: config.network.allow_unix_sockets().into(), dangerously_allow_all_unix_sockets: config.network.dangerously_allow_all_unix_sockets, + mitm_ca_cert_path, mitm_ca_trust_bundle_path, }) } @@ -614,9 +620,9 @@ impl NetworkProxy { self.runtime_settings().dangerously_allow_all_unix_sockets } - /// Returns the managed CA bundle child sandboxes should trust while MITM is active. - pub fn mitm_ca_trust_bundle_path(&self) -> Option { - self.runtime_settings().mitm_ca_trust_bundle_path + /// Returns the managed CA cert child sandboxes should add to native trust paths. + pub fn mitm_ca_cert_path(&self) -> Option { + self.runtime_settings().mitm_ca_cert_path } pub fn apply_to_env(&self, env: &mut HashMap) { diff --git a/codex-rs/sandboxing/src/landlock.rs b/codex-rs/sandboxing/src/landlock.rs index 518af85ac4..934c4b0d0c 100644 --- a/codex-rs/sandboxing/src/landlock.rs +++ b/codex-rs/sandboxing/src/landlock.rs @@ -27,7 +27,7 @@ pub fn create_linux_sandbox_command_args_for_permission_profile( sandbox_policy_cwd: &Path, use_legacy_landlock: bool, allow_network_for_proxy: bool, - mitm_ca_trust_bundle_path: Option<&Path>, + mitm_ca_cert_path: Option<&Path>, ) -> Vec { let permission_profile_json = serde_json::to_string(permission_profile) .unwrap_or_else(|err| panic!("failed to serialize permission profile: {err}")); @@ -54,12 +54,12 @@ pub fn create_linux_sandbox_command_args_for_permission_profile( if allow_network_for_proxy { linux_cmd.push("--allow-network-for-proxy".to_string()); } - if let Some(mitm_ca_trust_bundle_path) = mitm_ca_trust_bundle_path { - linux_cmd.push("--mitm-ca-trust-bundle".to_string()); + if let Some(mitm_ca_cert_path) = mitm_ca_cert_path { + linux_cmd.push("--mitm-ca-cert".to_string()); linux_cmd.push( - mitm_ca_trust_bundle_path + mitm_ca_cert_path .to_str() - .unwrap_or_else(|| panic!("MITM CA trust bundle path must be valid UTF-8")) + .unwrap_or_else(|| panic!("MITM CA cert path must be valid UTF-8")) .to_string(), ); } @@ -77,7 +77,7 @@ fn create_linux_sandbox_command_args( sandbox_policy_cwd: &Path, use_legacy_landlock: bool, allow_network_for_proxy: bool, - mitm_ca_trust_bundle_path: Option<&Path>, + mitm_ca_cert_path: Option<&Path>, ) -> Vec { let command_cwd = command_cwd .to_str() @@ -100,12 +100,12 @@ fn create_linux_sandbox_command_args( if allow_network_for_proxy { linux_cmd.push("--allow-network-for-proxy".to_string()); } - if let Some(mitm_ca_trust_bundle_path) = mitm_ca_trust_bundle_path { - linux_cmd.push("--mitm-ca-trust-bundle".to_string()); + if let Some(mitm_ca_cert_path) = mitm_ca_cert_path { + linux_cmd.push("--mitm-ca-cert".to_string()); linux_cmd.push( - mitm_ca_trust_bundle_path + mitm_ca_cert_path .to_str() - .unwrap_or_else(|| panic!("MITM CA trust bundle path must be valid UTF-8")) + .unwrap_or_else(|| panic!("MITM CA cert path must be valid UTF-8")) .to_string(), ); } diff --git a/codex-rs/sandboxing/src/landlock_tests.rs b/codex-rs/sandboxing/src/landlock_tests.rs index 053bdd6e18..b9bc697a4d 100644 --- a/codex-rs/sandboxing/src/landlock_tests.rs +++ b/codex-rs/sandboxing/src/landlock_tests.rs @@ -13,7 +13,7 @@ fn legacy_landlock_flag_is_included_when_requested() { cwd, /*use_legacy_landlock*/ false, /*allow_network_for_proxy*/ false, - /*mitm_ca_trust_bundle_path*/ None, + /*mitm_ca_cert_path*/ None, ); assert_eq!( default_bwrap.contains(&"--use-legacy-landlock".to_string()), @@ -26,7 +26,7 @@ fn legacy_landlock_flag_is_included_when_requested() { cwd, /*use_legacy_landlock*/ true, /*allow_network_for_proxy*/ false, - /*mitm_ca_trust_bundle_path*/ None, + /*mitm_ca_cert_path*/ None, ); assert_eq!( legacy_landlock.contains(&"--use-legacy-landlock".to_string()), @@ -46,7 +46,7 @@ fn proxy_flag_is_included_when_requested() { cwd, /*use_legacy_landlock*/ true, /*allow_network_for_proxy*/ true, - /*mitm_ca_trust_bundle_path*/ None, + /*mitm_ca_cert_path*/ None, ); assert_eq!( args.contains(&"--allow-network-for-proxy".to_string()), @@ -68,7 +68,7 @@ fn permission_profile_flag_is_included() { cwd, /*use_legacy_landlock*/ true, /*allow_network_for_proxy*/ false, - /*mitm_ca_trust_bundle_path*/ None, + /*mitm_ca_cert_path*/ None, ); assert_eq!( @@ -84,11 +84,11 @@ fn permission_profile_flag_is_included() { } #[test] -fn mitm_ca_trust_bundle_flag_is_included_when_requested() { +fn mitm_ca_cert_flag_is_included_when_requested() { let command = vec!["/bin/true".to_string()]; let command_cwd = Path::new("/tmp/link"); let cwd = Path::new("/tmp"); - let trust_bundle_path = Path::new("/tmp/ca-bundle.pem"); + let cert_path = Path::new("/tmp/ca.pem"); let args = create_linux_sandbox_command_args( command, @@ -96,12 +96,13 @@ fn mitm_ca_trust_bundle_flag_is_included_when_requested() { cwd, /*use_legacy_landlock*/ false, /*allow_network_for_proxy*/ true, - Some(trust_bundle_path), + Some(cert_path), ); - assert!(args.windows(2).any(|window| { - window[0] == "--mitm-ca-trust-bundle" && window[1] == "/tmp/ca-bundle.pem" - })); + assert!( + args.windows(2) + .any(|window| { window[0] == "--mitm-ca-cert" && window[1] == "/tmp/ca.pem" }) + ); } #[test] diff --git a/codex-rs/sandboxing/src/manager.rs b/codex-rs/sandboxing/src/manager.rs index 8a0749ca7f..ffc775dcb6 100644 --- a/codex-rs/sandboxing/src/manager.rs +++ b/codex-rs/sandboxing/src/manager.rs @@ -218,8 +218,7 @@ impl SandboxManager { let exe = codex_linux_sandbox_exe .ok_or(SandboxTransformError::MissingLinuxSandboxExecutable)?; let allow_proxy_network = allow_network_for_proxy(enforce_managed_network); - let mitm_ca_trust_bundle_path = - network.and_then(NetworkProxy::mitm_ca_trust_bundle_path); + let mitm_ca_cert_path = network.and_then(NetworkProxy::mitm_ca_cert_path); #[cfg(target_os = "linux")] ensure_linux_bubblewrap_is_supported( &effective_file_system_policy, @@ -234,7 +233,7 @@ impl SandboxManager { sandbox_policy_cwd, use_legacy_landlock, allow_proxy_network, - mitm_ca_trust_bundle_path.as_deref(), + mitm_ca_cert_path.as_deref(), ); let mut full_command = Vec::with_capacity(1 + args.len()); full_command.push(os_string_to_command_component(exe.as_os_str().to_owned()));