Skip missing paths in filesystem sandbox entries (#34598)

## Why

Default read-only protections for project metadata should apply when paths such
as `.git`, `.agents`, and `.codex` exist, without causing sandbox setup to
materialize missing paths as ACL targets.

## What changed

- Add an optional `missing_path_behavior` to filesystem sandbox entries and
  mark default project-metadata protections with `skip`.
- Preserve the behavior through permission transforms and exec/MCP protocol
  serialization while keeping existing path wire variants stable.
- Ignore skip-missing entries when projecting configuration or Windows sandbox
  overrides, while retaining explicit metadata carveouts.

## Testing

- Cover protocol round trips for path and special-path entries.
- Verify default metadata protections and Windows explicit carveout handling.

GitOrigin-RevId: 6df13dadacdd131c44aab9f15a967c81051355c1
This commit is contained in:
iceweasel-oai
2026-07-21 19:11:29 +00:00
committed by copyberry
parent ee71c4a90f
commit 87f71e35b8
63 changed files with 825 additions and 132 deletions

View File

@@ -743,11 +743,13 @@ mod tests {
use codex_network_proxy::NetworkProxyConfig;
use codex_network_proxy::RemoteNetworkProxyConfig;
use codex_network_proxy::RemoteNetworkProxyLaunchConfig;
use codex_protocol::models::ManagedFileSystemPermissions;
use codex_protocol::models::PermissionProfile;
use codex_protocol::permissions::FileSystemAccessMode;
use codex_protocol::permissions::FileSystemPath;
use codex_protocol::permissions::FileSystemSandboxEntry;
use codex_protocol::permissions::FileSystemSandboxPolicy;
use codex_protocol::permissions::FileSystemSpecialPath;
use codex_protocol::permissions::NetworkSandboxPolicy;
use codex_utils_path_uri::PathUri;
use pretty_assertions::assert_eq;
@@ -871,7 +873,75 @@ mod tests {
}
#[test]
fn filesystem_protocol_round_trips_permission_paths_as_uris() {
fn filesystem_protocol_round_trips_permission_entries() {
let native_cwd = std::env::current_dir().expect("current directory");
let cwd = PathUri::from_host_native_path(&native_cwd).expect("cwd URI");
let file_system = ManagedFileSystemPermissions::Restricted {
entries: vec![
FileSystemSandboxEntry {
path: FileSystemPath::Path {
path: native_cwd.clone().try_into().expect("absolute cwd"),
},
access: FileSystemAccessMode::Read,
missing_path_behavior: None,
},
FileSystemSandboxEntry::skip_missing_path(
FileSystemPath::Path {
path: native_cwd.join(".git").try_into().expect("absolute path"),
},
FileSystemAccessMode::Read,
),
FileSystemSandboxEntry::skip_missing_path(
FileSystemPath::Special {
value: FileSystemSpecialPath::ProjectRoots {
subpath: Some(".codex".into()),
},
},
FileSystemAccessMode::Read,
),
],
glob_scan_max_depth: Some(2.try_into().expect("non-zero depth")),
};
let permissions = PermissionProfile::Managed {
file_system,
network: NetworkSandboxPolicy::Restricted,
};
let sandbox =
FileSystemSandboxContext::from_permission_profile_with_cwd(permissions, cwd.clone());
let serialized = serde_json::to_value(&sandbox).expect("serialize sandbox");
assert_eq!(
serialized["permissions"]["file_system"]["entries"][0]["path"]["path"],
serde_json::json!(cwd.to_string())
);
assert_eq!(
serialized["permissions"]["file_system"]["entries"][1]["path"]["type"],
serde_json::json!("path")
);
assert_eq!(
serialized["permissions"]["file_system"]["entries"][1]["missing_path_behavior"],
serde_json::json!("skip")
);
assert_eq!(
serialized["permissions"]["file_system"]["entries"][2]["path"]["type"],
serde_json::json!("special")
);
assert_eq!(
serialized["permissions"]["file_system"]["entries"][2]["missing_path_behavior"],
serde_json::json!("skip")
);
assert!(!serialized.to_string().contains("generated_default_path"));
assert!(!serialized.to_string().contains("generated_default_special"));
assert_eq!(
serde_json::from_value::<FileSystemSandboxContext>(serialized)
.expect("deserialize sandbox"),
sandbox
);
}
#[test]
fn filesystem_protocol_round_trips_legacy_policy_paths_as_uris() {
let native_cwd = std::env::current_dir().expect("current directory");
let cwd = PathUri::from_host_native_path(&native_cwd).expect("cwd URI");
let mut file_system_policy =
@@ -880,6 +950,7 @@ mod tests {
path: native_cwd.try_into().expect("absolute cwd"),
},
access: FileSystemAccessMode::Read,
missing_path_behavior: None,
}]);
file_system_policy.glob_scan_max_depth = Some(2);
let permissions = PermissionProfile::from_runtime_permissions(