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)