Sandbox remote apply_patch operations (#38043)

## Why

Cross-platform remote `apply_patch` calls were rejected when filesystem writes
were restricted because patch verification and writes could not be safely
performed against executor files.

## What changed

- Route intercepted and direct remote patches through the executor-managed
  filesystem sandbox, including the configured workspace roots.
- Select the restricted-token sandbox for Windows executor paths when no
  Windows sandbox level was configured.
- Fail closed when an executor cannot enforce the requested sandbox, and treat
  executor-managed access failures as sandbox denials so approval can retry the
  patch without sandboxing.

## Testing

- Cover sandboxed remote patches, denied writes, approval retries, Windows
  sandbox selection, and executor filesystem enforcement.

GitOrigin-RevId: caddeed0b266c456a689080a14a3a58e2bd7887c
This commit is contained in:
iceweasel-oai
2026-08-11 17:47:22 +00:00
committed by copyberry
parent 1e557a554e
commit 34db7e5563
14 changed files with 408 additions and 123 deletions
+32 -5
View File
@@ -13,6 +13,7 @@ use codex_sandboxing::SandboxDirectSpawnTransformRequest;
use codex_sandboxing::SandboxExecRequest;
use codex_sandboxing::SandboxManager;
use codex_sandboxing::SandboxTransformRequest;
use codex_sandboxing::SandboxType;
use codex_sandboxing::SandboxablePreference;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_absolute_path::canonicalize_preserving_symlinks;
@@ -114,10 +115,15 @@ impl FileSystemSandboxRunner {
let sandbox_manager = SandboxManager::new();
let sandbox = sandbox_manager.select_initial(
permission_profile,
SandboxablePreference::Auto,
SandboxablePreference::Require,
sandbox_context.windows_sandbox_level,
/*has_managed_network_requirements*/ false,
);
if sandbox == SandboxType::None {
return Err(invalid_request(
"filesystem sandbox cannot be enforced on this executor".to_string(),
));
}
let command = SandboxCommand {
program: helper.as_path().as_os_str().to_owned(),
args: vec![CODEX_FS_HELPER_ARG1.to_string()],
@@ -545,10 +551,11 @@ mod tests {
let runner = FileSystemSandboxRunner::new(runtime_paths);
let native_cwd = AbsolutePathBuf::current_dir().expect("cwd");
let cwd = PathUri::from_abs_path(&native_cwd);
let file_system_policy = restricted_policy(vec![path_entry(
native_cwd.clone(),
FileSystemAccessMode::Write,
)]);
let file_system_policy = restricted_policy(vec![
#[cfg(windows)]
special_entry(FileSystemSpecialPath::Root, FileSystemAccessMode::Read),
path_entry(native_cwd.clone(), FileSystemAccessMode::Write),
]);
let network_policy = NetworkSandboxPolicy::Restricted;
let permission_profile =
PermissionProfile::from_runtime_permissions(&file_system_policy, network_policy);
@@ -557,6 +564,26 @@ mod tests {
uri: cwd,
native: native_cwd,
};
#[cfg(windows)]
let sandbox_context = {
let error = runner
.sandbox_exec_request(
&permission_profile,
&sandbox_cwd,
std::slice::from_ref(&sandbox_cwd.native),
&sandbox_context,
)
.expect_err("disabled Windows sandbox must not run the helper unsandboxed");
assert_eq!(
error.message,
"filesystem sandbox cannot be enforced on this executor"
);
crate::FileSystemSandboxContext {
windows_sandbox_level:
codex_protocol::config_types::WindowsSandboxLevel::RestrictedToken,
..sandbox_context
}
};
let request = runner
.sandbox_exec_request(
@@ -756,6 +756,10 @@ pub(crate) async fn assert_sandboxed_canonicalize_resolves_directory_alias(
/// Verifies that effective additional permissions extend a read-only sandbox with a writable root.
#[test_case(FileSystemImplementation::Local ; "local")]
#[test_case(FileSystemImplementation::Remote ; "remote")]
#[cfg_attr(
windows,
ignore = "Windows restricted-token sandbox cannot enforce split writable roots"
)]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn file_system_sandboxed_write_allows_additional_write_root(
implementation: FileSystemImplementation,
@@ -7,11 +7,13 @@ use codex_exec_server::ExecServerRuntimePaths;
use codex_exec_server::ExecutorFileSystem;
use codex_exec_server::FileSystemSandboxContext;
use codex_exec_server::LocalFileSystem;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::models::PermissionProfile;
use codex_protocol::permissions::FileSystemAccessMode;
use codex_protocol::permissions::FileSystemPath;
use codex_protocol::permissions::FileSystemSandboxEntry;
use codex_protocol::permissions::FileSystemSandboxPolicy;
use codex_protocol::permissions::FileSystemSpecialPath;
use codex_protocol::permissions::NetworkSandboxPolicy;
use codex_utils_absolute_path::AbsolutePathBuf;
@@ -103,9 +105,25 @@ pub(crate) fn workspace_write_sandbox(
}])
}
fn sandbox_context(entries: Vec<FileSystemSandboxEntry>) -> FileSystemSandboxContext {
FileSystemSandboxContext::from_permission_profile(PermissionProfile::from_runtime_permissions(
&FileSystemSandboxPolicy::restricted(entries),
NetworkSandboxPolicy::Restricted,
))
fn sandbox_context(mut entries: Vec<FileSystemSandboxEntry>) -> FileSystemSandboxContext {
if cfg!(windows) {
// Restricted-token sandboxing cannot enforce read restrictions, so leave the root
// readable while exercising the requested write restrictions.
entries.push(FileSystemSandboxEntry::new(
FileSystemPath::Special {
value: FileSystemSpecialPath::Root,
},
FileSystemAccessMode::Read,
));
}
let mut sandbox = FileSystemSandboxContext::from_permission_profile(
PermissionProfile::from_runtime_permissions(
&FileSystemSandboxPolicy::restricted(entries),
NetworkSandboxPolicy::Restricted,
),
);
if cfg!(windows) {
sandbox.windows_sandbox_level = WindowsSandboxLevel::RestrictedToken;
}
sandbox
}