diff --git a/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs b/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs index 932e44e267..d1d7c680f6 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/permissions.rs @@ -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, + subpath: Option, }, Tmpdir, SlashTmp, Unknown { path: String, - subpath: Option, + subpath: Option, }, } @@ -259,10 +259,21 @@ impl From 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 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), + }, } } } diff --git a/codex-rs/core/src/config/permissions.rs b/codex-rs/core/src/config/permissions.rs index 9c6d3ed725..88ee6f4e77 100644 --- a/codex-rs/core/src/config/permissions.rs +++ b/codex-rs/core/src/config/permissions.rs @@ -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, 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." diff --git a/codex-rs/core/src/context/environment_context.rs b/codex-rs/core/src/context/environment_context.rs index 2f795a8ea3..2117231f08 100644 --- a/codex-rs/core/src/context/environment_context.rs +++ b/codex-rs/core/src/context/environment_context.rs @@ -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) -> String { +fn render_special_path_with_subpath(base: &str, subpath: &Option) -> String { match subpath { - Some(subpath) => format!("{base}/{}", subpath.display()), + Some(subpath) => format!("{base}/{subpath}"), None => base.to_string(), } } diff --git a/codex-rs/core/src/context/world_state/environment_render_tests.rs b/codex-rs/core/src/context/world_state/environment_render_tests.rs index 70122586ed..3093680676 100644 --- a/codex-rs/core/src/context/world_state/environment_render_tests.rs +++ b/codex-rs/core/src/context/world_state/environment_render_tests.rs @@ -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, }, diff --git a/codex-rs/linux-sandbox/src/bwrap.rs b/codex-rs/linux-sandbox/src/bwrap.rs index 25a3814fb5..5c72a98d7c 100644 --- a/codex-rs/linux-sandbox/src/bwrap.rs +++ b/codex-rs/linux-sandbox/src/bwrap.rs @@ -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") diff --git a/codex-rs/protocol/src/permissions.rs b/codex-rs/protocol/src/permissions.rs index 5573f488e8..eba2f0e0aa 100644 --- a/codex-rs/protocol/src/permissions.rs +++ b/codex-rs/protocol/src/permissions.rs @@ -143,7 +143,7 @@ pub enum FileSystemSpecialPath { ProjectRoots { #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] - subpath: Option, + subpath: Option, }, Tmpdir, SlashTmp, @@ -159,16 +159,16 @@ pub enum FileSystemSpecialPath { path: String, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] - subpath: Option, + subpath: Option, }, } impl FileSystemSpecialPath { - pub fn project_roots(subpath: Option) -> Self { + pub fn project_roots(subpath: Option) -> Self { Self::ProjectRoots { subpath } } - pub fn unknown(path: impl Into, subpath: Option) -> Self { + pub fn unknown(path: impl Into, subpath: Option) -> 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, - subpath: impl Into, + subpath: impl Into, ) { append_default_read_only_entry_if_no_explicit_rule( entries, diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs index 3cc135da74..8a13667ed5 100644 --- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs +++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs @@ -1028,9 +1028,9 @@ fn special_path_label(value: &FileSystemSpecialPath) -> String { } } -fn path_label(base: &str, subpath: &Option) -> String { +fn path_label(base: &str, subpath: &Option) -> String { match subpath { - Some(subpath) => format!("{base}/{}", subpath.display()), + Some(subpath) => format!("{base}/{subpath}"), None => base.to_string(), } }