diff --git a/codex-rs/common/src/sandbox_summary.rs b/codex-rs/common/src/sandbox_summary.rs index 3d33d928..e0e309a9 100644 --- a/codex-rs/common/src/sandbox_summary.rs +++ b/codex-rs/common/src/sandbox_summary.rs @@ -7,6 +7,7 @@ pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String { SandboxPolicy::WorkspaceWrite { writable_roots, network_access, + include_default_writable_roots, } => { let mut summary = "workspace-write".to_string(); if !writable_roots.is_empty() { @@ -19,6 +20,9 @@ pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String { .join(", ") )); } + if !*include_default_writable_roots { + summary.push_str(" (exact writable roots)"); + } if *network_access { summary.push_str(" (network access enabled)"); } diff --git a/codex-rs/core/src/config.rs b/codex-rs/core/src/config.rs index 1b8da894..87629d82 100644 --- a/codex-rs/core/src/config.rs +++ b/codex-rs/core/src/config.rs @@ -356,6 +356,7 @@ impl ConfigToml { Some(s) => SandboxPolicy::WorkspaceWrite { writable_roots: s.writable_roots.clone(), network_access: s.network_access, + include_default_writable_roots: true, }, None => SandboxPolicy::new_workspace_write_policy(), }, @@ -727,6 +728,7 @@ writable_roots = [ SandboxPolicy::WorkspaceWrite { writable_roots: vec![PathBuf::from("/tmp")], network_access: false, + include_default_writable_roots: true, }, sandbox_workspace_write_cfg.derive_sandbox_policy(sandbox_mode_override) ); diff --git a/codex-rs/core/src/protocol.rs b/codex-rs/core/src/protocol.rs index 3be0c92c..af65f4d3 100644 --- a/codex-rs/core/src/protocol.rs +++ b/codex-rs/core/src/protocol.rs @@ -180,9 +180,19 @@ pub enum SandboxPolicy { /// default. #[serde(default)] network_access: bool, + + /// When set to `true`, will include defaults like the current working + /// directory and TMPDIR (on macOS). When `false`, only `writable_roots` + /// are used. (Mainly used for testing.) + #[serde(default = "default_true")] + include_default_writable_roots: bool, }, } +fn default_true() -> bool { + true +} + impl FromStr for SandboxPolicy { type Err = serde_json::Error; @@ -204,6 +214,7 @@ impl SandboxPolicy { SandboxPolicy::WorkspaceWrite { writable_roots: vec![], network_access: false, + include_default_writable_roots: true, } } @@ -235,7 +246,15 @@ impl SandboxPolicy { match self { SandboxPolicy::DangerFullAccess => Vec::new(), SandboxPolicy::ReadOnly => Vec::new(), - SandboxPolicy::WorkspaceWrite { writable_roots, .. } => { + SandboxPolicy::WorkspaceWrite { + writable_roots, + include_default_writable_roots, + .. + } => { + if !*include_default_writable_roots { + return writable_roots.clone(); + } + let mut roots = writable_roots.clone(); roots.push(cwd.to_path_buf()); diff --git a/codex-rs/linux-sandbox/tests/landlock.rs b/codex-rs/linux-sandbox/tests/landlock.rs index c16e9227..1375a4c6 100644 --- a/codex-rs/linux-sandbox/tests/landlock.rs +++ b/codex-rs/linux-sandbox/tests/landlock.rs @@ -49,6 +49,7 @@ async fn run_cmd(cmd: &[&str], writable_roots: &[PathBuf], timeout_ms: u64) { let sandbox_policy = SandboxPolicy::WorkspaceWrite { writable_roots: writable_roots.to_vec(), network_access: false, + include_default_writable_roots: true, }; let sandbox_program = env!("CARGO_BIN_EXE_codex-linux-sandbox"); let codex_linux_sandbox_exe = Some(PathBuf::from(sandbox_program));