From 1100b98f5ba3e0a7c392449e622bee01edd986da Mon Sep 17 00:00:00 2001 From: Winston Howes Date: Tue, 16 Jun 2026 14:54:15 -0700 Subject: [PATCH 1/4] Allow staged child CA helpers before launch wiring --- codex-rs/network-proxy/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codex-rs/network-proxy/src/lib.rs b/codex-rs/network-proxy/src/lib.rs index 440831d42c..229ccb81b6 100644 --- a/codex-rs/network-proxy/src/lib.rs +++ b/codex-rs/network-proxy/src/lib.rs @@ -1,6 +1,9 @@ #![deny(clippy::print_stdout, clippy::print_stderr)] +// These helpers are wired into command launches by the next layer of the MITM stack. +#[allow(dead_code)] mod certs; +#[allow(dead_code)] mod child_ca; mod config; mod connect_policy; From bf6697fab065ac85cff7dbd714d10c09c0d5fc91 Mon Sep 17 00:00:00 2001 From: Winston Howes Date: Tue, 16 Jun 2026 14:57:10 -0700 Subject: [PATCH 2/4] Keep CA helper stage within review limit --- codex-rs/network-proxy/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codex-rs/network-proxy/src/lib.rs b/codex-rs/network-proxy/src/lib.rs index 229ccb81b6..2aded28034 100644 --- a/codex-rs/network-proxy/src/lib.rs +++ b/codex-rs/network-proxy/src/lib.rs @@ -1,9 +1,7 @@ #![deny(clippy::print_stdout, clippy::print_stderr)] +#![allow(dead_code)] -// These helpers are wired into command launches by the next layer of the MITM stack. -#[allow(dead_code)] mod certs; -#[allow(dead_code)] mod child_ca; mod config; mod connect_policy; From 786049098c1d7b1388621d682c334be513215f0c Mon Sep 17 00:00:00 2001 From: Winston Howes Date: Tue, 16 Jun 2026 15:03:01 -0700 Subject: [PATCH 3/4] Preserve and propagate child CA directories --- codex-rs/network-proxy/src/child_ca.rs | 9 +++---- codex-rs/network-proxy/src/child_ca_tests.rs | 27 +++++++++----------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/codex-rs/network-proxy/src/child_ca.rs b/codex-rs/network-proxy/src/child_ca.rs index c0f4e267c3..be80e17f5c 100644 --- a/codex-rs/network-proxy/src/child_ca.rs +++ b/codex-rs/network-proxy/src/child_ca.rs @@ -21,9 +21,9 @@ where startup_ca_env_keys_present_in_child, &can_read_path, ); - // Fold SSL_CERT_DIR into SSL_CERT_FILE so children cannot consult an - // unmaterialized CA directory after preparation. - env.remove(crate::certs::SSL_CERT_DIR_ENV_KEY); + if ssl_cert_dir_contents.is_some() { + env.remove(crate::certs::SSL_CERT_DIR_ENV_KEY); + } let mut materialized_ca_trust_bundle_paths = Vec::new(); for key in crate::certs::CUSTOM_CA_ENV_KEYS { let Some(value) = env.get(key).filter(|value| !value.is_empty()) else { @@ -38,8 +38,7 @@ where &can_read_path, ) .unwrap_or_default(); - if key == "SSL_CERT_FILE" - && let Some(ssl_cert_dir_contents) = ssl_cert_dir_contents.as_deref() + if let Some(ssl_cert_dir_contents) = ssl_cert_dir_contents.as_deref() && let Err(err) = crate::certs::append_bounded_pem_contents( &mut custom_ca_bundle, ssl_cert_dir_contents, diff --git a/codex-rs/network-proxy/src/child_ca_tests.rs b/codex-rs/network-proxy/src/child_ca_tests.rs index 685d674e07..070720e149 100644 --- a/codex-rs/network-proxy/src/child_ca_tests.rs +++ b/codex-rs/network-proxy/src/child_ca_tests.rs @@ -1,7 +1,6 @@ use super::*; use pretty_assertions::assert_eq; use std::fs; -use std::path::Path; use tempfile::tempdir; const REQUESTS_CA_BUNDLE_ENV_KEY: &str = "REQUESTS_CA_BUNDLE"; @@ -24,11 +23,7 @@ fn requests_ca_bundle_env(value: impl Into) -> HashMap { } fn requests_ca_bundle_contents(env: &HashMap) -> String { - fs::read_to_string(Path::new( - env.get(REQUESTS_CA_BUNDLE_ENV_KEY) - .expect("REQUESTS_CA_BUNDLE should be set"), - )) - .unwrap() + fs::read_to_string(&env[REQUESTS_CA_BUNDLE_ENV_KEY]).unwrap() } fn ssl_cert_dir_env( @@ -50,6 +45,10 @@ fn ssl_cert_dir_env( "SSL_CERT_FILE".to_string(), mitm_ca_trust_bundle_path.display().to_string(), ), + ( + REQUESTS_CA_BUNDLE_ENV_KEY.to_string(), + mitm_ca_trust_bundle_path.display().to_string(), + ), ( crate::certs::SSL_CERT_DIR_ENV_KEY.to_string(), ssl_cert_dir.clone(), @@ -105,14 +104,12 @@ fn materializes_readable_ssl_cert_dir() { |_| true, ); - let ssl_cert_file_path = Path::new( - env.get("SSL_CERT_FILE") - .expect("SSL_CERT_FILE should be set"), - ); - assert_eq!( - fs::read_to_string(ssl_cert_file_path).unwrap(), - "dir ca a\ndir ca b\nmanaged ca\n" - ); + for key in ["SSL_CERT_FILE", REQUESTS_CA_BUNDLE_ENV_KEY] { + assert_eq!( + fs::read_to_string(&env[key]).unwrap(), + "dir ca a\ndir ca b\nmanaged ca\n" + ); + } assert_eq!(env.get(crate::certs::SSL_CERT_DIR_ENV_KEY), None); } @@ -137,7 +134,7 @@ fn bounds_aggregate_ssl_cert_dir_contents() { env.get("SSL_CERT_FILE"), Some(&mitm_ca_trust_bundle.path.display().to_string()) ); - assert_eq!(env.get(crate::certs::SSL_CERT_DIR_ENV_KEY), None); + assert!(env.contains_key(crate::certs::SSL_CERT_DIR_ENV_KEY)); } #[test] From 84088bc3861f3b4a364925090837c9c4d47d704f Mon Sep 17 00:00:00 2001 From: Winston Howes Date: Tue, 16 Jun 2026 15:18:18 -0700 Subject: [PATCH 4/4] Fix CA directory handling and hermetic proxy tests --- codex-rs/network-proxy/src/child_ca.rs | 6 +----- codex-rs/network-proxy/src/child_ca_tests.rs | 1 - codex-rs/network-proxy/src/http_proxy.rs | 9 +++++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/codex-rs/network-proxy/src/child_ca.rs b/codex-rs/network-proxy/src/child_ca.rs index be80e17f5c..8f245fbcef 100644 --- a/codex-rs/network-proxy/src/child_ca.rs +++ b/codex-rs/network-proxy/src/child_ca.rs @@ -168,11 +168,7 @@ where } } } - if trust_bundle.is_empty() { - None - } else { - Some(trust_bundle) - } + (!trust_bundle.is_empty()).then_some(trust_bundle) } fn managed_mitm_ca_trust_bundle_paths_for_env( diff --git a/codex-rs/network-proxy/src/child_ca_tests.rs b/codex-rs/network-proxy/src/child_ca_tests.rs index 070720e149..719c9cb5a9 100644 --- a/codex-rs/network-proxy/src/child_ca_tests.rs +++ b/codex-rs/network-proxy/src/child_ca_tests.rs @@ -74,7 +74,6 @@ fn materializes_readable_startup_ca_override() { HashMap::from([(REQUESTS_CA_BUNDLE_ENV_KEY, "startup-ca.pem".to_string())]), ); let mut env = requests_ca_bundle_env("startup-ca.pem"); - let bundle_paths = prepare_mitm_ca_trust_bundle_env( &mitm_ca_trust_bundle, &mut env, diff --git a/codex-rs/network-proxy/src/http_proxy.rs b/codex-rs/network-proxy/src/http_proxy.rs index f20c01b906..9595ea5eee 100644 --- a/codex-rs/network-proxy/src/http_proxy.rs +++ b/codex-rs/network-proxy/src/http_proxy.rs @@ -1058,11 +1058,11 @@ mod tests { #[tokio::test] async fn http_connect_accept_blocks_in_limited_mode() { - let policy = { - let mut policy = NetworkProxySettings::default(); - policy.set_allowed_domains(vec!["example.com".to_string()]); - policy + let mut policy = NetworkProxySettings { + allow_local_binding: true, + ..NetworkProxySettings::default() }; + policy.set_allowed_domains(vec!["example.com".to_string()]); let state = Arc::new(network_proxy_state_for_policy(policy)); state.set_network_mode(NetworkMode::Limited).await.unwrap(); @@ -1113,6 +1113,7 @@ mod tests { #[tokio::test] async fn http_connect_accept_blocks_hooked_host_in_full_mode_without_mitm_state() { let mut policy = NetworkProxySettings { + allow_local_binding: true, mitm: true, mitm_hooks: vec![crate::mitm_hook::MitmHookConfig { host: "api.github.com".to_string(),