From 402db13d17856a01f3a080ef152df2002a67a81a Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Mon, 8 Dec 2025 17:36:04 -0800 Subject: [PATCH] fix: more std::env::vars -> std::env::vars_os fixes --- codex-rs/core/src/exec.rs | 8 ++++++-- codex-rs/core/src/exec_env.rs | 6 +++++- codex-rs/core/tests/suite/seatbelt.rs | 4 +++- codex-rs/exec-server/src/posix/escalate_client.rs | 14 +++++++++----- codex-rs/exec-server/src/posix/escalate_server.rs | 4 +++- codex-rs/rmcp-client/src/bin/rmcp_test_server.rs | 6 +++++- codex-rs/rmcp-client/src/bin/test_stdio_server.rs | 6 +++++- .../src/bin/test_streamable_http_server.rs | 6 +++++- codex-rs/tui/src/app.rs | 12 +++++++++--- codex-rs/tui/src/chatwidget.rs | 9 ++++++++- 10 files changed, 58 insertions(+), 17 deletions(-) diff --git a/codex-rs/core/src/exec.rs b/codex-rs/core/src/exec.rs index ba1ac43004..5b70e260f0 100644 --- a/codex-rs/core/src/exec.rs +++ b/codex-rs/core/src/exec.rs @@ -851,7 +851,9 @@ mod tests { "-c".to_string(), "sleep 60 & echo $!; sleep 60".to_string(), ]; - let env: HashMap = std::env::vars().collect(); + let env: HashMap = std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))) + .collect(); let params = ExecParams { command, cwd: std::env::current_dir()?, @@ -894,7 +896,9 @@ mod tests { async fn process_exec_tool_call_respects_cancellation_token() -> Result<()> { let command = long_running_command(); let cwd = std::env::current_dir()?; - let env: HashMap = std::env::vars().collect(); + let env: HashMap = std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))) + .collect(); let cancel_token = CancellationToken::new(); let cancel_tx = cancel_token.clone(); let params = ExecParams { diff --git a/codex-rs/core/src/exec_env.rs b/codex-rs/core/src/exec_env.rs index 11334896bf..4432b6c817 100644 --- a/codex-rs/core/src/exec_env.rs +++ b/codex-rs/core/src/exec_env.rs @@ -12,7 +12,11 @@ use std::collections::HashSet; /// The derivation follows the algorithm documented in the struct-level comment /// for [`ShellEnvironmentPolicy`]. pub fn create_env(policy: &ShellEnvironmentPolicy) -> HashMap { - populate_env(std::env::vars(), policy) + populate_env( + std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))), + policy, + ) } fn populate_env(vars: I, policy: &ShellEnvironmentPolicy) -> HashMap diff --git a/codex-rs/core/tests/suite/seatbelt.rs b/codex-rs/core/tests/suite/seatbelt.rs index 52150b0511..3ff7f86c2a 100644 --- a/codex-rs/core/tests/suite/seatbelt.rs +++ b/codex-rs/core/tests/suite/seatbelt.rs @@ -232,7 +232,9 @@ async fn java_home_finds_runtime_under_seatbelt() { let command_cwd = std::env::current_dir().expect("getcwd"); let sandbox_cwd = command_cwd.clone(); - let mut env: HashMap = std::env::vars().collect(); + let mut env: HashMap = std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))) + .collect(); env.remove("JAVA_HOME"); env.remove(CODEX_SANDBOX_ENV_VAR); diff --git a/codex-rs/exec-server/src/posix/escalate_client.rs b/codex-rs/exec-server/src/posix/escalate_client.rs index bea4b6fa5f..8258a86f4f 100644 --- a/codex-rs/exec-server/src/posix/escalate_client.rs +++ b/codex-rs/exec-server/src/posix/escalate_client.rs @@ -34,12 +34,16 @@ pub(crate) async fn run(file: String, argv: Vec) -> anyhow::Result .send_with_fds(&HANDSHAKE_MESSAGE, &[server.into_inner().into()]) .await .context("failed to send handshake datagram")?; - let env = std::env::vars() - .filter(|(k, _)| { - !matches!( - k.as_str(), + let env = std::env::vars_os() + .filter_map(|(key, value)| { + let key = key.into_string().ok()?; + if matches!( + key.as_str(), ESCALATE_SOCKET_ENV_VAR | BASH_EXEC_WRAPPER_ENV_VAR - ) + ) { + return None; + } + Some((key, value.into_string().ok()?)) }) .collect(); client diff --git a/codex-rs/exec-server/src/posix/escalate_server.rs b/codex-rs/exec-server/src/posix/escalate_server.rs index 72934607a3..e719370228 100644 --- a/codex-rs/exec-server/src/posix/escalate_server.rs +++ b/codex-rs/exec-server/src/posix/escalate_server.rs @@ -55,7 +55,9 @@ impl EscalateServer { client_socket.set_cloexec(false)?; let escalate_task = tokio::spawn(escalate_task(escalate_server, self.policy.clone())); - let mut env = std::env::vars().collect::>(); + let mut env = std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))) + .collect::>(); env.insert( ESCALATE_SOCKET_ENV_VAR.to_string(), client_socket.as_raw_fd().to_string(), diff --git a/codex-rs/rmcp-client/src/bin/rmcp_test_server.rs b/codex-rs/rmcp-client/src/bin/rmcp_test_server.rs index 23b2f93b38..0ab7fdbea3 100644 --- a/codex-rs/rmcp-client/src/bin/rmcp_test_server.rs +++ b/codex-rs/rmcp-client/src/bin/rmcp_test_server.rs @@ -105,7 +105,11 @@ impl ServerHandler for TestToolServer { } }; - let env_snapshot: HashMap = std::env::vars().collect(); + let env_snapshot: HashMap = std::env::vars_os() + .filter_map(|(key, val)| { + Some((key.into_string().ok()?, val.into_string().ok()?)) + }) + .collect(); let structured_content = json!({ "echo": args.message, "env": env_snapshot.get("MCP_TEST_VALUE"), diff --git a/codex-rs/rmcp-client/src/bin/test_stdio_server.rs b/codex-rs/rmcp-client/src/bin/test_stdio_server.rs index aafba59324..1d50e429bf 100644 --- a/codex-rs/rmcp-client/src/bin/test_stdio_server.rs +++ b/codex-rs/rmcp-client/src/bin/test_stdio_server.rs @@ -217,7 +217,11 @@ impl ServerHandler for TestToolServer { } }; - let env_snapshot: HashMap = std::env::vars().collect(); + let env_snapshot: HashMap = std::env::vars_os() + .filter_map(|(key, val)| { + Some((key.into_string().ok()?, val.into_string().ok()?)) + }) + .collect(); let structured_content = json!({ "echo": format!("ECHOING: {}", args.message), "env": env_snapshot.get("MCP_TEST_VALUE"), diff --git a/codex-rs/rmcp-client/src/bin/test_streamable_http_server.rs b/codex-rs/rmcp-client/src/bin/test_streamable_http_server.rs index f56a858241..4f7e6d6ac2 100644 --- a/codex-rs/rmcp-client/src/bin/test_streamable_http_server.rs +++ b/codex-rs/rmcp-client/src/bin/test_streamable_http_server.rs @@ -214,7 +214,11 @@ impl ServerHandler for TestToolServer { } }; - let env_snapshot: HashMap = std::env::vars().collect(); + let env_snapshot: HashMap = std::env::vars_os() + .filter_map(|(key, val)| { + Some((key.into_string().ok()?, val.into_string().ok()?)) + }) + .collect(); let structured_content = json!({ "echo": format!("ECHOING: {}", args.message), "env": env_snapshot.get("MCP_TEST_VALUE"), diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 0a09b15e7c..25f40fadf5 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -401,7 +401,7 @@ impl App { .unwrap_or(false); if should_check { let cwd = app.config.cwd.clone(); - let env_map: std::collections::HashMap = std::env::vars().collect(); + let env_map = collect_string_env_map(); let tx = app.app_event_tx.clone(); let logs_base_dir = app.config.codex_home.clone(); let sandbox_policy = app.config.sandbox_policy.clone(); @@ -864,8 +864,7 @@ impl App { && !self.chat_widget.world_writable_warning_hidden(); if should_check { let cwd = self.config.cwd.clone(); - let env_map: std::collections::HashMap = - std::env::vars().collect(); + let env_map = collect_string_env_map(); let tx = self.app_event_tx.clone(); let logs_base_dir = self.config.codex_home.clone(); let sandbox_policy = self.config.sandbox_policy.clone(); @@ -1117,6 +1116,13 @@ impl App { } } +#[cfg(target_os = "windows")] +fn collect_string_env_map() -> std::collections::HashMap { + std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))) + .collect() +} + fn migration_prompt_allowed_auth_modes(migration_config_key: &str) -> Option<&'static [AuthMode]> { match migration_config_key { HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG => Some(&GPT_5_1_MIGRATION_AUTH_MODES), diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index a0b42ddbe4..9dec5b66ff 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -2647,7 +2647,7 @@ impl ChatWidget { return None; } let cwd = self.config.cwd.clone(); - let env_map: std::collections::HashMap = std::env::vars().collect(); + let env_map = collect_string_env_map(); match codex_windows_sandbox::apply_world_writable_scan_and_denies( self.config.codex_home.as_path(), cwd.as_path(), @@ -3450,5 +3450,12 @@ pub(crate) fn show_review_commit_picker_with_entries( }); } +#[cfg(target_os = "windows")] +fn collect_string_env_map() -> std::collections::HashMap { + std::env::vars_os() + .filter_map(|(key, value)| Some((key.into_string().ok()?, value.into_string().ok()?))) + .collect() +} + #[cfg(test)] pub(crate) mod tests;