Files
codex/codex-rs/sandboxing/src/windows_tests.rs
T
zm-oai 7efc49b258 Align Windows sandbox temp permissions with the child environment (#51512)
## Why

Windows temp grants could fall back to host `TEMP`/`TMP` values and bypass read-only or denied subpaths. Sandbox permissions must match the environment passed to the child process.

## What changed

- Resolve `:tmpdir` from absolute `TEMP`/`TMP` paths in the completed workload environment, preserving access modes and missing-path rules without falling back to host values.
- Deduplicate Windows environment keys case-insensitively in a deterministic order so permission resolution and the child environment select the same value.
- Use the resolved temp policy for elevated sandbox overrides across core execution, exec-server, and direct spawning.
- Launch direct-spawn sandbox wrappers with the supplied Codex executable, materializing an inner helper only when it is that executable.

## Testing

Add Windows regression coverage for temp-only writes, read-only and denied carveouts, mixed-case and duplicate environment keys, unavailable temp paths, and empty or missing write-root overrides. Exercise core execution and direct spawning, and extend exec-server RPC coverage to the elevated backend with temp values set through the environment policy.

GitOrigin-RevId: 16b8bd4702cc434fd743a08c75a3e4515780bff3
2026-10-06 23:21:06 +00:00

59 lines
2.2 KiB
Rust

//! Windows temp override behavior not covered by a successful child launch.
use super::*;
use codex_protocol::permissions::FileSystemAccessMode;
use codex_protocol::permissions::FileSystemPath;
use codex_protocol::permissions::FileSystemSandboxEntry;
use codex_protocol::permissions::FileSystemSpecialPath;
use codex_protocol::permissions::NetworkSandboxPolicy;
use pretty_assertions::assert_eq;
#[test]
fn elevated_non_write_temp_never_grants_write_access() {
let dir = tempfile::TempDir::new().unwrap();
let cwd = AbsolutePathBuf::from_absolute_path(dir.path().join("work")).unwrap();
let temp = dir.path().join("temp");
std::fs::create_dir_all(cwd.as_path()).unwrap();
std::fs::create_dir_all(&temp).unwrap();
let env = HashMap::from([("Temp".into(), temp.to_string_lossy().into_owned())]);
for access in [FileSystemAccessMode::Read, FileSystemAccessMode::Deny] {
let profile = PermissionProfile::from_runtime_permissions(
&FileSystemSandboxPolicy::restricted(vec![
FileSystemSandboxEntry::new(
FileSystemPath::Special {
value: FileSystemSpecialPath::Root,
},
FileSystemAccessMode::Read,
),
FileSystemSandboxEntry::new(
FileSystemPath::Special {
value: FileSystemSpecialPath::Tmpdir,
},
access,
),
]),
NetworkSandboxPolicy::Restricted,
);
let overrides = resolve_windows_elevated_filesystem_overrides(
SandboxType::WindowsRestrictedToken,
&profile,
&cwd,
true,
&env,
)
.unwrap();
let write_roots = overrides
.as_ref()
.and_then(|o| o.write_roots_override.as_ref());
assert!(write_roots.is_none_or(Vec::is_empty));
if access == FileSystemAccessMode::Deny {
assert_eq!(
overrides.unwrap().additional_deny_read_paths,
vec![
AbsolutePathBuf::from_absolute_path(dunce::canonicalize(&temp).unwrap())
.unwrap(),
]
);
}
}
}