feat(sandbox): add workspace-write opt-in (default false); enable .git writes in CI via config override

This commit is contained in:
James Peter
2025-09-06 22:15:17 +10:00
parent 274dcaef3e
commit 3df630f9ec
6 changed files with 43 additions and 6 deletions
+9
View File
@@ -92,6 +92,15 @@ codex --sandbox danger-full-access
The same setting can be persisted in `~/.codex/config.toml` via the top-level `sandbox_mode = "MODE"` key, e.g. `sandbox_mode = "workspace-write"`.
If you need to allow the agent to update Git metadata (e.g., in CI when it must commit/push), you can opt‑in by setting a workspace‑write tweak:
```toml
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
allow_git_writes = true # default is false; enables writes under .git
```
### Debugging Virtual Cursor
Use these console helpers to diagnose motion/cancellation behavior when testing in a real browser:
+4
View File
@@ -9,6 +9,7 @@ pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String {
network_access,
exclude_tmpdir_env_var,
exclude_slash_tmp,
allow_git_writes,
} => {
let mut summary = "workspace-write".to_string();
@@ -27,6 +28,9 @@ pub fn summarize_sandbox_policy(sandbox_policy: &SandboxPolicy) -> String {
);
summary.push_str(&format!(" [{}]", writable_entries.join(", ")));
if *allow_git_writes {
summary.push_str(" (git writes enabled)");
}
if *network_access {
summary.push_str(" (network access enabled)");
}
+2
View File
@@ -595,11 +595,13 @@ impl ConfigToml {
network_access,
exclude_tmpdir_env_var,
exclude_slash_tmp,
allow_git_writes,
}) => SandboxPolicy::WorkspaceWrite {
writable_roots: writable_roots.clone(),
network_access: *network_access,
exclude_tmpdir_env_var: *exclude_tmpdir_env_var,
exclude_slash_tmp: *exclude_slash_tmp,
allow_git_writes: *allow_git_writes,
},
None => SandboxPolicy::new_workspace_write_policy(),
},
+4
View File
@@ -341,6 +341,10 @@ pub struct SandboxWorkspaceWrite {
pub exclude_tmpdir_env_var: bool,
#[serde(default)]
pub exclude_slash_tmp: bool,
/// When true, do not protect the top-level `.git` folder under a writable
/// root. Defaults to false for safety.
#[serde(default)]
pub allow_git_writes: bool,
}
#[derive(Deserialize, Debug, Clone, PartialEq, Default)]
+12 -3
View File
@@ -198,6 +198,11 @@ pub enum SandboxPolicy {
/// writable roots on UNIX. Defaults to `false`.
#[serde(default)]
exclude_slash_tmp: bool,
/// When true, do not protect the top-level `.git` folder under a
/// writable root. Defaults to false for safety.
#[serde(default)]
allow_git_writes: bool,
},
}
@@ -248,6 +253,7 @@ impl SandboxPolicy {
network_access: false,
exclude_tmpdir_env_var: false,
exclude_slash_tmp: false,
allow_git_writes: false,
}
}
@@ -283,6 +289,7 @@ impl SandboxPolicy {
writable_roots,
exclude_tmpdir_env_var,
exclude_slash_tmp,
allow_git_writes,
network_access: _,
} => {
// Start from explicitly configured writable roots.
@@ -321,9 +328,11 @@ impl SandboxPolicy {
.into_iter()
.map(|writable_root| {
let mut subpaths = Vec::new();
let top_level_git = writable_root.join(".git");
if top_level_git.is_dir() {
subpaths.push(top_level_git);
if !allow_git_writes {
let top_level_git = writable_root.join(".git");
if top_level_git.is_dir() {
subpaths.push(top_level_git);
}
}
WritableRoot {
root: writable_root,
+12 -3
View File
@@ -223,6 +223,11 @@ pub enum SandboxPolicy {
/// writable roots on UNIX. Defaults to `false`.
#[serde(default)]
exclude_slash_tmp: bool,
/// When true, do not protect the top-level `.git` folder under a
/// writable root. Defaults to false for safety.
#[serde(default)]
allow_git_writes: bool,
},
}
@@ -280,6 +285,7 @@ impl SandboxPolicy {
network_access: false,
exclude_tmpdir_env_var: false,
exclude_slash_tmp: false,
allow_git_writes: false,
}
}
@@ -315,6 +321,7 @@ impl SandboxPolicy {
writable_roots,
exclude_tmpdir_env_var,
exclude_slash_tmp,
allow_git_writes,
network_access: _,
} => {
// Start from explicitly configured writable roots.
@@ -353,9 +360,11 @@ impl SandboxPolicy {
.into_iter()
.map(|writable_root| {
let mut subpaths = Vec::new();
let top_level_git = writable_root.join(".git");
if top_level_git.is_dir() {
subpaths.push(top_level_git);
if !allow_git_writes {
let top_level_git = writable_root.join(".git");
if top_level_git.is_dir() {
subpaths.push(top_level_git);
}
}
WritableRoot {
root: writable_root,