Files
codex/codex-rs/exec-server/src/sandboxed_file_system_path_uri_tests.rs
T
Adam Perry @ OpenAI 841b5490b2 Preserve filesystem sandbox policy context when the cwd disappears (#46112)
## Why

Removing the selected working directory can prevent filesystem sandbox helpers from launching, even when the requested absolute paths remain accessible. Permission rules must stay anchored to the selected directory while those operations continue.

## What changed

- Require a policy `cwd` in `FileSystemSandboxContext` and launch filesystem helpers from the filesystem root while preserving the policy directory and workspace roots.
- Carry explicit `policyContext` in filesystem RPCs, preserving legacy wire fields and resolving omitted directories from older clients at executor ingress.
- Keep permission paths as executor file URIs and validate host compatibility where they are enforced.
- Bind Windows relative denial globs to the policy directory before changing the helper's launch directory, preserving home-relative patterns.

## Testing

Add regression coverage for `apply_patch` after working-directory removal, legacy RPC directory fallbacks, cross-platform permission URI transport, and Windows relative read denials. The patch regression verifies that an allowed file is updated while an explicitly denied file remains unreadable and unchanged.

GitOrigin-RevId: b0f4db722b27cb72ec129fc297c85732afac11f7
2026-09-17 04:37:54 +00:00

78 lines
2.9 KiB
Rust

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_path_uri::PathUri;
use pretty_assertions::assert_eq;
use tokio::io;
use super::*;
#[tokio::test]
async fn sandboxed_file_system_rejects_non_native_uri_as_invalid_input() {
let runtime_paths = ExecServerRuntimePaths::new(
std::env::current_exe().expect("current exe"),
/*codex_linux_sandbox_exe*/ None,
)
.expect("runtime paths");
let file_system = SandboxedFileSystem::new(runtime_paths.clone());
let cwd = PathUri::from_host_native_path(std::env::temp_dir()).expect("native temporary cwd");
let sandbox = FileSystemSandboxContext::from_permission_profile(
PermissionProfile::from_runtime_permissions(
&FileSystemSandboxPolicy::restricted(Vec::new()),
NetworkSandboxPolicy::Restricted,
),
cwd.clone(),
);
let error = file_system
.read_file(&non_native_uri(), Default::default(), Some(&sandbox))
.await
.expect_err("non-native URI should be rejected");
assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
// A foreign permission path must not select the unsandboxed filesystem, even with a root grant.
let file_system = crate::LocalFileSystem::with_runtime_paths(runtime_paths);
let foreign = non_native_uri();
let policy = FileSystemSandboxPolicy::restricted(vec![
FileSystemSandboxEntry::new(
FileSystemPath::Special {
value: FileSystemSpecialPath::Root,
},
FileSystemAccessMode::Write,
),
FileSystemSandboxEntry::new(foreign.clone().into(), FileSystemAccessMode::Write),
]);
let sandbox = FileSystemSandboxContext::from_permission_profile(
PermissionProfile::from_runtime_permissions(&policy, NetworkSandboxPolicy::Restricted),
cwd,
);
let readable = tempfile::NamedTempFile::new().expect("readable file");
let error = file_system
.read_file(
&PathUri::from_host_native_path(readable.path()).expect("readable file URI"),
Default::default(),
Some(&sandbox),
)
.await
.expect_err("foreign permission path must not allow unsandboxed access");
assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
assert!(error.to_string().contains(&foreign.to_string()));
}
fn non_native_uri() -> PathUri {
#[cfg(unix)]
let uri = "file://server/share/file.txt";
#[cfg(windows)]
let uri = "file:///usr/local/file.txt";
match PathUri::parse(uri) {
Ok(uri) => uri,
Err(err) => panic!("valid non-native URI should parse: {err}"),
}
}