fix: support split carveouts in windows restricted-token sandbox (#14172)

## Summary
- keep legacy Windows restricted-token sandboxing as the supported
baseline
- support the split-policy subset that restricted-token can enforce
directly today
- support full-disk read, the same writable root set as legacy
`WorkspaceWrite`, and extra read-only carveouts under those writable
roots via additional deny-write ACLs
- continue to fail closed for unsupported split-only shapes, including
explicit unreadable (`none`) carveouts, reopened writable descendants
under read-only carveouts, and writable root sets that do not match the
legacy workspace roots

## Example
Given a filesystem policy like:

```toml
":root" = "read"
":cwd" = "write"
"./docs" = "read"
```

the restricted-token backend can keep the workspace writable while
denying writes under `docs` by layering an extra deny-write carveout on
top of the legacy workspace-write roots.

A policy like:

```toml
"/workspace" = "write"
"/workspace/docs" = "read"
"/workspace/docs/tmp" = "write"
```

still fails closed, because the unelevated backend cannot reopen the
nested writable descendant safely.

## Stack
-> fix: support split carveouts in windows restricted-token sandbox
#14172
fix: support split carveouts in windows elevated sandbox #14568
This commit is contained in:
viyatb-oai
2026-03-24 22:54:18 -07:00
committed by GitHub
parent 8c62829a2b
commit 95ba762620
8 changed files with 538 additions and 185 deletions

View File

@@ -734,21 +734,21 @@ mod tests {
access: ReadOnlyAccess::FullAccess,
network_access: false,
};
ExecRequest {
command: vec!["cmd".to_string()],
cwd: PathBuf::from("."),
env: HashMap::new(),
network: None,
expiration: ExecExpiration::DefaultTimeout,
capture_policy: codex_core::exec::ExecCapturePolicy::ShellTool,
sandbox: SandboxType::WindowsRestrictedToken,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
sandbox_policy: sandbox_policy.clone(),
file_system_sandbox_policy: FileSystemSandboxPolicy::from(&sandbox_policy),
network_sandbox_policy: NetworkSandboxPolicy::from(&sandbox_policy),
arg0: None,
}
ExecRequest::new(
vec!["cmd".to_string()],
PathBuf::from("."),
HashMap::new(),
/*network*/ None,
ExecExpiration::DefaultTimeout,
codex_core::exec::ExecCapturePolicy::ShellTool,
SandboxType::WindowsRestrictedToken,
WindowsSandboxLevel::Disabled,
/*windows_sandbox_private_desktop*/ false,
sandbox_policy.clone(),
FileSystemSandboxPolicy::from(&sandbox_policy),
NetworkSandboxPolicy::from(&sandbox_policy),
/*arg0*/ None,
)
}
#[tokio::test]
@@ -846,21 +846,21 @@ mod tests {
outgoing: Arc::new(OutgoingMessageSender::new(tx)),
request_id: request_id.clone(),
process_id: Some("proc-100".to_string()),
exec_request: ExecRequest {
command: vec!["sh".to_string(), "-lc".to_string(), "sleep 30".to_string()],
cwd: PathBuf::from("."),
env: HashMap::new(),
network: None,
expiration: ExecExpiration::Cancellation(CancellationToken::new()),
capture_policy: codex_core::exec::ExecCapturePolicy::ShellTool,
sandbox: SandboxType::None,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
windows_sandbox_private_desktop: false,
sandbox_policy: sandbox_policy.clone(),
file_system_sandbox_policy: FileSystemSandboxPolicy::from(&sandbox_policy),
network_sandbox_policy: NetworkSandboxPolicy::from(&sandbox_policy),
arg0: None,
},
exec_request: ExecRequest::new(
vec!["sh".to_string(), "-lc".to_string(), "sleep 30".to_string()],
PathBuf::from("."),
HashMap::new(),
/*network*/ None,
ExecExpiration::Cancellation(CancellationToken::new()),
codex_core::exec::ExecCapturePolicy::ShellTool,
SandboxType::None,
WindowsSandboxLevel::Disabled,
/*windows_sandbox_private_desktop*/ false,
sandbox_policy.clone(),
FileSystemSandboxPolicy::from(&sandbox_policy),
NetworkSandboxPolicy::from(&sandbox_policy),
/*arg0*/ None,
),
started_network_proxy: None,
tty: false,
stream_stdin: false,