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 authored and copyberry committed 2026-07-15 01:31:40 +00:00
1 parent 70a0b1eef8
commit 72b41c55fb
7 files changed
+292 -281

No files matched your search

+5 -51
View File
@@ -6,7 +6,6 @@ use std::path::PathBuf;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_absolute_path::canonicalize_preserving_symlinks;
use codex_utils_path_uri::PathUri;
use globset::GlobBuilder;
use globset::GlobMatcher;
use schemars::JsonSchema;
@@ -177,31 +176,11 @@ impl FileSystemSpecialPath {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema, TS)]
pub struct FileSystemSandboxEntry<PathType = AbsolutePathBuf> {
pub path: FileSystemPath<PathType>,
pub struct FileSystemSandboxEntry {
pub path: FileSystemPath,
pub access: FileSystemAccessMode,
}
impl From<FileSystemSandboxEntry<AbsolutePathBuf>> for FileSystemSandboxEntry<PathUri> {
fn from(value: FileSystemSandboxEntry<AbsolutePathBuf>) -> Self {
FileSystemSandboxEntry {
path: value.path.into(),
access: value.access,
}
}
}
impl TryFrom<FileSystemSandboxEntry<PathUri>> for FileSystemSandboxEntry<AbsolutePathBuf> {
type Error = io::Error;
fn try_from(value: FileSystemSandboxEntry<PathUri>) -> Result<Self, Self::Error> {
Ok(FileSystemSandboxEntry {
path: value.path.try_into()?,
access: value.access,
})
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, Default, JsonSchema, TS,
)]
@@ -359,9 +338,10 @@ enum InvalidDenyReadGlobBehavior {
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "snake_case")]
#[ts(tag = "type")]
pub enum FileSystemPath<PathType = AbsolutePathBuf> {
pub enum FileSystemPath {
Path {
path: PathType,
// TODO(anp): Use PathUri once permission paths no longer require native-path rollout serialization.
path: AbsolutePathBuf,
},
/// A git-style glob pattern. Pattern entries currently support
/// FileSystemAccessMode::Deny only.
@@ -373,32 +353,6 @@ pub enum FileSystemPath<PathType = AbsolutePathBuf> {
},
}
impl From<FileSystemPath<AbsolutePathBuf>> for FileSystemPath<PathUri> {
fn from(value: FileSystemPath<AbsolutePathBuf>) -> Self {
match value {
FileSystemPath::Path { path } => FileSystemPath::Path {
path: PathUri::from_abs_path(&path),
},
FileSystemPath::GlobPattern { pattern } => FileSystemPath::GlobPattern { pattern },
FileSystemPath::Special { value } => FileSystemPath::Special { value },
}
}
}
impl TryFrom<FileSystemPath<PathUri>> for FileSystemPath<AbsolutePathBuf> {
type Error = io::Error;
fn try_from(value: FileSystemPath<PathUri>) -> Result<Self, Self::Error> {
Ok(match value {
FileSystemPath::Path { path } => FileSystemPath::Path {
path: path.to_abs_path()?,
},
FileSystemPath::GlobPattern { pattern } => FileSystemPath::GlobPattern { pattern },
FileSystemPath::Special { value } => FileSystemPath::Special { value },
})
}
}
const PROJECT_ROOTS_GLOB_PATTERN_PREFIX: &str = "codex-project-roots://";
pub fn project_roots_glob_pattern(subpath: &Path) -> String {