Run exec-server fs operations through sandbox helper (#17294)

## Summary
- run exec-server filesystem RPCs requiring sandboxing through a
`codex-fs` arg0 helper over stdin/stdout
- keep direct local filesystem execution for `DangerFullAccess` and
external sandbox policies
- remove the standalone exec-server binary path in favor of top-level
arg0 dispatch/runtime paths
- add sandbox escape regression coverage for local and remote filesystem
paths

## Validation
- `just fmt`
- `git diff --check`
- remote devbox: `cd codex-rs && bazel test --bes_backend=
--bes_results_url= //codex-rs/exec-server:all` (6/6 passed)

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
starr-openai
2026-04-12 18:36:03 -07:00
committed by GitHub
parent 7c1e41c8b6
commit d626dc3895
52 changed files with 2313 additions and 895 deletions

View File

@@ -1,7 +1,6 @@
use async_trait::async_trait;
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
use codex_protocol::protocol::SandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
use tokio::io;
use tracing::trace;
@@ -13,6 +12,7 @@ use crate::ExecServerError;
use crate::ExecutorFileSystem;
use crate::FileMetadata;
use crate::FileSystemResult;
use crate::FileSystemSandboxContext;
use crate::ReadDirectoryEntry;
use crate::RemoveOptions;
use crate::protocol::FsCopyParams;
@@ -40,13 +40,17 @@ impl RemoteFileSystem {
#[async_trait]
impl ExecutorFileSystem for RemoteFileSystem {
async fn read_file(&self, path: &AbsolutePathBuf) -> FileSystemResult<Vec<u8>> {
async fn read_file(
&self,
path: &AbsolutePathBuf,
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<Vec<u8>> {
trace!("remote fs read_file");
let response = self
.client
.fs_read_file(FsReadFileParams {
path: path.clone(),
sandbox_policy: None,
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;
@@ -58,53 +62,18 @@ impl ExecutorFileSystem for RemoteFileSystem {
})
}
async fn read_file_with_sandbox_policy(
async fn write_file(
&self,
path: &AbsolutePathBuf,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<Vec<u8>> {
trace!("remote fs read_file_with_sandbox_policy");
let response = self
.client
.fs_read_file(FsReadFileParams {
path: path.clone(),
sandbox_policy: sandbox_policy.cloned(),
})
.await
.map_err(map_remote_error)?;
STANDARD.decode(response.data_base64).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("remote fs/readFile returned invalid base64 dataBase64: {err}"),
)
})
}
async fn write_file(&self, path: &AbsolutePathBuf, contents: Vec<u8>) -> FileSystemResult<()> {
contents: Vec<u8>,
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<()> {
trace!("remote fs write_file");
self.client
.fs_write_file(FsWriteFileParams {
path: path.clone(),
data_base64: STANDARD.encode(contents),
sandbox_policy: None,
})
.await
.map_err(map_remote_error)?;
Ok(())
}
async fn write_file_with_sandbox_policy(
&self,
path: &AbsolutePathBuf,
contents: Vec<u8>,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<()> {
trace!("remote fs write_file_with_sandbox_policy");
self.client
.fs_write_file(FsWriteFileParams {
path: path.clone(),
data_base64: STANDARD.encode(contents),
sandbox_policy: sandbox_policy.cloned(),
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;
@@ -115,66 +84,31 @@ impl ExecutorFileSystem for RemoteFileSystem {
&self,
path: &AbsolutePathBuf,
options: CreateDirectoryOptions,
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<()> {
trace!("remote fs create_directory");
self.client
.fs_create_directory(FsCreateDirectoryParams {
path: path.clone(),
recursive: Some(options.recursive),
sandbox_policy: None,
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;
Ok(())
}
async fn create_directory_with_sandbox_policy(
async fn get_metadata(
&self,
path: &AbsolutePathBuf,
create_directory_options: CreateDirectoryOptions,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<()> {
trace!("remote fs create_directory_with_sandbox_policy");
self.client
.fs_create_directory(FsCreateDirectoryParams {
path: path.clone(),
recursive: Some(create_directory_options.recursive),
sandbox_policy: sandbox_policy.cloned(),
})
.await
.map_err(map_remote_error)?;
Ok(())
}
async fn get_metadata(&self, path: &AbsolutePathBuf) -> FileSystemResult<FileMetadata> {
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<FileMetadata> {
trace!("remote fs get_metadata");
let response = self
.client
.fs_get_metadata(FsGetMetadataParams {
path: path.clone(),
sandbox_policy: None,
})
.await
.map_err(map_remote_error)?;
Ok(FileMetadata {
is_directory: response.is_directory,
is_file: response.is_file,
created_at_ms: response.created_at_ms,
modified_at_ms: response.modified_at_ms,
})
}
async fn get_metadata_with_sandbox_policy(
&self,
path: &AbsolutePathBuf,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<FileMetadata> {
trace!("remote fs get_metadata_with_sandbox_policy");
let response = self
.client
.fs_get_metadata(FsGetMetadataParams {
path: path.clone(),
sandbox_policy: sandbox_policy.cloned(),
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;
@@ -189,13 +123,14 @@ impl ExecutorFileSystem for RemoteFileSystem {
async fn read_directory(
&self,
path: &AbsolutePathBuf,
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<Vec<ReadDirectoryEntry>> {
trace!("remote fs read_directory");
let response = self
.client
.fs_read_directory(FsReadDirectoryParams {
path: path.clone(),
sandbox_policy: None,
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;
@@ -210,58 +145,19 @@ impl ExecutorFileSystem for RemoteFileSystem {
.collect())
}
async fn read_directory_with_sandbox_policy(
async fn remove(
&self,
path: &AbsolutePathBuf,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<Vec<ReadDirectoryEntry>> {
trace!("remote fs read_directory_with_sandbox_policy");
let response = self
.client
.fs_read_directory(FsReadDirectoryParams {
path: path.clone(),
sandbox_policy: sandbox_policy.cloned(),
})
.await
.map_err(map_remote_error)?;
Ok(response
.entries
.into_iter()
.map(|entry| ReadDirectoryEntry {
file_name: entry.file_name,
is_directory: entry.is_directory,
is_file: entry.is_file,
})
.collect())
}
async fn remove(&self, path: &AbsolutePathBuf, options: RemoveOptions) -> FileSystemResult<()> {
options: RemoveOptions,
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<()> {
trace!("remote fs remove");
self.client
.fs_remove(FsRemoveParams {
path: path.clone(),
recursive: Some(options.recursive),
force: Some(options.force),
sandbox_policy: None,
})
.await
.map_err(map_remote_error)?;
Ok(())
}
async fn remove_with_sandbox_policy(
&self,
path: &AbsolutePathBuf,
remove_options: RemoveOptions,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<()> {
trace!("remote fs remove_with_sandbox_policy");
self.client
.fs_remove(FsRemoveParams {
path: path.clone(),
recursive: Some(remove_options.recursive),
force: Some(remove_options.force),
sandbox_policy: sandbox_policy.cloned(),
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;
@@ -273,6 +169,7 @@ impl ExecutorFileSystem for RemoteFileSystem {
source_path: &AbsolutePathBuf,
destination_path: &AbsolutePathBuf,
options: CopyOptions,
sandbox: Option<&FileSystemSandboxContext>,
) -> FileSystemResult<()> {
trace!("remote fs copy");
self.client
@@ -280,27 +177,7 @@ impl ExecutorFileSystem for RemoteFileSystem {
source_path: source_path.clone(),
destination_path: destination_path.clone(),
recursive: options.recursive,
sandbox_policy: None,
})
.await
.map_err(map_remote_error)?;
Ok(())
}
async fn copy_with_sandbox_policy(
&self,
source_path: &AbsolutePathBuf,
destination_path: &AbsolutePathBuf,
copy_options: CopyOptions,
sandbox_policy: Option<&SandboxPolicy>,
) -> FileSystemResult<()> {
trace!("remote fs copy_with_sandbox_policy");
self.client
.fs_copy(FsCopyParams {
source_path: source_path.clone(),
destination_path: destination_path.clone(),
recursive: copy_options.recursive,
sandbox_policy: sandbox_policy.cloned(),
sandbox: sandbox.cloned(),
})
.await
.map_err(map_remote_error)?;