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:17:18 +00:00
committed by copyberry
parent ee71c4a90f
commit 87f71e35b8
63 changed files with 825 additions and 132 deletions
+57
View File
@@ -148,6 +148,7 @@ mod tests {
use codex_exec_server::EnvironmentManager;
use codex_utils_path_uri::LegacyAppPathString;
use pretty_assertions::assert_eq;
use serde_json::Value;
use super::*;
@@ -192,6 +193,62 @@ mod tests {
}
}
#[test]
fn sandbox_state_serializes_skip_missing_entries_as_missing_path_behavior() {
let sandbox_cwd = PathUri::from_host_native_path(
std::env::current_dir().expect("current directory should be available"),
)
.expect("current directory should convert to a URI");
let sandbox_state = SandboxState {
permission_profile: PermissionProfile::workspace_write(),
codex_linux_sandbox_exe: None,
sandbox_cwd,
use_legacy_landlock: false,
};
let serialized = serde_json::to_value(&sandbox_state).expect("serialize sandbox state");
let serialized_text = serde_json::to_string(&serialized).expect("serialize JSON text");
assert!(
!serialized_text.contains("generated_default_path"),
"MCP sandbox metadata must preserve FileSystemPath's stable wire variants"
);
assert!(
!serialized_text.contains("generated_default_special"),
"MCP sandbox metadata must preserve FileSystemPath's stable wire variants"
);
let entries = serialized
.pointer("/permissionProfile/file_system/entries")
.and_then(Value::as_array)
.expect("workspace-write profile should contain filesystem entries");
let skip_missing_entries = entries
.iter()
.filter(|entry| {
entry.get("missing_path_behavior").and_then(Value::as_str) == Some("skip")
})
.collect::<Vec<_>>();
assert!(
!skip_missing_entries.is_empty(),
"skip-missing entries should be represented as optional missing_path_behavior"
);
assert!(
skip_missing_entries.iter().all(|entry| {
matches!(
entry.pointer("/path/type").and_then(Value::as_str),
Some("path" | "special")
)
}),
"skip-missing entries should use the stable path/special variants"
);
let deserialized: SandboxState =
serde_json::from_value(serialized).expect("deserialize sandbox state");
assert_eq!(
deserialized.permission_profile,
sandbox_state.permission_profile
);
}
#[test]
fn local_stdio_requires_local_stdio_availability() {
let runtime_context = McpRuntimeContext::new(