exec-server: canonicalize bound filesystem paths (#25149)

## Summary
- add executor filesystem canonicalization as a bound-path operation
- route remote canonicalization through the exec-server filesystem RPC
surface
- keep path normalization attached to the filesystem that owns the path

## Stack
- 2/5 in the skills path authority stack extracted from
https://github.com/openai/codex/pull/25098
- follows merged https://github.com/openai/codex/pull/25121

## Validation
- `cd
/Users/starr/code/codex-worktrees/pr-25098-restack-review-pr1b/codex-rs
&& just fmt`
- Not run: tests/checks (not requested)
- GitHub CI pending on rewritten head
This commit is contained in:
starr-openai
2026-06-01 11:53:31 -07:00
committed by GitHub
parent f1609d9fb6
commit 53ac02356e
14 changed files with 655 additions and 1 deletions
@@ -11,12 +11,18 @@ use crate::ExecutorFileSystem;
use crate::RemoveOptions;
use crate::local_file_system::LocalFileSystem;
use crate::protocol::FS_WRITE_FILE_METHOD;
use crate::protocol::FsCanonicalizeParams;
use crate::protocol::FsCanonicalizeResponse;
use crate::protocol::FsCopyParams;
use crate::protocol::FsCopyResponse;
use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsCreateDirectoryResponse;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsGetMetadataResponse;
use crate::protocol::FsJoinParams;
use crate::protocol::FsJoinResponse;
use crate::protocol::FsParentParams;
use crate::protocol::FsParentResponse;
use crate::protocol::FsReadDirectoryEntry;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadDirectoryResponse;
@@ -106,6 +112,42 @@ impl FileSystemHandler {
})
}
pub(crate) async fn canonicalize(
&self,
params: FsCanonicalizeParams,
) -> Result<FsCanonicalizeResponse, JSONRPCErrorError> {
let path = self
.file_system
.canonicalize(&params.path, params.sandbox.as_ref())
.await
.map_err(map_fs_error)?;
Ok(FsCanonicalizeResponse { path })
}
pub(crate) async fn join(
&self,
params: FsJoinParams,
) -> Result<FsJoinResponse, JSONRPCErrorError> {
let path = self
.file_system
.join(&params.base_path, &params.path)
.await
.map_err(map_fs_error)?;
Ok(FsJoinResponse { path })
}
pub(crate) async fn parent(
&self,
params: FsParentParams,
) -> Result<FsParentResponse, JSONRPCErrorError> {
let path = self
.file_system
.parent(&params.path)
.await
.map_err(map_fs_error)?;
Ok(FsParentResponse { path })
}
pub(crate) async fn read_directory(
&self,
params: FsReadDirectoryParams,
@@ -16,12 +16,18 @@ use crate::client::http_client::PendingReqwestHttpBodyStream;
use crate::client::http_client::ReqwestHttpRequestRunner;
use crate::protocol::ExecParams;
use crate::protocol::ExecResponse;
use crate::protocol::FsCanonicalizeParams;
use crate::protocol::FsCanonicalizeResponse;
use crate::protocol::FsCopyParams;
use crate::protocol::FsCopyResponse;
use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsCreateDirectoryResponse;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsGetMetadataResponse;
use crate::protocol::FsJoinParams;
use crate::protocol::FsJoinResponse;
use crate::protocol::FsParentParams;
use crate::protocol::FsParentResponse;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadDirectoryResponse;
use crate::protocol::FsReadFileParams;
@@ -240,6 +246,30 @@ impl ExecServerHandler {
self.file_system.get_metadata(params).await
}
pub(crate) async fn fs_canonicalize(
&self,
params: FsCanonicalizeParams,
) -> Result<FsCanonicalizeResponse, JSONRPCErrorError> {
self.require_initialized_for("filesystem")?;
self.file_system.canonicalize(params).await
}
pub(crate) async fn fs_join(
&self,
params: FsJoinParams,
) -> Result<FsJoinResponse, JSONRPCErrorError> {
self.require_initialized_for("filesystem")?;
self.file_system.join(params).await
}
pub(crate) async fn fs_parent(
&self,
params: FsParentParams,
) -> Result<FsParentResponse, JSONRPCErrorError> {
self.require_initialized_for("filesystem")?;
self.file_system.parent(params).await
}
pub(crate) async fn fs_read_directory(
&self,
params: FsReadDirectoryParams,
@@ -5,16 +5,22 @@ use crate::protocol::EXEC_READ_METHOD;
use crate::protocol::EXEC_TERMINATE_METHOD;
use crate::protocol::EXEC_WRITE_METHOD;
use crate::protocol::ExecParams;
use crate::protocol::FS_CANONICALIZE_METHOD;
use crate::protocol::FS_COPY_METHOD;
use crate::protocol::FS_CREATE_DIRECTORY_METHOD;
use crate::protocol::FS_GET_METADATA_METHOD;
use crate::protocol::FS_JOIN_METHOD;
use crate::protocol::FS_PARENT_METHOD;
use crate::protocol::FS_READ_DIRECTORY_METHOD;
use crate::protocol::FS_READ_FILE_METHOD;
use crate::protocol::FS_REMOVE_METHOD;
use crate::protocol::FS_WRITE_FILE_METHOD;
use crate::protocol::FsCanonicalizeParams;
use crate::protocol::FsCopyParams;
use crate::protocol::FsCreateDirectoryParams;
use crate::protocol::FsGetMetadataParams;
use crate::protocol::FsJoinParams;
use crate::protocol::FsParentParams;
use crate::protocol::FsReadDirectoryParams;
use crate::protocol::FsReadFileParams;
use crate::protocol::FsRemoveParams;
@@ -96,6 +102,24 @@ pub(crate) fn build_router() -> RpcRouter<ExecServerHandler> {
handler.fs_get_metadata(params).await
},
);
router.request(
FS_CANONICALIZE_METHOD,
|handler: Arc<ExecServerHandler>, params: FsCanonicalizeParams| async move {
handler.fs_canonicalize(params).await
},
);
router.request(
FS_JOIN_METHOD,
|handler: Arc<ExecServerHandler>, params: FsJoinParams| async move {
handler.fs_join(params).await
},
);
router.request(
FS_PARENT_METHOD,
|handler: Arc<ExecServerHandler>, params: FsParentParams| async move {
handler.fs_parent(params).await
},
);
router.request(
FS_READ_DIRECTORY_METHOD,
|handler: Arc<ExecServerHandler>, params: FsReadDirectoryParams| async move {