Use PathUri in filesystem permission paths for exec-server (#28165)

## Why

Progress towards letting app-server and exec-server run on different
platforms, specifically for sandbox configuration.

## What

- Make the filesystem path containment hierarchy generic, defaulting to
`AbsolutePathBuf` for now.
- Have clients specify `AbsolutePathBuf` or `PathUri` directly where
needed.
- Use `PathUri` throughout exec-server filesystem protocol and trait
boundaries.
- Implement `From` for conversion to path URIs and `TryFrom` for
fallible conversion to absolute paths through the generic type
hierarchy.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-15 23:55:23 +00:00
committed by GitHub
parent 428cd44154
commit 46f17930b6
17 changed files with 320 additions and 97 deletions
+8 -4
View File
@@ -66,7 +66,11 @@ impl FileSystemSandboxRunner {
request: FsHelperRequest,
) -> Result<FsHelperPayload, JSONRPCErrorError> {
let cwd = sandbox_cwd(sandbox)?;
let mut file_system_policy = sandbox.permissions.file_system_sandbox_policy();
let native_permissions: PermissionProfile =
sandbox.permissions.clone().try_into().map_err(|err| {
invalid_request(format!("invalid sandbox permission path URI: {err}"))
})?;
let mut file_system_policy = native_permissions.file_system_sandbox_policy();
let helper_read_roots = if sandbox.use_legacy_landlock {
Vec::new()
} else {
@@ -80,7 +84,7 @@ impl FileSystemSandboxRunner {
normalize_file_system_policy_root_aliases(&mut file_system_policy);
let network_policy = NetworkSandboxPolicy::Restricted;
let permission_profile = PermissionProfile::from_runtime_permissions_with_enforcement(
sandbox.permissions.enforcement(),
native_permissions.enforcement(),
&file_system_policy,
network_policy,
);
@@ -578,7 +582,7 @@ mod tests {
},
access: FileSystemAccessMode::Write,
}]);
let sandbox_context = crate::FileSystemSandboxContext::from_permission_profile(
let sandbox_context = codex_file_system::FileSystemSandboxContext::from_permission_profile(
PermissionProfile::from_runtime_permissions(&policy, NetworkSandboxPolicy::Restricted),
);
@@ -650,7 +654,7 @@ mod tests {
policy: &FileSystemSandboxPolicy,
cwd: PathUri,
) -> crate::FileSystemSandboxContext {
crate::FileSystemSandboxContext::from_permission_profile_with_cwd(
codex_file_system::FileSystemSandboxContext::from_permission_profile_with_cwd(
PermissionProfile::from_runtime_permissions(policy, NetworkSandboxPolicy::Restricted),
cwd,
)
+5 -4
View File
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use crate::FileSystemSandboxContext;
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
use codex_file_system::FileSystemSandboxContext;
use codex_protocol::config_types::ShellEnvironmentPolicyInherit;
use codex_utils_path_uri::PathUri;
use serde::Deserialize;
@@ -454,7 +454,7 @@ mod base64_bytes {
mod tests {
use super::FsReadFileParams;
use super::HttpRequestParams;
use crate::FileSystemSandboxContext;
use codex_file_system::FileSystemSandboxContext;
use codex_protocol::models::PermissionProfile;
use codex_utils_path_uri::PathUri;
use pretty_assertions::assert_eq;
@@ -465,18 +465,19 @@ mod tests {
.expect("current directory")
.join("legacy-file.txt");
let legacy_cwd = std::env::current_dir().expect("current directory");
let expected_sandbox = FileSystemSandboxContext::from_permission_profile_with_cwd(
let native_sandbox = FileSystemSandboxContext::from_permission_profile_with_cwd(
PermissionProfile::default(),
PathUri::from_path(&legacy_cwd).expect("cwd URI"),
);
let mut legacy_sandbox =
serde_json::to_value(&expected_sandbox).expect("sandbox should serialize");
serde_json::to_value(&native_sandbox).expect("sandbox should serialize");
legacy_sandbox["cwd"] = serde_json::json!(legacy_cwd.to_string_lossy());
let params: FsReadFileParams = serde_json::from_value(serde_json::json!({
"path": legacy_path.to_string_lossy(),
"sandbox": legacy_sandbox,
}))
.expect("legacy absolute path should deserialize");
let expected_sandbox = native_sandbox;
let expected = FsReadFileParams {
path: PathUri::from_path(legacy_path).expect("path URI"),
sandbox: Some(expected_sandbox.clone()),