Refactor exec-server filesystem API into codex-file-system (#19892)

## Summary
- Extracted the shared filesystem types and `ExecutorFileSystem` trait
into a new `codex-file-system` crate
- Switched `codex-config` and `codex-git-utils` to depend on that crate
instead of `codex-exec-server`
- Kept `codex-exec-server` re-exporting the same API for existing
callers

## Testing
- Ran `cargo test -p codex-file-system`
- Ran `cargo test -p codex-git-utils`
- Ran `cargo test -p codex-config`
- Ran `cargo test -p codex-exec-server`
- Ran `just fix -p codex-file-system`, `just fix -p codex-git-utils`,
`just fix -p codex-config`, `just fix -p codex-exec-server`
- Ran `just fmt`
- Updated and verified the Bazel module lockfile
This commit is contained in:
Michael Zeng
2026-04-27 17:43:15 -07:00
committed by GitHub
Unverified
parent 2f3b5ed81a
commit a3350de855
14 changed files with 61 additions and 24 deletions
+13 -2
View File
@@ -2288,9 +2288,9 @@ dependencies = [
"async-trait",
"base64 0.22.1",
"codex-app-server-protocol",
"codex-exec-server",
"codex-execpolicy",
"codex-features",
"codex-file-system",
"codex-git-utils",
"codex-model-provider-info",
"codex-network-proxy",
@@ -2609,6 +2609,7 @@ dependencies = [
"bytes",
"codex-app-server-protocol",
"codex-client",
"codex-file-system",
"codex-protocol",
"codex-sandboxing",
"codex-test-binary-support",
@@ -2719,6 +2720,16 @@ dependencies = [
"tokio",
]
[[package]]
name = "codex-file-system"
version = "0.0.0"
dependencies = [
"async-trait",
"codex-protocol",
"codex-utils-absolute-path",
"serde",
]
[[package]]
name = "codex-git-utils"
version = "0.0.0"
@@ -2726,7 +2737,7 @@ dependencies = [
"anyhow",
"assert_matches",
"chrono",
"codex-exec-server",
"codex-file-system",
"codex-protocol",
"codex-utils-absolute-path",
"futures",
+2
View File
@@ -36,6 +36,7 @@ members = [
"hooks",
"secrets",
"exec",
"file-system",
"exec-server",
"execpolicy",
"execpolicy-legacy",
@@ -142,6 +143,7 @@ codex-core-plugins = { path = "core-plugins" }
codex-core-skills = { path = "core-skills" }
codex-device-key = { path = "device-key" }
codex-exec = { path = "exec" }
codex-file-system = { path = "file-system" }
codex-exec-server = { path = "exec-server" }
codex-execpolicy = { path = "execpolicy" }
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
+1 -1
View File
@@ -16,9 +16,9 @@ anyhow = { workspace = true }
async-trait = { workspace = true }
base64 = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-exec-server = { workspace = true }
codex-execpolicy = { workspace = true }
codex-features = { workspace = true }
codex-file-system = { workspace = true }
codex-git-utils = { workspace = true }
codex-model-provider-info = { workspace = true }
codex-network-proxy = { workspace = true }
+1 -1
View File
@@ -5,7 +5,7 @@ use super::macos::load_managed_admin_config_layer;
use crate::diagnostics::config_error_from_toml;
use crate::diagnostics::io_error_from_config_error;
use crate::state::LoaderOverrides;
use codex_exec_server::ExecutorFileSystem;
use codex_file_system::ExecutorFileSystem;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::io;
use std::path::Path;
+1 -1
View File
@@ -25,7 +25,7 @@ use crate::state::LoaderOverrides;
use crate::thread_config::ThreadConfigContext;
use crate::thread_config::ThreadConfigLoader;
use codex_app_server_protocol::ConfigLayerSource;
use codex_exec_server::ExecutorFileSystem;
use codex_file_system::ExecutorFileSystem;
use codex_git_utils::resolve_root_git_project_for_trust;
use codex_protocol::config_types::ApprovalsReviewer;
use codex_protocol::config_types::SandboxMode;
+1
View File
@@ -17,6 +17,7 @@ base64 = { workspace = true }
bytes = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-client = { workspace = true }
codex-file-system = { workspace = true }
codex-protocol = { workspace = true }
codex-sandboxing = { workspace = true }
codex-utils-absolute-path = { workspace = true }
+1 -1
View File
@@ -3,10 +3,10 @@ use std::sync::Arc;
use crate::ExecServerError;
use crate::ExecServerRuntimePaths;
use crate::ExecutorFileSystem;
use crate::HttpClient;
use crate::client::LazyRemoteExecServerClient;
use crate::client::http_client::ReqwestHttpClient;
use crate::file_system::ExecutorFileSystem;
use crate::local_file_system::LocalFileSystem;
use crate::local_process::LocalProcess;
use crate::process::ExecBackend;
+1 -3
View File
@@ -20,7 +20,6 @@ use tokio::process::Command;
use crate::ExecServerRuntimePaths;
use crate::FileSystemSandboxContext;
use crate::file_system::file_system_policy_has_cwd_dependent_entries;
use crate::fs_helper::CODEX_FS_HELPER_ARG1;
use crate::fs_helper::FsHelperPayload;
use crate::fs_helper::FsHelperRequest;
@@ -115,8 +114,7 @@ fn sandbox_cwd(sandbox: &FileSystemSandboxContext) -> Result<AbsolutePathBuf, JS
return Ok(cwd.clone());
}
let file_system_policy = sandbox.permissions.file_system_sandbox_policy();
if file_system_policy_has_cwd_dependent_entries(&file_system_policy) {
if sandbox.has_cwd_dependent_permissions() {
return Err(invalid_request(
"file system sandbox context with dynamic permissions requires cwd".to_string(),
));
+8 -9
View File
@@ -2,7 +2,6 @@ mod client;
mod client_api;
mod connection;
mod environment;
mod file_system;
mod fs_helper;
mod fs_helper_main;
mod fs_sandbox;
@@ -25,20 +24,20 @@ pub use client::http_client::ReqwestHttpClient;
pub use client_api::ExecServerClientConnectOptions;
pub use client_api::HttpClient;
pub use client_api::RemoteExecServerConnectArgs;
pub use codex_file_system::CopyOptions;
pub use codex_file_system::CreateDirectoryOptions;
pub use codex_file_system::ExecutorFileSystem;
pub use codex_file_system::FileMetadata;
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 environment::CODEX_EXEC_SERVER_URL_ENV_VAR;
pub use environment::Environment;
pub use environment::EnvironmentManager;
pub use environment::EnvironmentManagerArgs;
pub use environment::LOCAL_ENVIRONMENT_ID;
pub use environment::REMOTE_ENVIRONMENT_ID;
pub use file_system::CopyOptions;
pub use file_system::CreateDirectoryOptions;
pub use file_system::ExecutorFileSystem;
pub use file_system::FileMetadata;
pub use file_system::FileSystemResult;
pub use file_system::FileSystemSandboxContext;
pub use file_system::ReadDirectoryEntry;
pub use file_system::RemoveOptions;
pub use fs_helper::CODEX_FS_HELPER_ARG1;
pub use fs_helper_main::main as run_fs_helper_main;
pub use local_file_system::LOCAL_FS;
+6
View File
@@ -0,0 +1,6 @@
load("//:defs.bzl", "codex_rust_crate")
codex_rust_crate(
name = "file-system",
crate_name = "codex_file_system",
)
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "codex-file-system"
version.workspace = true
edition.workspace = true
license.workspace = true
[lints]
workspace = true
[dependencies]
async-trait = { workspace = true }
codex-protocol = { workspace = true }
codex-utils-absolute-path = { workspace = true }
serde = { workspace = true, features = ["derive"] }
@@ -9,8 +9,8 @@ use codex_protocol::permissions::FileSystemSpecialPath;
use codex_protocol::permissions::NetworkSandboxPolicy;
use codex_protocol::protocol::SandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::io;
use std::path::Path;
use tokio::io;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CreateDirectoryOptions {
@@ -99,16 +99,20 @@ impl FileSystemSandboxContext {
&& !file_system_policy.has_full_disk_write_access()
}
pub(crate) fn drop_cwd_if_unused(mut self) -> Self {
pub fn has_cwd_dependent_permissions(&self) -> bool {
let file_system_policy = self.permissions.file_system_sandbox_policy();
if !file_system_policy_has_cwd_dependent_entries(&file_system_policy) {
file_system_policy_has_cwd_dependent_entries(&file_system_policy)
}
pub fn drop_cwd_if_unused(mut self) -> Self {
if !self.has_cwd_dependent_permissions() {
self.cwd = None;
}
self
}
}
pub(crate) fn file_system_policy_has_cwd_dependent_entries(
fn file_system_policy_has_cwd_dependent_entries(
file_system_policy: &FileSystemSandboxPolicy,
) -> bool {
file_system_policy
@@ -125,6 +129,8 @@ pub(crate) fn file_system_policy_has_cwd_dependent_entries(
pub type FileSystemResult<T> = io::Result<T>;
/// Abstract filesystem access used by components that may operate locally or via
/// a remote executor.
#[async_trait]
pub trait ExecutorFileSystem: Send + Sync {
async fn read_file(
+1 -1
View File
@@ -11,7 +11,7 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
chrono = { workspace = true }
codex-exec-server = { workspace = true }
codex-file-system = { workspace = true }
codex-protocol = { workspace = true }
codex-utils-absolute-path = { workspace = true }
futures = { workspace = true, features = ["alloc"] }
+1 -1
View File
@@ -4,7 +4,7 @@ use std::ffi::OsStr;
use std::path::Path;
use std::path::PathBuf;
use codex_exec_server::ExecutorFileSystem;
use codex_file_system::ExecutorFileSystem;
use codex_utils_absolute_path::AbsolutePathBuf;
use futures::future::join_all;
use schemars::JsonSchema;