windows-sandbox: pass workspace roots to runner (#24108)

## Why

#23813 switches the Windows sandbox runner path to `PermissionProfile`,
but it still left one runtime anchor for resolving symbolic
`:workspace_roots` entries. That is not enough once a turn has multiple
effective workspace roots: exact entries and deny globs under
`:workspace_roots` need to be materialized for every runtime root before
the command runner chooses token mode or builds ACL plans.

## What Changed

- Replaces the Windows runner/setup `permission_profile_cwd` plumbing
with `workspace_roots: Vec<AbsolutePathBuf>`.
- Resolves Windows-local `PermissionProfile` data with
`materialize_project_roots_with_workspace_roots(...)` instead of the
single-cwd helper.
- Threads `Config::effective_workspace_roots()` through core execution,
unified exec, TUI setup/read-grant flows, app-server setup, app-server
`command/exec`, and `debug sandbox` on Windows.
- Preserves those workspace roots through the zsh-fork escalation
executor instead of rebuilding them from `sandbox_policy_cwd`.
- Makes `ExecRequest::new(...)` and the remaining
`build_exec_request(...)` helper path take
`windows_sandbox_workspace_roots` explicitly so new call sites cannot
silently fall back to `vec![cwd]`.
- Clarifies the `debug sandbox` non-Windows comment: remaining
cwd-dependent resolution still uses `sandbox_policy_cwd`, while
`:workspace_roots` entries are already materialized from config roots.
- Updates elevated runner IPC `SpawnRequest` to send `workspace_roots`
and bumps the framed IPC protocol version to `3` for the payload shape
change.
- Adds Windows-local resolver coverage for expanding exact and glob
`:workspace_roots` entries across multiple roots, plus core helper
coverage proving explicit roots are preserved.

## Verification

- `cargo check -p codex-windows-sandbox -p codex-core -p codex-tui -p
codex-cli -p codex-app-server`
- `cargo test -p codex-windows-sandbox`
- `cargo test -p codex-core windows_sandbox`
- `cargo test -p codex-core unix_escalation`
- `cargo test -p codex-app-server windows_sandbox`
- `cargo test -p codex-tui windows_sandbox`
- `cargo test -p codex-cli debug_sandbox`
- `just test -p codex-core unified_exec`
- `just test -p codex-core
build_exec_request_preserves_windows_workspace_roots`
- `env -u CODEX_NETWORK_PROXY_ACTIVE -u
CODEX_NETWORK_ALLOW_LOCAL_BINDING just test -p codex-app-server --lib
command_exec`
- `just test -p codex-windows-sandbox`
- `just test -p codex-exec sandbox`
- `just fix -p codex-core -p codex-app-server -p codex-windows-sandbox`

A local macOS cross-check with `cargo check --target
x86_64-pc-windows-msvc ...` did not reach crate Rust code because native
dependencies require Windows SDK headers (`windows.h` / `assert.h`) in
this environment; Windows CI remains the real target validation.

Two local targeted filters compile but do not run assertions on macOS:
`env -u CODEX_NETWORK_PROXY_ACTIVE -u CODEX_NETWORK_ALLOW_LOCAL_BINDING
just test -p codex-app-server --lib command_exec_processor` matched zero
tests, and `just test -p codex-linux-sandbox landlock` matched zero
tests because the landlock suite is Linux-only.
This commit is contained in:
Michael Bolin authored and GitHub committed 2026-05-28 15:26:55 -07:00
1 parent e7dda8070e
commit 986c60467b
40 files changed
+517 -213

No files matched your search

@@ -203,6 +203,7 @@ impl CommandExecRequestProcessor {
network_proxy_spec,
network_proxy_permission_profile,
managed_network_requirements_enabled,
windows_sandbox_workspace_roots,
) = if let Some(permission_profile) = permission_profile {
let overrides = ConfigOverrides {
cwd: Some(cwd.to_path_buf()),
@@ -230,6 +231,7 @@ impl CommandExecRequestProcessor {
config.permissions.network.clone(),
config.permissions.permission_profile().clone(),
config.managed_network_requirements_enabled(),
config.effective_workspace_roots(),
)
} else if let Some(policy) = sandbox_policy.map(|policy| policy.to_core()) {
self.config
@@ -255,6 +257,7 @@ impl CommandExecRequestProcessor {
self.config.permissions.network.clone(),
self.config.permissions.permission_profile().clone(),
self.config.managed_network_requirements_enabled(),
self.config.effective_workspace_roots(),
)
} else {
(
@@ -262,6 +265,7 @@ impl CommandExecRequestProcessor {
self.config.permissions.network.clone(),
self.config.permissions.permission_profile().clone(),
self.config.managed_network_requirements_enabled(),
self.config.effective_workspace_roots(),
)
};
let started_network_proxy = match network_proxy_spec.as_ref() {
@@ -318,6 +322,7 @@ impl CommandExecRequestProcessor {
exec_params,
&effective_permission_profile,
&sandbox_cwd,
windows_sandbox_workspace_roots.as_slice(),
&codex_linux_sandbox_exe,
use_legacy_landlock,
)
@@ -77,7 +77,7 @@ impl WindowsSandboxRequestProcessor {
let setup_request = WindowsSandboxSetupRequest {
mode,
permission_profile: config.permissions.effective_permission_profile(),
permission_profile_cwd: config.cwd.to_path_buf(),
workspace_roots: config.effective_workspace_roots(),
command_cwd,
env_map: std::env::vars().collect(),
codex_home: config.codex_home.to_path_buf(),