From 531ce7626ff76414f8c5ed0eff7e18137921b5fc Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 24 Jun 2025 17:48:51 -0700 Subject: [PATCH] fix: pretty-print the sandbox config in the TUI/exec modes (#1376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that https://github.com/openai/codex/pull/1373 simplified the sandbox config, we can print something much simpler in the TUI (and in `codex exec`) to summarize the sandbox config. Before: ![Screenshot 2025-06-24 at 5 45 52 PM](https://github.com/user-attachments/assets/b7633efb-a619-43e1-9abe-7bb0be2d0ec0) With this change: ![Screenshot 2025-06-24 at 5 46 44 PM](https://github.com/user-attachments/assets/8d099bdd-a429-4796-a08d-70931d984e4f) For reference, my `config.toml` contains: ``` [sandbox] mode = "workspace-write" writable_roots = ["/tmp", "/Users/mbolin/.pyenv/shims"] ``` Fixes https://github.com/openai/codex/issues/1248 --- codex-rs/common/Cargo.toml | 1 + codex-rs/common/src/lib.rs | 5 +++++ codex-rs/common/src/sandbox_summary.rs | 28 ++++++++++++++++++++++++++ codex-rs/core/src/protocol.rs | 22 +++++++++++--------- codex-rs/exec/Cargo.toml | 6 +++++- codex-rs/exec/src/event_processor.rs | 3 ++- codex-rs/tui/Cargo.toml | 6 +++++- codex-rs/tui/src/history_cell.rs | 3 ++- 8 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 codex-rs/common/src/sandbox_summary.rs diff --git a/codex-rs/common/Cargo.toml b/codex-rs/common/Cargo.toml index b4b658da..eff7a6c0 100644 --- a/codex-rs/common/Cargo.toml +++ b/codex-rs/common/Cargo.toml @@ -16,3 +16,4 @@ serde = { version = "1", optional = true } # Separate feature so that `clap` is not a mandatory dependency. cli = ["clap", "toml", "serde"] elapsed = [] +sandbox_summary = [] diff --git a/codex-rs/common/src/lib.rs b/codex-rs/common/src/lib.rs index 074f648f..18ed49e5 100644 --- a/codex-rs/common/src/lib.rs +++ b/codex-rs/common/src/lib.rs @@ -12,3 +12,8 @@ mod config_override; #[cfg(feature = "cli")] pub use config_override::CliConfigOverrides; + +mod sandbox_summary; + +#[cfg(feature = "sandbox_summary")] +pub use sandbox_summary::summarize_sandbox_policy; diff --git a/codex-rs/common/src/sandbox_summary.rs b/codex-rs/common/src/sandbox_summary.rs new file mode 100644 index 00000000..3d33d928 --- /dev/null +++ b/codex-rs/common/src/sandbox_summary.rs @@ -0,0 +1,28 @@ +use codex_core::protocol::SandboxPolicy; + +pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String { + match sandbox_policy { + SandboxPolicy::DangerFullAccess => "danger-full-access".to_string(), + SandboxPolicy::ReadOnly => "read-only".to_string(), + SandboxPolicy::WorkspaceWrite { + writable_roots, + network_access, + } => { + let mut summary = "workspace-write".to_string(); + if !writable_roots.is_empty() { + summary.push_str(&format!( + " [{}]", + writable_roots + .iter() + .map(|p| p.to_string_lossy()) + .collect::>() + .join(", ") + )); + } + if *network_access { + summary.push_str(" (network access enabled)"); + } + summary + } + } +} diff --git a/codex-rs/core/src/protocol.rs b/codex-rs/core/src/protocol.rs index f3250de4..42cf9299 100644 --- a/codex-rs/core/src/protocol.rs +++ b/codex-rs/core/src/protocol.rs @@ -183,17 +183,8 @@ impl SandboxPolicy { /// the current working directory and the per-user tmp dir on macOS. It does /// not allow network access. pub fn new_workspace_write_policy() -> Self { - let mut writable_roots = vec![]; - - // Also include the per-user tmp dir on macOS. - if cfg!(target_os = "macos") { - if let Some(tmpdir) = std::env::var_os("TMPDIR") { - writable_roots.push(PathBuf::from(tmpdir)); - } - } - SandboxPolicy::WorkspaceWrite { - writable_roots, + writable_roots: vec![], network_access: false, } } @@ -229,6 +220,17 @@ impl SandboxPolicy { SandboxPolicy::WorkspaceWrite { writable_roots, .. } => { let mut roots = writable_roots.clone(); roots.push(cwd.to_path_buf()); + + // Also include the per-user tmp dir on macOS. + // Note this is added dynamically rather than storing it in + // writable_roots because writable_roots contains only static + // values deserialized from the config file. + if cfg!(target_os = "macos") { + if let Some(tmpdir) = std::env::var_os("TMPDIR") { + roots.push(PathBuf::from(tmpdir)); + } + } + roots } } diff --git a/codex-rs/exec/Cargo.toml b/codex-rs/exec/Cargo.toml index c3bde697..8c0c3737 100644 --- a/codex-rs/exec/Cargo.toml +++ b/codex-rs/exec/Cargo.toml @@ -19,7 +19,11 @@ anyhow = "1" chrono = "0.4.40" clap = { version = "4", features = ["derive"] } codex-core = { path = "../core" } -codex-common = { path = "../common", features = ["cli", "elapsed"] } +codex-common = { path = "../common", features = [ + "cli", + "elapsed", + "sandbox_summary", +] } codex-linux-sandbox = { path = "../linux-sandbox" } mcp-types = { path = "../mcp-types" } owo-colors = "4.2.0" diff --git a/codex-rs/exec/src/event_processor.rs b/codex-rs/exec/src/event_processor.rs index 4cbbd25f..e2a8bbb2 100644 --- a/codex-rs/exec/src/event_processor.rs +++ b/codex-rs/exec/src/event_processor.rs @@ -1,4 +1,5 @@ use codex_common::elapsed::format_elapsed; +use codex_common::summarize_sandbox_policy; use codex_core::WireApi; use codex_core::config::Config; use codex_core::model_supports_reasoning_summaries; @@ -134,7 +135,7 @@ impl EventProcessor { ("model", config.model.clone()), ("provider", config.model_provider_id.clone()), ("approval", format!("{:?}", config.approval_policy)), - ("sandbox", format!("{:?}", config.sandbox_policy)), + ("sandbox", summarize_sandbox_policy(&config.sandbox_policy)), ]; if config.model_provider.wire_api == WireApi::Responses && model_supports_reasoning_summaries(&config.model) diff --git a/codex-rs/tui/Cargo.toml b/codex-rs/tui/Cargo.toml index 2d7840e6..0891517d 100644 --- a/codex-rs/tui/Cargo.toml +++ b/codex-rs/tui/Cargo.toml @@ -20,7 +20,11 @@ base64 = "0.22.1" clap = { version = "4", features = ["derive"] } codex-ansi-escape = { path = "../ansi-escape" } codex-core = { path = "../core" } -codex-common = { path = "../common", features = ["cli", "elapsed"] } +codex-common = { path = "../common", features = [ + "cli", + "elapsed", + "sandbox_summary", +] } codex-linux-sandbox = { path = "../linux-sandbox" } codex-login = { path = "../login" } color-eyre = "0.6.3" diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index 481576b5..e2a54283 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -6,6 +6,7 @@ use crate::text_formatting::format_and_truncate_tool_result; use base64::Engine; use codex_ansi_escape::ansi_escape_line; use codex_common::elapsed::format_duration; +use codex_common::summarize_sandbox_policy; use codex_core::WireApi; use codex_core::config::Config; use codex_core::model_supports_reasoning_summaries; @@ -152,7 +153,7 @@ impl HistoryCell { ("model", config.model.clone()), ("provider", config.model_provider_id.clone()), ("approval", format!("{:?}", config.approval_policy)), - ("sandbox", format!("{:?}", config.sandbox_policy)), + ("sandbox", summarize_sandbox_policy(&config.sandbox_policy)), ]; if config.model_provider.wire_api == WireApi::Responses && model_supports_reasoning_summaries(&config.model)