mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Add a bounded filesystem walk RPC (#29841)
Stack 1 of 3. Follow-ups: #29842 and #29844. ## What changes Adds a general bounded `fs/walk` operation to the exec server. The operation returns file and directory entries plus recoverable per-path errors. It skips symlinks, preserves the existing filesystem sandbox routing, and enforces depth, directory, entry, and response-size limits. This PR only defines and wires the filesystem operation. It does not change any callers yet.
This commit is contained in:
@@ -58,6 +58,7 @@ use crate::protocol::FS_READ_BLOCK_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_WALK_METHOD;
|
||||
use crate::protocol::FS_WRITE_FILE_METHOD;
|
||||
use crate::protocol::FsCanonicalizeParams;
|
||||
use crate::protocol::FsCanonicalizeResponse;
|
||||
@@ -79,6 +80,8 @@ use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsReadFileResponse;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsRemoveResponse;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWalkResponse;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
use crate::protocol::FsWriteFileResponse;
|
||||
use crate::protocol::HTTP_REQUEST_BODY_DELTA_METHOD;
|
||||
@@ -620,6 +623,10 @@ impl ExecServerClient {
|
||||
self.call(FS_READ_DIRECTORY_METHOD, ¶ms).await
|
||||
}
|
||||
|
||||
pub async fn fs_walk(&self, params: FsWalkParams) -> Result<FsWalkResponse, ExecServerError> {
|
||||
self.call(FS_WALK_METHOD, ¶ms).await
|
||||
}
|
||||
|
||||
pub async fn fs_remove(
|
||||
&self,
|
||||
params: FsRemoveParams,
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::protocol::FS_GET_METADATA_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_WALK_METHOD;
|
||||
use crate::protocol::FS_WRITE_FILE_METHOD;
|
||||
use crate::protocol::FsCanonicalizeParams;
|
||||
use crate::protocol::FsCanonicalizeResponse;
|
||||
@@ -33,6 +34,8 @@ use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsReadFileResponse;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsRemoveResponse;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWalkResponse;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
use crate::protocol::FsWriteFileResponse;
|
||||
use crate::rpc::internal_error;
|
||||
@@ -56,6 +59,8 @@ pub(crate) enum FsHelperRequest {
|
||||
Canonicalize(FsCanonicalizeParams),
|
||||
#[serde(rename = "fs/readDirectory")]
|
||||
ReadDirectory(FsReadDirectoryParams),
|
||||
#[serde(rename = "fs/walk")]
|
||||
Walk(FsWalkParams),
|
||||
#[serde(rename = "fs/remove")]
|
||||
Remove(FsRemoveParams),
|
||||
#[serde(rename = "fs/copy")]
|
||||
@@ -84,6 +89,8 @@ pub(crate) enum FsHelperPayload {
|
||||
Canonicalize(FsCanonicalizeResponse),
|
||||
#[serde(rename = "fs/readDirectory")]
|
||||
ReadDirectory(FsReadDirectoryResponse),
|
||||
#[serde(rename = "fs/walk")]
|
||||
Walk(FsWalkResponse),
|
||||
#[serde(rename = "fs/remove")]
|
||||
Remove(FsRemoveResponse),
|
||||
#[serde(rename = "fs/copy")]
|
||||
@@ -99,6 +106,7 @@ impl FsHelperPayload {
|
||||
Self::GetMetadata(_) => FS_GET_METADATA_METHOD,
|
||||
Self::Canonicalize(_) => FS_CANONICALIZE_METHOD,
|
||||
Self::ReadDirectory(_) => FS_READ_DIRECTORY_METHOD,
|
||||
Self::Walk(_) => FS_WALK_METHOD,
|
||||
Self::Remove(_) => FS_REMOVE_METHOD,
|
||||
Self::Copy(_) => FS_COPY_METHOD,
|
||||
}
|
||||
@@ -162,6 +170,13 @@ impl FsHelperPayload {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expect_walk(self) -> Result<FsWalkResponse, JSONRPCErrorError> {
|
||||
match self {
|
||||
Self::Walk(response) => Ok(response),
|
||||
other => Err(unexpected_response(FS_WALK_METHOD, other.operation())),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expect_remove(self) -> Result<FsRemoveResponse, JSONRPCErrorError> {
|
||||
match self {
|
||||
Self::Remove(response) => Ok(response),
|
||||
@@ -263,6 +278,13 @@ pub(crate) async fn run_direct_request(
|
||||
entries,
|
||||
}))
|
||||
}
|
||||
FsHelperRequest::Walk(params) => {
|
||||
let outcome = file_system
|
||||
.walk(¶ms.path, params.options, /*sandbox*/ None)
|
||||
.await
|
||||
.map_err(map_fs_error)?;
|
||||
Ok(FsHelperPayload::Walk(outcome))
|
||||
}
|
||||
FsHelperRequest::Remove(params) => {
|
||||
file_system
|
||||
.remove(
|
||||
|
||||
@@ -51,6 +51,11 @@ pub use codex_file_system::FileSystemResult;
|
||||
pub use codex_file_system::FileSystemSandboxContext;
|
||||
pub use codex_file_system::ReadDirectoryEntry;
|
||||
pub use codex_file_system::RemoveOptions;
|
||||
pub use codex_file_system::WalkEntry;
|
||||
pub use codex_file_system::WalkEntryKind;
|
||||
pub use codex_file_system::WalkError;
|
||||
pub use codex_file_system::WalkOptions;
|
||||
pub use codex_file_system::WalkOutcome;
|
||||
pub use environment::CODEX_EXEC_SERVER_NOISE_AUTH_TOKEN_ENV_VAR;
|
||||
pub use environment::CODEX_EXEC_SERVER_NOISE_CHATGPT_ACCOUNT_ID_ENV_VAR;
|
||||
pub use environment::CODEX_EXEC_SERVER_NOISE_ENVIRONMENT_ID_ENV_VAR;
|
||||
@@ -113,6 +118,8 @@ pub use protocol::FsReadFileParams;
|
||||
pub use protocol::FsReadFileResponse;
|
||||
pub use protocol::FsRemoveParams;
|
||||
pub use protocol::FsRemoveResponse;
|
||||
pub use protocol::FsWalkParams;
|
||||
pub use protocol::FsWalkResponse;
|
||||
pub use protocol::FsWriteFileParams;
|
||||
pub use protocol::FsWriteFileResponse;
|
||||
pub use protocol::HttpHeader;
|
||||
|
||||
@@ -22,6 +22,8 @@ use crate::FileSystemResult;
|
||||
use crate::FileSystemSandboxContext;
|
||||
use crate::ReadDirectoryEntry;
|
||||
use crate::RemoveOptions;
|
||||
use crate::WalkOptions;
|
||||
use crate::WalkOutcome;
|
||||
use crate::regular_file;
|
||||
use crate::sandboxed_file_system::SandboxedFileSystem;
|
||||
|
||||
@@ -170,6 +172,16 @@ impl LocalFileSystem {
|
||||
file_system.read_directory(path, sandbox).await
|
||||
}
|
||||
|
||||
async fn walk(
|
||||
&self,
|
||||
path: &PathUri,
|
||||
options: WalkOptions,
|
||||
sandbox: Option<&FileSystemSandboxContext>,
|
||||
) -> FileSystemResult<WalkOutcome> {
|
||||
let (file_system, sandbox) = self.file_system_for(sandbox)?;
|
||||
file_system.walk(path, options, sandbox).await
|
||||
}
|
||||
|
||||
async fn remove(
|
||||
&self,
|
||||
path: &PathUri,
|
||||
@@ -255,6 +267,15 @@ impl ExecutorFileSystem for LocalFileSystem {
|
||||
Box::pin(LocalFileSystem::read_directory(self, path, sandbox))
|
||||
}
|
||||
|
||||
fn walk<'a>(
|
||||
&'a self,
|
||||
path: &'a PathUri,
|
||||
options: WalkOptions,
|
||||
sandbox: Option<&'a FileSystemSandboxContext>,
|
||||
) -> ExecutorFileSystemFuture<'a, WalkOutcome> {
|
||||
Box::pin(LocalFileSystem::walk(self, path, options, sandbox))
|
||||
}
|
||||
|
||||
fn remove<'a>(
|
||||
&'a self,
|
||||
path: &'a PathUri,
|
||||
|
||||
@@ -15,6 +15,8 @@ use crate::FileSystemResult;
|
||||
use crate::FileSystemSandboxContext;
|
||||
use crate::ReadDirectoryEntry;
|
||||
use crate::RemoveOptions;
|
||||
use crate::WalkOptions;
|
||||
use crate::WalkOutcome;
|
||||
use crate::client::LazyRemoteExecServerClient;
|
||||
use crate::protocol::FsCanonicalizeParams;
|
||||
use crate::protocol::FsCopyParams;
|
||||
@@ -23,6 +25,7 @@ use crate::protocol::FsGetMetadataParams;
|
||||
use crate::protocol::FsReadDirectoryParams;
|
||||
use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
|
||||
const INVALID_REQUEST_ERROR_CODE: i64 = -32600;
|
||||
@@ -183,6 +186,25 @@ impl RemoteFileSystem {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn walk(
|
||||
&self,
|
||||
path: &PathUri,
|
||||
options: WalkOptions,
|
||||
sandbox: Option<&FileSystemSandboxContext>,
|
||||
) -> FileSystemResult<WalkOutcome> {
|
||||
trace!("remote fs walk");
|
||||
let client = self.client.get().await.map_err(map_remote_error)?;
|
||||
let response = client
|
||||
.fs_walk(FsWalkParams {
|
||||
path: path.clone(),
|
||||
options,
|
||||
sandbox: remote_sandbox_context(sandbox),
|
||||
})
|
||||
.await
|
||||
.map_err(map_remote_error)?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn remove(
|
||||
&self,
|
||||
path: &PathUri,
|
||||
@@ -286,6 +308,15 @@ impl ExecutorFileSystem for RemoteFileSystem {
|
||||
Box::pin(RemoteFileSystem::read_directory(self, path, sandbox))
|
||||
}
|
||||
|
||||
fn walk<'a>(
|
||||
&'a self,
|
||||
path: &'a PathUri,
|
||||
options: WalkOptions,
|
||||
sandbox: Option<&'a FileSystemSandboxContext>,
|
||||
) -> ExecutorFileSystemFuture<'a, WalkOutcome> {
|
||||
Box::pin(RemoteFileSystem::walk(self, path, options, sandbox))
|
||||
}
|
||||
|
||||
fn remove<'a>(
|
||||
&'a self,
|
||||
path: &'a PathUri,
|
||||
|
||||
@@ -15,6 +15,8 @@ use crate::FileSystemResult;
|
||||
use crate::FileSystemSandboxContext;
|
||||
use crate::ReadDirectoryEntry;
|
||||
use crate::RemoveOptions;
|
||||
use crate::WalkOptions;
|
||||
use crate::WalkOutcome;
|
||||
use crate::fs_helper::FsHelperPayload;
|
||||
use crate::fs_helper::FsHelperRequest;
|
||||
use crate::fs_sandbox::FileSystemSandboxRunner;
|
||||
@@ -25,6 +27,7 @@ use crate::protocol::FsGetMetadataParams;
|
||||
use crate::protocol::FsReadDirectoryParams;
|
||||
use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -200,6 +203,29 @@ impl SandboxedFileSystem {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn walk(
|
||||
&self,
|
||||
path: &PathUri,
|
||||
options: WalkOptions,
|
||||
sandbox: Option<&FileSystemSandboxContext>,
|
||||
) -> FileSystemResult<WalkOutcome> {
|
||||
let sandbox = require_platform_sandbox(sandbox)?;
|
||||
validate_native_path(path)?;
|
||||
let response = self
|
||||
.run_sandboxed(
|
||||
sandbox,
|
||||
FsHelperRequest::Walk(FsWalkParams {
|
||||
path: path.clone(),
|
||||
options,
|
||||
sandbox: None,
|
||||
}),
|
||||
)
|
||||
.await?
|
||||
.expect_walk()
|
||||
.map_err(map_sandbox_error)?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn remove(
|
||||
&self,
|
||||
path: &PathUri,
|
||||
@@ -317,6 +343,15 @@ impl ExecutorFileSystem for SandboxedFileSystem {
|
||||
Box::pin(SandboxedFileSystem::read_directory(self, path, sandbox))
|
||||
}
|
||||
|
||||
fn walk<'a>(
|
||||
&'a self,
|
||||
path: &'a PathUri,
|
||||
options: WalkOptions,
|
||||
sandbox: Option<&'a FileSystemSandboxContext>,
|
||||
) -> ExecutorFileSystemFuture<'a, WalkOutcome> {
|
||||
Box::pin(SandboxedFileSystem::walk(self, path, options, sandbox))
|
||||
}
|
||||
|
||||
fn remove<'a>(
|
||||
&'a self,
|
||||
path: &'a PathUri,
|
||||
|
||||
@@ -33,6 +33,8 @@ use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsReadFileResponse;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsRemoveResponse;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWalkResponse;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
use crate::protocol::FsWriteFileResponse;
|
||||
use crate::rpc::internal_error;
|
||||
@@ -198,6 +200,16 @@ impl FileSystemHandler {
|
||||
Ok(FsReadDirectoryResponse { entries })
|
||||
}
|
||||
|
||||
pub(crate) async fn walk(
|
||||
&self,
|
||||
params: FsWalkParams,
|
||||
) -> Result<FsWalkResponse, JSONRPCErrorError> {
|
||||
self.file_system
|
||||
.walk(¶ms.path, params.options, params.sandbox.as_ref())
|
||||
.await
|
||||
.map_err(map_fs_error)
|
||||
}
|
||||
|
||||
pub(crate) async fn remove(
|
||||
&self,
|
||||
params: FsRemoveParams,
|
||||
|
||||
@@ -37,6 +37,8 @@ use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsReadFileResponse;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsRemoveResponse;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWalkResponse;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
use crate::protocol::FsWriteFileResponse;
|
||||
use crate::protocol::HttpRequestParams;
|
||||
@@ -311,6 +313,14 @@ impl ExecServerHandler {
|
||||
self.file_system.read_directory(params).await
|
||||
}
|
||||
|
||||
pub(crate) async fn fs_walk(
|
||||
&self,
|
||||
params: FsWalkParams,
|
||||
) -> Result<FsWalkResponse, JSONRPCErrorError> {
|
||||
self.require_initialized_for("filesystem")?;
|
||||
self.file_system.walk(params).await
|
||||
}
|
||||
|
||||
pub(crate) async fn fs_remove(
|
||||
&self,
|
||||
params: FsRemoveParams,
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::protocol::FS_READ_BLOCK_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_WALK_METHOD;
|
||||
use crate::protocol::FS_WRITE_FILE_METHOD;
|
||||
use crate::protocol::FsCanonicalizeParams;
|
||||
use crate::protocol::FsCloseParams;
|
||||
@@ -28,6 +29,7 @@ use crate::protocol::FsReadBlockParams;
|
||||
use crate::protocol::FsReadDirectoryParams;
|
||||
use crate::protocol::FsReadFileParams;
|
||||
use crate::protocol::FsRemoveParams;
|
||||
use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
use crate::protocol::HTTP_REQUEST_METHOD;
|
||||
use crate::protocol::HttpRequestParams;
|
||||
@@ -147,6 +149,12 @@ pub(crate) fn build_router() -> RpcRouter<ExecServerHandler> {
|
||||
handler.fs_read_directory(params).await
|
||||
},
|
||||
);
|
||||
router.request(
|
||||
FS_WALK_METHOD,
|
||||
|handler: Arc<ExecServerHandler>, params: FsWalkParams| async move {
|
||||
handler.fs_walk(params).await
|
||||
},
|
||||
);
|
||||
router.request(
|
||||
FS_REMOVE_METHOD,
|
||||
|handler: Arc<ExecServerHandler>, params: FsRemoveParams| async move {
|
||||
|
||||
Reference in New Issue
Block a user