[codex] migrate ExecutorFileSystem paths to PathUri (#27424)

## Why

We're moving exec-server to use PathUri for its internal path
representations.

## What

Move `ExecutorFileSystem` APIs to use `PathUri` instead of
`AbsolutePathBuf`. Future changes will convert higher-level parts of
exec-server.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-11 11:44:18 -07:00
committed by GitHub
Unverified
parent 4a05d3b282
commit b2a4e3be27
52 changed files with 1126 additions and 495 deletions
@@ -3,6 +3,7 @@ use std::io;
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_utils_path_uri::PathUri;
use crate::CopyOptions;
use crate::CreateDirectoryOptions;
@@ -52,9 +53,10 @@ impl FileSystemHandler {
&self,
params: FsReadFileParams,
) -> Result<FsReadFileResponse, JSONRPCErrorError> {
let path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
let bytes = self
.file_system
.read_file(&params.path, params.sandbox.as_ref())
.read_file(&path, params.sandbox.as_ref())
.await
.map_err(map_fs_error)?;
Ok(FsReadFileResponse {
@@ -66,13 +68,14 @@ impl FileSystemHandler {
&self,
params: FsWriteFileParams,
) -> Result<FsWriteFileResponse, JSONRPCErrorError> {
let path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
let bytes = STANDARD.decode(params.data_base64).map_err(|err| {
invalid_request(format!(
"{FS_WRITE_FILE_METHOD} requires valid base64 dataBase64: {err}"
))
})?;
self.file_system
.write_file(&params.path, bytes, params.sandbox.as_ref())
.write_file(&path, bytes, params.sandbox.as_ref())
.await
.map_err(map_fs_error)?;
Ok(FsWriteFileResponse {})
@@ -83,9 +86,10 @@ impl FileSystemHandler {
params: FsCreateDirectoryParams,
) -> Result<FsCreateDirectoryResponse, JSONRPCErrorError> {
let recursive = params.recursive.unwrap_or(true);
let path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
self.file_system
.create_directory(
&params.path,
&path,
CreateDirectoryOptions { recursive },
params.sandbox.as_ref(),
)
@@ -98,9 +102,10 @@ impl FileSystemHandler {
&self,
params: FsGetMetadataParams,
) -> Result<FsGetMetadataResponse, JSONRPCErrorError> {
let path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
let metadata = self
.file_system
.get_metadata(&params.path, params.sandbox.as_ref())
.get_metadata(&path, params.sandbox.as_ref())
.await
.map_err(map_fs_error)?;
Ok(FsGetMetadataResponse {
@@ -116,11 +121,13 @@ impl FileSystemHandler {
&self,
params: FsCanonicalizeParams,
) -> Result<FsCanonicalizeResponse, JSONRPCErrorError> {
let requested_path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
let path = self
.file_system
.canonicalize(&params.path, params.sandbox.as_ref())
.canonicalize(&requested_path, params.sandbox.as_ref())
.await
.map_err(map_fs_error)?;
let path = path.to_abs_path().map_err(map_fs_error)?;
Ok(FsCanonicalizeResponse { path })
}
@@ -128,11 +135,8 @@ impl FileSystemHandler {
&self,
params: FsJoinParams,
) -> Result<FsJoinResponse, JSONRPCErrorError> {
let path = self
.file_system
.join(&params.base_path, &params.path)
.await
.map_err(map_fs_error)?;
// TODO(anp): remove and migrate callers to PathUri.
let path = params.base_path.join(params.path);
Ok(FsJoinResponse { path })
}
@@ -140,11 +144,8 @@ impl FileSystemHandler {
&self,
params: FsParentParams,
) -> Result<FsParentResponse, JSONRPCErrorError> {
let path = self
.file_system
.parent(&params.path)
.await
.map_err(map_fs_error)?;
// TODO(anp): remove and migrate callers to PathUri.
let path = params.path.parent();
Ok(FsParentResponse { path })
}
@@ -152,9 +153,10 @@ impl FileSystemHandler {
&self,
params: FsReadDirectoryParams,
) -> Result<FsReadDirectoryResponse, JSONRPCErrorError> {
let path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
let entries = self
.file_system
.read_directory(&params.path, params.sandbox.as_ref())
.read_directory(&path, params.sandbox.as_ref())
.await
.map_err(map_fs_error)?
.into_iter()
@@ -173,9 +175,10 @@ impl FileSystemHandler {
) -> Result<FsRemoveResponse, JSONRPCErrorError> {
let recursive = params.recursive.unwrap_or(true);
let force = params.force.unwrap_or(true);
let path = PathUri::from_abs_path(&params.path).map_err(map_fs_error)?;
self.file_system
.remove(
&params.path,
&path,
RemoveOptions { recursive, force },
params.sandbox.as_ref(),
)
@@ -188,10 +191,13 @@ impl FileSystemHandler {
&self,
params: FsCopyParams,
) -> Result<FsCopyResponse, JSONRPCErrorError> {
let source_path = PathUri::from_abs_path(&params.source_path).map_err(map_fs_error)?;
let destination_path =
PathUri::from_abs_path(&params.destination_path).map_err(map_fs_error)?;
self.file_system
.copy(
&params.source_path,
&params.destination_path,
&source_path,
&destination_path,
CopyOptions {
recursive: params.recursive,
},
@@ -262,6 +268,24 @@ mod tests {
.await
.expect("write file");
let canonicalized = handler
.canonicalize(FsCanonicalizeParams {
path: path.clone(),
sandbox: Some(FileSystemSandboxContext::from_legacy_sandbox_policy(
sandbox_policy.clone(),
sandbox_cwd.clone(),
)),
})
.await
.expect("canonicalize file");
assert_eq!(
canonicalized.path,
AbsolutePathBuf::from_absolute_path(
std::fs::canonicalize(path.as_path()).expect("canonical path"),
)
.expect("absolute canonical path"),
);
let response = handler
.read_file(FsReadFileParams {
path,
@@ -276,4 +300,34 @@ mod tests {
assert_eq!(response.data_base64, STANDARD.encode("ok"));
}
}
#[tokio::test]
async fn protocol_join_and_parent_remain_native_path_operations() {
let temp_dir = tempfile::tempdir().expect("tempdir");
let runtime_paths = ExecServerRuntimePaths::new(
std::env::current_exe().expect("current exe"),
/*codex_linux_sandbox_exe*/ None,
)
.expect("runtime paths");
let handler = FileSystemHandler::new(runtime_paths);
let base_path =
AbsolutePathBuf::from_absolute_path(temp_dir.path()).expect("absolute tempdir");
let joined = handler
.join(FsJoinParams {
base_path: base_path.clone(),
path: "nested/file.txt".into(),
})
.await
.expect("join path");
assert_eq!(joined.path, base_path.join("nested/file.txt"));
let parent = handler
.parent(FsParentParams {
path: joined.path.clone(),
})
.await
.expect("parent path");
assert_eq!(parent.path, joined.path.parent());
}
}