Separate exec permission paths from core models (#33200)

## Why

Core filesystem permission models operate on native absolute paths, while exec
sandbox contexts must serialize paths as portable URIs.

## What changed

- Make the core filesystem permission and profile types concrete over
  `AbsolutePathBuf` instead of generic over their path representation.
- Add exec-specific permission types that convert native permission paths to
  `PathUri` values at the sandbox protocol boundary.
- Replace the legacy read/write-roots tuple with a named
  `LegacyReadWriteRoots` struct.

## Testing

- Add coverage that exec sandbox permission paths serialize as URIs and round
  trip through the filesystem protocol.

GitOrigin-RevId: a0ef5f8aba9bbfdf00a00fcc4f199314836bc85d
This commit is contained in:
Adam Perry @ OpenAI
2026-07-15 01:31:40 +00:00
committed by copyberry
parent 70a0b1eef8
commit 72b41c55fb
7 changed files with 292 additions and 281 deletions
@@ -597,6 +597,11 @@ mod tests {
use codex_file_system::FileSystemSandboxContext;
use codex_network_proxy::ManagedNetworkSandboxContext;
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::NetworkSandboxPolicy;
use codex_utils_path_uri::PathUri;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
@@ -694,6 +699,38 @@ mod tests {
.expect_err("native absolute sandbox cwd should not deserialize as a URI");
}
#[test]
fn filesystem_protocol_round_trips_permission_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 =
FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
path: FileSystemPath::Path {
path: native_cwd.try_into().expect("absolute cwd"),
},
access: FileSystemAccessMode::Read,
}]);
file_system_policy.glob_scan_max_depth = Some(2);
let permissions = PermissionProfile::from_runtime_permissions(
&file_system_policy,
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!(
serde_json::from_value::<FileSystemSandboxContext>(serialized)
.expect("deserialize sandbox"),
sandbox
);
}
#[test]
fn http_request_timeout_treats_omitted_and_null_as_no_timeout() {
let omitted: HttpRequestParams = serde_json::from_value(serde_json::json!({