Run fs helper through Windows sandbox wrapper (#28359)

## Why

This is the final PR in the Windows fs-helper sandbox stack and contains
the actual bug fix.

The exec-server filesystem helper is a direct-spawn path: it asks
`SandboxManager` for a `SandboxExecRequest`, then launches the returned
argv itself. That works on macOS and Linux because the transformed argv
is already a self-contained sandbox wrapper. On Windows, the transformed
request carried `WindowsRestrictedToken` metadata, but the direct-spawn
fs-helper runner still launched the helper argv directly.

That means Windows filesystem built-ins backed by the fs-helper could
run with the parent Codex process permissions instead of the configured
Windows sandbox. This PR makes the direct-spawn transform produce a
self-contained Windows wrapper argv before fs-helper launches it.

## What Changed

- Added `SandboxManager::transform_for_direct_spawn()` for callers that
launch the returned argv themselves.
- Wrapped Windows restricted-token direct-spawn requests with `codex.exe
--run-as-windows-sandbox` and then marked the outer request as
unsandboxed, matching the macOS/Linux wrapper argv shape.
- Updated `exec-server/src/fs_sandbox.rs` to use the direct-spawn
transform for fs-helper launches.
- Materialized the inner `codex.exe --codex-run-as-fs-helper` executable
into `.sandbox-bin` so the sandboxed user can run it.
- Carried runtime workspace roots through `FileSystemSandboxContext` as
`PathUri` values so `:workspace_roots` policies resolve correctly
without sending native client paths over exec-server JSON.
- Preserved wrapper setup identity environment needed by Windows sandbox
setup without changing the serialized inner helper environment.

## Verification

- `just bazel-lock-update`
- `just bazel-lock-check`
- `just test -p codex-sandboxing transform_for_direct_spawn_windows`
- `just test -p codex-exec-server fs_sandbox::tests`
- `just fix -p codex-windows-sandbox -p codex-sandboxing -p
codex-exec-server -p codex-core -p codex-file-system`

Local note: `just fmt` completed Rust formatting, but this workstation
still fails the non-Rust formatter phases because uv cannot open its
cache and the local buildifier/dotslash path is missing.
This commit is contained in:
iceweasel-oai
2026-06-17 10:00:42 -07:00
committed by GitHub
Unverified
parent c78911e37f
commit ef75171f18
16 changed files with 861 additions and 399 deletions
@@ -33,6 +33,7 @@ use codex_sandboxing::SandboxType;
use codex_sandboxing::SandboxablePreference;
use codex_sandboxing::policy_transforms::effective_permission_profile;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::PathUri;
use futures::future::BoxFuture;
use std::path::PathBuf;
use std::time::Instant;
@@ -99,6 +100,11 @@ impl ApplyPatchRuntime {
Some(FileSystemSandboxContext {
permissions: permissions.into(),
cwd: Some(attempt.sandbox_cwd.clone()),
workspace_roots: attempt
.workspace_roots
.iter()
.map(PathUri::from_abs_path)
.collect(),
windows_sandbox_level: attempt.windows_sandbox_level,
windows_sandbox_private_desktop: attempt.windows_sandbox_private_desktop,
use_legacy_landlock: attempt.use_legacy_landlock,