protocol: keep special path subpaths opaque

This commit is contained in:
Adam Perry
2026-07-10 01:52:00 +00:00
parent a9f12e9f15
commit 4e29c8c733
7 changed files with 43 additions and 31 deletions
@@ -23,7 +23,7 @@ use serde::Deserialize;
use serde::Serialize;
use std::io;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::path::Path;
use ts_rs::TS;
v2_enum_from_core! {
@@ -244,13 +244,13 @@ pub enum FileSystemSpecialPath {
Minimal,
#[serde(alias = "current_working_directory")]
ProjectRoots {
subpath: Option<PathBuf>,
subpath: Option<LegacyAppPathString>,
},
Tmpdir,
SlashTmp,
Unknown {
path: String,
subpath: Option<PathBuf>,
subpath: Option<LegacyAppPathString>,
},
}
@@ -259,10 +259,21 @@ impl From<CoreFileSystemSpecialPath> for FileSystemSpecialPath {
match value {
CoreFileSystemSpecialPath::Root => Self::Root,
CoreFileSystemSpecialPath::Minimal => Self::Minimal,
CoreFileSystemSpecialPath::ProjectRoots { subpath } => Self::ProjectRoots { subpath },
CoreFileSystemSpecialPath::ProjectRoots { subpath } => Self::ProjectRoots {
subpath: subpath
.as_deref()
.map(Path::new)
.map(LegacyAppPathString::from_path),
},
CoreFileSystemSpecialPath::Tmpdir => Self::Tmpdir,
CoreFileSystemSpecialPath::SlashTmp => Self::SlashTmp,
CoreFileSystemSpecialPath::Unknown { path, subpath } => Self::Unknown { path, subpath },
CoreFileSystemSpecialPath::Unknown { path, subpath } => Self::Unknown {
path,
subpath: subpath
.as_deref()
.map(Path::new)
.map(LegacyAppPathString::from_path),
},
}
}
}
@@ -272,10 +283,15 @@ impl From<FileSystemSpecialPath> for CoreFileSystemSpecialPath {
match value {
FileSystemSpecialPath::Root => Self::Root,
FileSystemSpecialPath::Minimal => Self::Minimal,
FileSystemSpecialPath::ProjectRoots { subpath } => Self::ProjectRoots { subpath },
FileSystemSpecialPath::ProjectRoots { subpath } => Self::ProjectRoots {
subpath: subpath.map(LegacyAppPathString::into_string),
},
FileSystemSpecialPath::Tmpdir => Self::Tmpdir,
FileSystemSpecialPath::SlashTmp => Self::SlashTmp,
FileSystemSpecialPath::Unknown { path, subpath } => Self::Unknown { path, subpath },
FileSystemSpecialPath::Unknown { path, subpath } => Self::Unknown {
path,
subpath: subpath.map(LegacyAppPathString::into_string),
},
}
}
}
+8 -10
View File
@@ -274,7 +274,7 @@ fn insert_special_filesystem_permission_toml(
insert_scoped_filesystem_permission_toml(
entries,
":workspace_roots".to_string(),
subpath.unwrap_or_else(|| PathBuf::from(".")),
subpath.unwrap_or_else(|| ".".to_string()),
access,
);
}
@@ -303,7 +303,7 @@ fn insert_special_filesystem_permission_toml(
fn insert_scoped_filesystem_permission_toml(
entries: &mut BTreeMap<String, FilesystemPermissionToml>,
path: String,
subpath: PathBuf,
subpath: String,
access: FileSystemAccessMode,
) {
let permission = entries
@@ -311,13 +311,10 @@ fn insert_scoped_filesystem_permission_toml(
.or_insert_with(|| FilesystemPermissionToml::Scoped(BTreeMap::new()));
match permission {
FilesystemPermissionToml::Scoped(scoped_entries) => {
scoped_entries.insert(subpath.to_string_lossy().into_owned(), access);
scoped_entries.insert(subpath, access);
}
FilesystemPermissionToml::Access(_) => {
*permission = FilesystemPermissionToml::Scoped(BTreeMap::from([(
subpath.to_string_lossy().into_owned(),
access,
)]));
*permission = FilesystemPermissionToml::Scoped(BTreeMap::from([(subpath, access)]));
}
}
}
@@ -608,7 +605,9 @@ fn compile_scoped_filesystem_path(
}
if let Some(special) = parse_special_path(path) {
let subpath = parse_relative_subpath(subpath)?;
let subpath = parse_relative_subpath(subpath)?
.to_string_lossy()
.into_owned();
let special = match special {
FileSystemSpecialPath::ProjectRoots { .. } => Ok(FileSystemPath::Special {
value: FileSystemSpecialPath::project_roots(Some(subpath)),
@@ -894,8 +893,7 @@ fn maybe_push_unknown_special_path_warning(
startup_warnings,
match subpath.as_deref() {
Some(subpath) => format!(
"Configured filesystem path `{path}` with nested entry `{}` is not recognized by this version of Codex and will be ignored. Upgrade Codex if this path is required.",
subpath.display()
"Configured filesystem path `{path}` with nested entry `{subpath}` is not recognized by this version of Codex and will be ignored. Upgrade Codex if this path is required."
),
None => format!(
"Configured filesystem path `{path}` is not recognized by this version of Codex and will be ignored. Upgrade Codex if this path is required."
@@ -6,7 +6,6 @@ use codex_protocol::permissions::FileSystemSandboxEntry;
use codex_protocol::permissions::FileSystemSpecialPath;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::collections::HashSet;
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct FileSystemContext {
@@ -179,9 +178,9 @@ fn render_special_path(value: &FileSystemSpecialPath) -> String {
}
}
fn render_special_path_with_subpath(base: &str, subpath: &Option<PathBuf>) -> String {
fn render_special_path_with_subpath(base: &str, subpath: &Option<String>) -> String {
match subpath {
Some(subpath) => format!("{base}/{}", subpath.display()),
Some(subpath) => format!("{base}/{subpath}"),
None => base.to_string(),
}
}
@@ -14,12 +14,11 @@ use codex_utils_absolute_path::test_support::PathBufExt;
use core_test_support::test_path_buf;
use pretty_assertions::assert_eq;
use std::path::Path;
use std::path::PathBuf;
fn fake_shell_name() -> String {
let shell = crate::shell::Shell {
shell_type: ShellType::Bash,
shell_path: PathBuf::from("/bin/bash"),
shell_path: "/bin/bash".to_string(),
};
shell.name().to_string()
}
@@ -150,7 +149,7 @@ fn workspace_write_permission_profile_with_private_denials() -> PermissionProfil
},
FileSystemSandboxEntry {
path: FileSystemPath::Special {
value: FileSystemSpecialPath::project_roots(Some(PathBuf::from("private"))),
value: FileSystemSpecialPath::project_roots(Some("private".to_string())),
},
access: FileSystemAccessMode::Deny,
},
+1 -1
View File
@@ -410,7 +410,7 @@ fn create_filesystem_args(
// rules should keep their normal bwrap behavior, which can mask
// the first missing component to prevent creation under writable
// roots.
let project_subpath = subpath.as_path();
let project_subpath = Path::new(subpath);
if project_subpath != Path::new(".git")
&& project_subpath != Path::new(".agents")
&& project_subpath != Path::new(".codex")
+5 -5
View File
@@ -143,7 +143,7 @@ pub enum FileSystemSpecialPath {
ProjectRoots {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
subpath: Option<PathBuf>,
subpath: Option<String>,
},
Tmpdir,
SlashTmp,
@@ -159,16 +159,16 @@ pub enum FileSystemSpecialPath {
path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
subpath: Option<PathBuf>,
subpath: Option<String>,
},
}
impl FileSystemSpecialPath {
pub fn project_roots(subpath: Option<PathBuf>) -> Self {
pub fn project_roots(subpath: Option<String>) -> Self {
Self::ProjectRoots { subpath }
}
pub fn unknown(path: impl Into<String>, subpath: Option<PathBuf>) -> Self {
pub fn unknown(path: impl Into<String>, subpath: Option<String>) -> Self {
Self::Unknown {
path: path.into(),
subpath,
@@ -1712,7 +1712,7 @@ fn legacy_runtime_file_system_policy_for_cwd(
fn append_default_read_only_project_root_subpath_if_no_explicit_rule(
entries: &mut Vec<FileSystemSandboxEntry>,
subpath: impl Into<PathBuf>,
subpath: impl Into<String>,
) {
append_default_read_only_entry_if_no_explicit_rule(
entries,
@@ -1028,9 +1028,9 @@ fn special_path_label(value: &FileSystemSpecialPath) -> String {
}
}
fn path_label(base: &str, subpath: &Option<PathBuf>) -> String {
fn path_label(base: &str, subpath: &Option<String>) -> String {
match subpath {
Some(subpath) => format!("{base}/{}", subpath.display()),
Some(subpath) => format!("{base}/{subpath}"),
None => base.to_string(),
}
}