mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
feat: allow limited git writes in workspace sandbox
Co-authored-by: Codex noreply@openai.com
This commit is contained in:
co-authored by
Codex noreply@openai.com
parent
d6748f741a
commit
8980fd17ee
@@ -86,6 +86,12 @@ codex --sandbox danger-full-access
|
||||
```
|
||||
|
||||
In `workspace-write`, Codex also includes `~/.codex/memories` in its writable roots so memory maintenance does not require an extra approval.
|
||||
Set the following to allow Git metadata writes under writable roots while keeping Git config and hooks read-only:
|
||||
|
||||
```toml
|
||||
[sandbox_workspace_write]
|
||||
allow_limited_git_writes = true
|
||||
```
|
||||
|
||||
## Code Organization
|
||||
|
||||
|
||||
@@ -2864,6 +2864,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -3013,6 +3013,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
+8
@@ -14716,6 +14716,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
@@ -14753,6 +14757,10 @@
|
||||
},
|
||||
"SandboxWorkspaceWrite": {
|
||||
"properties": {
|
||||
"allow_limited_git_writes": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"exclude_slash_tmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
+8
@@ -11245,6 +11245,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
@@ -11282,6 +11286,10 @@
|
||||
},
|
||||
"SandboxWorkspaceWrite": {
|
||||
"properties": {
|
||||
"allow_limited_git_writes": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"exclude_slash_tmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -98,6 +98,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -698,6 +698,10 @@
|
||||
},
|
||||
"SandboxWorkspaceWrite": {
|
||||
"properties": {
|
||||
"allow_limited_git_writes": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"exclude_slash_tmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -793,6 +793,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -793,6 +793,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
+4
@@ -219,6 +219,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -793,6 +793,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -249,6 +249,10 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"allowLimitedGitWrites": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"excludeSlashTmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
|
||||
import type { NetworkAccess } from "./NetworkAccess";
|
||||
|
||||
export type SandboxPolicy = { "type": "dangerFullAccess" } | { "type": "readOnly", networkAccess: boolean, } | { "type": "externalSandbox", networkAccess: NetworkAccess, } | { "type": "workspaceWrite", writableRoots: Array<AbsolutePathBuf>, networkAccess: boolean, excludeTmpdirEnvVar: boolean, excludeSlashTmp: boolean, };
|
||||
export type SandboxPolicy = { "type": "dangerFullAccess" } | { "type": "readOnly", networkAccess: boolean, } | { "type": "externalSandbox", networkAccess: NetworkAccess, } | { "type": "workspaceWrite", writableRoots: Array<AbsolutePathBuf>, networkAccess: boolean, allowLimitedGitWrites: boolean, excludeTmpdirEnvVar: boolean, excludeSlashTmp: boolean, };
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SandboxWorkspaceWrite = { writable_roots: Array<string>, network_access: boolean, exclude_tmpdir_env_var: boolean, exclude_slash_tmp: boolean, };
|
||||
export type SandboxWorkspaceWrite = { writable_roots: Array<string>, network_access: boolean, allow_limited_git_writes: boolean, exclude_tmpdir_env_var: boolean, exclude_slash_tmp: boolean, };
|
||||
|
||||
@@ -223,6 +223,7 @@ pub struct SandboxSettings {
|
||||
#[serde(default)]
|
||||
pub writable_roots: Vec<AbsolutePathBuf>,
|
||||
pub network_access: Option<bool>,
|
||||
pub allow_limited_git_writes: Option<bool>,
|
||||
pub exclude_tmpdir_env_var: Option<bool>,
|
||||
pub exclude_slash_tmp: Option<bool>,
|
||||
}
|
||||
|
||||
@@ -136,6 +136,8 @@ pub struct SandboxWorkspaceWrite {
|
||||
#[serde(default)]
|
||||
pub network_access: bool,
|
||||
#[serde(default)]
|
||||
pub allow_limited_git_writes: bool,
|
||||
#[serde(default)]
|
||||
pub exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
pub exclude_slash_tmp: bool,
|
||||
|
||||
@@ -449,6 +449,8 @@ pub enum SandboxPolicy {
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
#[serde(default)]
|
||||
allow_limited_git_writes: bool,
|
||||
#[serde(default)]
|
||||
exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
exclude_slash_tmp: bool,
|
||||
@@ -480,6 +482,8 @@ enum SandboxPolicyDeserialize {
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
#[serde(default)]
|
||||
allow_limited_git_writes: bool,
|
||||
#[serde(default)]
|
||||
exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
exclude_slash_tmp: bool,
|
||||
@@ -518,6 +522,7 @@ impl<'de> Deserialize<'de> for SandboxPolicy {
|
||||
writable_roots,
|
||||
read_only_access,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => {
|
||||
@@ -529,6 +534,7 @@ impl<'de> Deserialize<'de> for SandboxPolicy {
|
||||
Ok(SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
})
|
||||
@@ -559,11 +565,13 @@ impl SandboxPolicy {
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => codex_protocol::protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: writable_roots.clone(),
|
||||
network_access: *network_access,
|
||||
allow_limited_git_writes: *allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var: *exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp: *exclude_slash_tmp,
|
||||
},
|
||||
@@ -591,11 +599,13 @@ impl From<codex_protocol::protocol::SandboxPolicy> for SandboxPolicy {
|
||||
codex_protocol::protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
},
|
||||
|
||||
@@ -2086,6 +2086,7 @@ fn sandbox_policy_round_trips_workspace_write_access() {
|
||||
let v2_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: true,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
};
|
||||
@@ -2096,6 +2097,7 @@ fn sandbox_policy_round_trips_workspace_write_access() {
|
||||
codex_protocol::protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: true,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
}
|
||||
@@ -2142,6 +2144,7 @@ fn sandbox_policy_deserializes_legacy_workspace_write_full_access_field() {
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![absolute_path("/workspace")],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
|
||||
@@ -2183,6 +2183,7 @@ async fn turn_start_updates_sandbox_and_cwd_between_turns_v2() -> Result<()> {
|
||||
sandbox_policy: Some(codex_app_server_protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![first_cwd.try_into()?],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}),
|
||||
|
||||
@@ -772,6 +772,7 @@ impl ConfigToml {
|
||||
Some(SandboxWorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
}) => {
|
||||
@@ -780,11 +781,12 @@ impl ConfigToml {
|
||||
} else {
|
||||
NetworkSandboxPolicy::Restricted
|
||||
};
|
||||
PermissionProfile::workspace_write_with(
|
||||
PermissionProfile::workspace_write_with_limited_git_writes(
|
||||
writable_roots,
|
||||
network_policy,
|
||||
*exclude_tmpdir_env_var,
|
||||
*exclude_slash_tmp,
|
||||
*allow_limited_git_writes,
|
||||
)
|
||||
}
|
||||
None => PermissionProfile::workspace_write(),
|
||||
|
||||
@@ -883,6 +883,8 @@ pub struct SandboxWorkspaceWrite {
|
||||
#[serde(default)]
|
||||
pub network_access: bool,
|
||||
#[serde(default)]
|
||||
pub allow_limited_git_writes: bool,
|
||||
#[serde(default)]
|
||||
pub exclude_tmpdir_env_var: bool,
|
||||
#[serde(default)]
|
||||
pub exclude_slash_tmp: bool,
|
||||
@@ -893,6 +895,7 @@ impl From<SandboxWorkspaceWrite> for codex_app_server_protocol::SandboxSettings
|
||||
Self {
|
||||
writable_roots: sandbox_workspace_write.writable_roots,
|
||||
network_access: Some(sandbox_workspace_write.network_access),
|
||||
allow_limited_git_writes: Some(sandbox_workspace_write.allow_limited_git_writes),
|
||||
exclude_tmpdir_env_var: Some(sandbox_workspace_write.exclude_tmpdir_env_var),
|
||||
exclude_slash_tmp: Some(sandbox_workspace_write.exclude_slash_tmp),
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ Expects `/usr/bin/sandbox-exec` to be present.
|
||||
|
||||
When using the workspace-write sandbox policy, the Seatbelt profile allows
|
||||
writes under the configured writable roots while keeping `.git` (directory or
|
||||
pointer file), the resolved `gitdir:` target, and `.codex` read-only.
|
||||
pointer file), the resolved `gitdir:` target, and `.codex` read-only by
|
||||
default. When `allow_limited_git_writes` is enabled, Git metadata writes are allowed,
|
||||
but `.git/config`, `.git/hooks`, and resolved worktree gitdir config/hooks
|
||||
remain read-only.
|
||||
|
||||
Network access and filesystem read/write roots are controlled by
|
||||
`SandboxPolicy`. Seatbelt consumes the resolved policy and enforces it.
|
||||
|
||||
@@ -2514,6 +2514,10 @@
|
||||
"SandboxWorkspaceWrite": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allow_limited_git_writes": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"exclude_slash_tmp": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
|
||||
@@ -795,6 +795,46 @@ async fn runtime_config_uses_tui_raw_output_mode() {
|
||||
assert!(cfg.tui_raw_output_mode);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sandbox_workspace_write_allow_limited_git_writes_keeps_config_and_hooks_read_only()
|
||||
-> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cwd = TempDir::new()?;
|
||||
let git_dir = cwd.path().join(".git");
|
||||
let git_config = git_dir.join("config");
|
||||
let git_hooks = git_dir.join("hooks");
|
||||
std::fs::create_dir_all(&git_hooks)?;
|
||||
std::fs::write(&git_config, "[core]\n")?;
|
||||
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml {
|
||||
sandbox_mode: Some(SandboxMode::WorkspaceWrite),
|
||||
sandbox_workspace_write: Some(SandboxWorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: true,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
ConfigOverrides {
|
||||
cwd: Some(cwd.path().to_path_buf()),
|
||||
..Default::default()
|
||||
},
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
let file_system = config.permissions.file_system_sandbox_policy();
|
||||
|
||||
assert!(file_system.can_write_path_with_cwd(git_dir.join("index").as_path(), cwd.path()));
|
||||
assert!(!file_system.can_write_path_with_cwd(git_config.as_path(), cwd.path()));
|
||||
assert!(
|
||||
!file_system.can_write_path_with_cwd(git_hooks.join("pre-commit").as_path(), cwd.path())
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_toml_deserializes_permission_profiles() {
|
||||
let toml = r#"
|
||||
@@ -1654,6 +1694,7 @@ async fn default_permissions_profile_populates_runtime_sandbox_policy() -> std::
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
@@ -1926,6 +1967,7 @@ async fn permission_profile_override_keeps_memories_root_out_of_legacy_projectio
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
@@ -2312,6 +2354,7 @@ async fn explicit_builtin_workspace_profile_ignores_legacy_workspace_write_setti
|
||||
sandbox_workspace_write: Some(SandboxWorkspaceWrite {
|
||||
writable_roots: vec![extra_root.path().abs()],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}),
|
||||
@@ -2528,6 +2571,7 @@ async fn implicit_builtin_workspace_profile_preserves_sandbox_workspace_write_se
|
||||
sandbox_workspace_write: Some(SandboxWorkspaceWrite {
|
||||
writable_roots: vec![extra_root.clone()],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: false,
|
||||
}),
|
||||
@@ -2564,6 +2608,7 @@ async fn implicit_builtin_workspace_profile_preserves_sandbox_workspace_write_se
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access,
|
||||
allow_limited_git_writes: _,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
} => {
|
||||
@@ -2833,6 +2878,7 @@ async fn permissions_profiles_allow_direct_write_roots_outside_workspace_root()
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![external_write_path],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
@@ -3554,6 +3600,7 @@ trust_level = "trusted"
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![writable_root.clone()],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
@@ -3594,6 +3641,7 @@ exclude_slash_tmp = true
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![writable_root],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
|
||||
@@ -77,9 +77,10 @@ pub(crate) fn builtin_permission_profile(
|
||||
Some(SandboxWorkspaceWrite {
|
||||
writable_roots: _,
|
||||
network_access,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
}) => PermissionProfile::workspace_write_with(
|
||||
}) => PermissionProfile::workspace_write_with_limited_git_writes(
|
||||
&[],
|
||||
if *network_access {
|
||||
NetworkSandboxPolicy::Enabled
|
||||
@@ -88,6 +89,7 @@ pub(crate) fn builtin_permission_profile(
|
||||
},
|
||||
*exclude_tmpdir_env_var,
|
||||
*exclude_slash_tmp,
|
||||
*allow_limited_git_writes,
|
||||
),
|
||||
None => PermissionProfile::workspace_write(),
|
||||
}),
|
||||
|
||||
@@ -472,6 +472,7 @@ fn windows_restricted_token_allows_legacy_workspace_write_policies() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -530,6 +531,7 @@ fn windows_restricted_token_rejects_split_only_filesystem_policies() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -575,6 +577,7 @@ fn windows_restricted_token_rejects_root_write_read_only_carveouts() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -621,6 +624,7 @@ fn windows_restricted_token_supports_full_read_split_write_read_carveouts() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -679,6 +683,7 @@ fn windows_restricted_token_rejects_unreadable_split_carveouts() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -766,6 +771,7 @@ fn windows_elevated_supports_split_write_read_carveouts() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -824,6 +830,7 @@ fn windows_elevated_supports_unreadable_split_carveouts() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -887,6 +894,7 @@ fn windows_elevated_supports_unreadable_globs() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -944,6 +952,7 @@ fn windows_elevated_rejects_reopened_writable_descendants() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
@@ -3770,6 +3770,7 @@ async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -3906,6 +3907,7 @@ async fn session_configuration_apply_permission_profile_accepts_direct_write_roo
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![external_write_path],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
}
|
||||
@@ -4204,6 +4206,7 @@ async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_upda
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
@@ -844,6 +844,7 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
let workspace_write = |network_access| SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -2064,6 +2065,7 @@ async fn approving_apply_patch_for_session_skips_future_prompts_for_same_file()
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -2993,6 +2995,7 @@ allow_local_binding = true
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -3274,6 +3277,7 @@ allow_local_binding = true
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -3479,6 +3483,7 @@ allow_local_binding = true
|
||||
let turn_sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
@@ -39,6 +39,7 @@ async fn guardian_review_session_does_not_inherit_legacy_notify() -> Result<()>
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
@@ -727,6 +727,7 @@ fn sample_thread_start_response() -> ThreadStartResponse {
|
||||
sandbox: codex_app_server_protocol::SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
},
|
||||
|
||||
@@ -326,6 +326,7 @@ mod agent {
|
||||
let consolidation_sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
@@ -413,10 +413,27 @@ impl PermissionProfile {
|
||||
exclude_tmpdir_env_var: bool,
|
||||
exclude_slash_tmp: bool,
|
||||
) -> Self {
|
||||
let file_system = FileSystemSandboxPolicy::workspace_write(
|
||||
Self::workspace_write_with_limited_git_writes(
|
||||
writable_roots,
|
||||
network,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
/*allow_limited_git_writes*/ false,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn workspace_write_with_limited_git_writes(
|
||||
writable_roots: &[AbsolutePathBuf],
|
||||
network: NetworkSandboxPolicy,
|
||||
exclude_tmpdir_env_var: bool,
|
||||
exclude_slash_tmp: bool,
|
||||
allow_limited_git_writes: bool,
|
||||
) -> Self {
|
||||
let file_system = FileSystemSandboxPolicy::workspace_write_with_limited_git_writes(
|
||||
writable_roots,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
allow_limited_git_writes,
|
||||
);
|
||||
Self::Managed {
|
||||
file_system: ManagedFileSystemPermissions::from_sandbox_policy(&file_system),
|
||||
|
||||
@@ -520,6 +520,20 @@ impl FileSystemSandboxPolicy {
|
||||
writable_roots: &[AbsolutePathBuf],
|
||||
exclude_tmpdir_env_var: bool,
|
||||
exclude_slash_tmp: bool,
|
||||
) -> Self {
|
||||
Self::workspace_write_with_limited_git_writes(
|
||||
writable_roots,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
/*allow_limited_git_writes*/ false,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn workspace_write_with_limited_git_writes(
|
||||
writable_roots: &[AbsolutePathBuf],
|
||||
exclude_tmpdir_env_var: bool,
|
||||
exclude_slash_tmp: bool,
|
||||
allow_limited_git_writes: bool,
|
||||
) -> Self {
|
||||
let mut entries = vec![FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -560,13 +574,39 @@ impl FileSystemSandboxPolicy {
|
||||
}),
|
||||
);
|
||||
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(&mut entries, ".git");
|
||||
if allow_limited_git_writes {
|
||||
entries.push(FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(Some(".git".into())),
|
||||
},
|
||||
access: FileSystemAccessMode::Write,
|
||||
});
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
&mut entries,
|
||||
".git/config",
|
||||
);
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
&mut entries,
|
||||
".git/hooks",
|
||||
);
|
||||
} else {
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(&mut entries, ".git");
|
||||
}
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(&mut entries, ".agents");
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(&mut entries, ".codex");
|
||||
for writable_root in writable_roots {
|
||||
if allow_limited_git_writes {
|
||||
entries.push(FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
path: writable_root.join(".git"),
|
||||
},
|
||||
access: FileSystemAccessMode::Write,
|
||||
});
|
||||
}
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
writable_root,
|
||||
/*protect_missing_dot_codex*/ false,
|
||||
allow_limited_git_writes,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(&mut entries, protected_path);
|
||||
}
|
||||
@@ -584,10 +624,17 @@ impl FileSystemSandboxPolicy {
|
||||
/// into split filesystem policy.
|
||||
pub fn from_legacy_sandbox_policy_for_cwd(sandbox_policy: &SandboxPolicy, cwd: &Path) -> Self {
|
||||
let mut file_system_policy = Self::from(sandbox_policy);
|
||||
if let SandboxPolicy::WorkspaceWrite { writable_roots, .. } = sandbox_policy {
|
||||
if let SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
allow_limited_git_writes,
|
||||
..
|
||||
} = sandbox_policy
|
||||
{
|
||||
if let Ok(cwd_root) = AbsolutePathBuf::from_absolute_path(cwd) {
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
&cwd_root, /*protect_missing_dot_codex*/ true,
|
||||
&cwd_root,
|
||||
/*protect_missing_dot_codex*/ true,
|
||||
*allow_limited_git_writes,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(
|
||||
&mut file_system_policy.entries,
|
||||
@@ -599,6 +646,7 @@ impl FileSystemSandboxPolicy {
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
writable_root,
|
||||
/*protect_missing_dot_codex*/ false,
|
||||
*allow_limited_git_writes,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(
|
||||
&mut file_system_policy.entries,
|
||||
@@ -879,6 +927,7 @@ impl FileSystemSandboxPolicy {
|
||||
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
path, /*protect_missing_dot_codex*/ false,
|
||||
/*allow_limited_git_writes*/ false,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(
|
||||
&mut self.entries,
|
||||
@@ -973,11 +1022,23 @@ impl FileSystemSandboxPolicy {
|
||||
let protect_missing_dot_codex = AbsolutePathBuf::from_absolute_path(cwd)
|
||||
.ok()
|
||||
.is_some_and(|cwd| normalize_effective_absolute_path(cwd) == root);
|
||||
let allow_limited_git_writes = std::iter::once(&root)
|
||||
.chain(raw_writable_roots.iter().copied())
|
||||
.any(|raw_root| {
|
||||
let dot_git = raw_root.join(PROTECTED_METADATA_GIT_PATH_NAME);
|
||||
resolved_entries
|
||||
.iter()
|
||||
.any(|entry| entry.access.can_write() && entry.path == dot_git)
|
||||
});
|
||||
let mut read_only_subpaths: Vec<AbsolutePathBuf> =
|
||||
default_read_only_subpaths_for_writable_root(&root, protect_missing_dot_codex)
|
||||
.into_iter()
|
||||
.filter(|path| !has_explicit_resolved_path_entry(&resolved_entries, path))
|
||||
.collect();
|
||||
default_read_only_subpaths_for_writable_root(
|
||||
&root,
|
||||
protect_missing_dot_codex,
|
||||
allow_limited_git_writes,
|
||||
)
|
||||
.into_iter()
|
||||
.filter(|path| !has_explicit_resolved_path_entry(&resolved_entries, path))
|
||||
.collect();
|
||||
// Narrower explicit non-write entries carve out broader writable roots.
|
||||
// More specific write entries still remain writable because they appear
|
||||
// as separate WritableRoot values and are checked independently.
|
||||
@@ -1193,6 +1254,7 @@ impl FileSystemSandboxPolicy {
|
||||
/*normalize_effective_paths*/ false,
|
||||
),
|
||||
network_access: network_policy.is_enabled(),
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: !tmpdir_writable,
|
||||
exclude_slash_tmp: !slash_tmp_writable,
|
||||
}
|
||||
@@ -1267,13 +1329,15 @@ impl From<&SandboxPolicy> for FileSystemSandboxPolicy {
|
||||
}
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
..
|
||||
} => FileSystemSandboxPolicy::workspace_write(
|
||||
} => FileSystemSandboxPolicy::workspace_write_with_limited_git_writes(
|
||||
writable_roots,
|
||||
*exclude_tmpdir_env_var,
|
||||
*exclude_slash_tmp,
|
||||
*allow_limited_git_writes,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -1542,6 +1606,7 @@ fn normalize_effective_absolute_path(path: AbsolutePathBuf) -> AbsolutePathBuf {
|
||||
pub(crate) fn default_read_only_subpaths_for_writable_root(
|
||||
writable_root: &AbsolutePathBuf,
|
||||
protect_missing_dot_codex: bool,
|
||||
allow_limited_git_writes: bool,
|
||||
) -> Vec<AbsolutePathBuf> {
|
||||
let mut subpaths: Vec<AbsolutePathBuf> = Vec::new();
|
||||
let top_level_git = writable_root.join(PROTECTED_METADATA_GIT_PATH_NAME);
|
||||
@@ -1556,9 +1621,19 @@ pub(crate) fn default_read_only_subpaths_for_writable_root(
|
||||
&& is_git_pointer_file(&top_level_git)
|
||||
&& let Some(gitdir) = resolve_gitdir_from_file(&top_level_git)
|
||||
{
|
||||
subpaths.push(gitdir);
|
||||
if allow_limited_git_writes {
|
||||
subpaths.extend(protected_git_subpaths_when_writable(&gitdir));
|
||||
} else {
|
||||
subpaths.push(gitdir);
|
||||
}
|
||||
}
|
||||
if allow_limited_git_writes {
|
||||
if top_level_git_is_dir {
|
||||
subpaths.extend(protected_git_subpaths_when_writable(&top_level_git));
|
||||
}
|
||||
} else {
|
||||
subpaths.push(top_level_git);
|
||||
}
|
||||
subpaths.push(top_level_git);
|
||||
}
|
||||
|
||||
let top_level_agents = writable_root.join(PROTECTED_METADATA_AGENTS_PATH_NAME);
|
||||
@@ -1591,6 +1666,7 @@ fn legacy_runtime_file_system_policy_for_cwd(
|
||||
) -> FileSystemSandboxPolicy {
|
||||
let SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
..
|
||||
@@ -1642,7 +1718,9 @@ fn legacy_runtime_file_system_policy_for_cwd(
|
||||
|
||||
if let Ok(cwd_root) = AbsolutePathBuf::from_absolute_path(cwd) {
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
&cwd_root, /*protect_missing_dot_codex*/ true,
|
||||
&cwd_root,
|
||||
/*protect_missing_dot_codex*/ true,
|
||||
*allow_limited_git_writes,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(&mut entries, protected_path);
|
||||
}
|
||||
@@ -1651,6 +1729,7 @@ fn legacy_runtime_file_system_policy_for_cwd(
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
writable_root,
|
||||
/*protect_missing_dot_codex*/ false,
|
||||
*allow_limited_git_writes,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(&mut entries, protected_path);
|
||||
}
|
||||
@@ -1659,6 +1738,13 @@ fn legacy_runtime_file_system_policy_for_cwd(
|
||||
FileSystemSandboxPolicy::restricted(entries)
|
||||
}
|
||||
|
||||
fn protected_git_subpaths_when_writable(gitdir: &AbsolutePathBuf) -> Vec<AbsolutePathBuf> {
|
||||
["config", "hooks"]
|
||||
.into_iter()
|
||||
.map(|subpath| gitdir.join(subpath))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
entries: &mut Vec<FileSystemSandboxEntry>,
|
||||
subpath: impl Into<PathBuf>,
|
||||
@@ -1945,6 +2031,7 @@ mod tests {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -1986,6 +2073,64 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workspace_write_with_limited_git_writes_protects_only_config_and_hooks() {
|
||||
let cwd = TempDir::new().expect("tempdir");
|
||||
let git_dir = cwd.path().join(".git");
|
||||
let git_config = git_dir.join("config");
|
||||
let git_hooks = git_dir.join("hooks");
|
||||
std::fs::create_dir_all(&git_hooks).expect("create git hooks");
|
||||
std::fs::write(&git_config, "[core]\n").expect("write git config");
|
||||
|
||||
let policy = FileSystemSandboxPolicy::workspace_write_with_limited_git_writes(
|
||||
&[],
|
||||
/*exclude_tmpdir_env_var*/ true,
|
||||
/*exclude_slash_tmp*/ true,
|
||||
/*allow_limited_git_writes*/ true,
|
||||
);
|
||||
|
||||
assert!(policy.can_write_path_with_cwd(git_dir.join("index").as_path(), cwd.path()));
|
||||
assert!(!policy.can_write_path_with_cwd(git_config.as_path(), cwd.path()));
|
||||
assert!(
|
||||
!policy.can_write_path_with_cwd(git_hooks.join("pre-commit").as_path(), cwd.path())
|
||||
);
|
||||
|
||||
let root = AbsolutePathBuf::from_absolute_path(
|
||||
cwd.path().canonicalize().expect("canonicalize cwd"),
|
||||
)
|
||||
.expect("absolute cwd");
|
||||
let writable_root = policy
|
||||
.get_writable_roots_with_cwd(cwd.path())
|
||||
.into_iter()
|
||||
.find(|writable_root| writable_root.root == root)
|
||||
.expect("workspace writable root");
|
||||
|
||||
assert!(
|
||||
!writable_root
|
||||
.read_only_subpaths
|
||||
.contains(&root.join(".git")),
|
||||
".git should remain writable"
|
||||
);
|
||||
assert!(
|
||||
writable_root
|
||||
.read_only_subpaths
|
||||
.contains(&root.join(".git").join("config")),
|
||||
".git/config should remain read-only"
|
||||
);
|
||||
assert!(
|
||||
writable_root
|
||||
.read_only_subpaths
|
||||
.contains(&root.join(".git").join("hooks")),
|
||||
".git/hooks should remain read-only"
|
||||
);
|
||||
assert!(
|
||||
!writable_root
|
||||
.protected_metadata_names
|
||||
.contains(&".git".to_string()),
|
||||
".git should not be protected as an all-or-nothing metadata directory"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_current_working_directory_special_path_deserializes_as_project_roots()
|
||||
-> serde_json::Result<()> {
|
||||
@@ -2101,6 +2246,7 @@ mod tests {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -2134,6 +2280,7 @@ mod tests {
|
||||
default_read_only_subpaths_for_writable_root(
|
||||
&expected_root,
|
||||
/*protect_missing_dot_codex*/ true,
|
||||
/*allow_limited_git_writes*/ false,
|
||||
)
|
||||
.into_iter()
|
||||
.map(|path| FileSystemSandboxEntry {
|
||||
@@ -2617,6 +2764,7 @@ mod tests {
|
||||
let legacy_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -2644,6 +2792,7 @@ mod tests {
|
||||
let legacy_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
@@ -915,6 +915,11 @@ pub enum SandboxPolicy {
|
||||
#[serde(default)]
|
||||
network_access: bool,
|
||||
|
||||
/// When set to `true`, Git metadata under writable roots can be written
|
||||
/// while Git config and hooks remain read-only.
|
||||
#[serde(default)]
|
||||
allow_limited_git_writes: bool,
|
||||
|
||||
/// When set to `true`, will NOT include the per-user `TMPDIR`
|
||||
/// environment variable among the default writable roots. Defaults to
|
||||
/// `false`.
|
||||
@@ -1021,6 +1026,7 @@ impl SandboxPolicy {
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
}
|
||||
@@ -1058,6 +1064,7 @@ impl SandboxPolicy {
|
||||
SandboxPolicy::ReadOnly { .. } => Vec::new(),
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
allow_limited_git_writes,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
network_access: _,
|
||||
@@ -1131,6 +1138,7 @@ impl SandboxPolicy {
|
||||
read_only_subpaths: default_read_only_subpaths_for_writable_root(
|
||||
&writable_root,
|
||||
protect_missing_dot_codex,
|
||||
*allow_limited_git_writes,
|
||||
),
|
||||
protected_metadata_names: Vec::new(),
|
||||
root: writable_root,
|
||||
@@ -4518,12 +4526,14 @@ mod tests {
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![writable_root],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: true,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
|
||||
@@ -299,6 +299,7 @@ fn compatibility_workspace_write_policy(
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
network_access: network_policy.is_enabled(),
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: !tmpdir_writable,
|
||||
exclude_slash_tmp: !slash_tmp_writable,
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ fn dynamic_network_policy_allows_tls_without_darwin_user_cache_write() {
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
@@ -439,6 +440,7 @@ fn dynamic_network_policy_preserves_restricted_policy_when_proxy_config_without_
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
@@ -475,6 +477,7 @@ fn dynamic_network_policy_blocks_dns_when_local_binding_has_no_proxy_ports() {
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
@@ -503,6 +506,7 @@ fn dynamic_network_policy_preserves_restricted_policy_for_managed_network_withou
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
@@ -793,6 +797,7 @@ fn create_seatbelt_args_full_network_with_proxy_is_still_proxy_only() {
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
},
|
||||
@@ -844,6 +849,7 @@ fn create_seatbelt_args_with_read_only_git_and_codex_subpaths() {
|
||||
.map(|p| p.try_into().unwrap())
|
||||
.collect(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -1087,6 +1093,7 @@ fn create_seatbelt_args_block_first_time_dot_codex_creation_with_metadata_name_r
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![repo_root.as_path().try_into().expect("absolute repo root")],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -1140,6 +1147,7 @@ fn create_seatbelt_args_with_read_only_git_pointer_file() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![worktree_root.try_into().expect("worktree_root is absolute")],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
@@ -1236,6 +1244,7 @@ fn create_seatbelt_args_for_cwd_as_git_repo() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
};
|
||||
|
||||
@@ -846,6 +846,7 @@ mod tests {
|
||||
let legacy_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
};
|
||||
|
||||
@@ -133,6 +133,7 @@ mod tests {
|
||||
let summary = summarize_sandbox_policy(&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![writable_root.clone()],
|
||||
network_access: true,
|
||||
allow_limited_git_writes: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user