core: pass permission profiles to Windows runner (#23715)

## Why

This is the functional handoff PR for the Windows sandbox
`PermissionProfile` migration. After #23714, the Windows elevated
backend can accept a profile-native request, but core still sent a
compatibility `SandboxPolicy` into the elevated command-runner path.
That meant profile-only details such as deny globs had to be translated
through side channels instead of being preserved in the runner
`SpawnRequest`.

Passing the real `PermissionProfile` completes the command-runner
handoff while leaving the unelevated restricted-token fallback on the
legacy policy-string API.

## What

- Updates one-shot Windows elevated execution in `core/src/exec.rs` to
call `run_windows_sandbox_capture_for_permission_profile_elevated`.
- Updates unified exec in `core/src/unified_exec/process_manager.rs` to
call `spawn_windows_sandbox_session_elevated_for_permission_profile`.
- Passes `request.permission_profile` /
`exec_request.permission_profile` and the stored Windows sandbox policy
cwd to the elevated backend.
- Keeps compatibility `SandboxPolicy` serialization only for the
non-elevated restricted-token fallback.

## Verification

- `cargo test -p codex-core --test all --no-run`
This commit is contained in:
Michael Bolin
2026-05-20 17:57:36 -07:00
committed by GitHub
Unverified
parent 713a5b1b00
commit 63a72e6b78
2 changed files with 26 additions and 12 deletions
+24 -10
View File
@@ -433,10 +433,10 @@ pub(crate) async fn execute_exec_request(
expiration,
capture_policy,
sandbox,
windows_sandbox_policy_cwd: _,
windows_sandbox_policy_cwd,
windows_sandbox_level,
windows_sandbox_private_desktop,
permission_profile: _,
permission_profile,
file_system_sandbox_policy: _,
network_sandbox_policy,
windows_sandbox_filesystem_overrides,
@@ -465,6 +465,8 @@ pub(crate) async fn execute_exec_request(
after_spawn,
sandbox,
&sandbox_policy,
&permission_profile,
&windows_sandbox_policy_cwd,
windows_sandbox_filesystem_overrides.as_ref(),
)
.await;
@@ -472,6 +474,7 @@ pub(crate) async fn execute_exec_request(
finalize_exec_result(raw_output_result, sandbox, duration)
}
#[allow(clippy::too_many_arguments)]
async fn get_raw_output_result(
params: ExecParams,
network_sandbox_policy: NetworkSandboxPolicy,
@@ -479,14 +482,22 @@ async fn get_raw_output_result(
after_spawn: Option<Box<dyn FnOnce() + Send>>,
#[cfg_attr(not(windows), allow(unused_variables))] sandbox: SandboxType,
#[cfg_attr(not(windows), allow(unused_variables))] sandbox_policy: &SandboxPolicy,
#[cfg_attr(not(windows), allow(unused_variables))] permission_profile: &PermissionProfile,
#[cfg_attr(not(windows), allow(unused_variables))] windows_sandbox_policy_cwd: &AbsolutePathBuf,
#[cfg_attr(not(windows), allow(unused_variables))] windows_sandbox_filesystem_overrides: Option<
&WindowsSandboxFilesystemOverrides,
>,
) -> Result<RawExecToolCallOutput> {
#[cfg(target_os = "windows")]
if sandbox == SandboxType::WindowsRestrictedToken {
return exec_windows_sandbox(params, sandbox_policy, windows_sandbox_filesystem_overrides)
.await;
return exec_windows_sandbox(
params,
sandbox_policy,
permission_profile,
windows_sandbox_policy_cwd,
windows_sandbox_filesystem_overrides,
)
.await;
}
exec(params, network_sandbox_policy, stdout_stream, after_spawn).await
@@ -562,10 +573,12 @@ fn record_windows_sandbox_spawn_failure(
async fn exec_windows_sandbox(
params: ExecParams,
sandbox_policy: &SandboxPolicy,
permission_profile: &PermissionProfile,
windows_sandbox_policy_cwd: &AbsolutePathBuf,
windows_sandbox_filesystem_overrides: Option<&WindowsSandboxFilesystemOverrides>,
) -> Result<RawExecToolCallOutput> {
use crate::config::find_codex_home;
use codex_windows_sandbox::run_windows_sandbox_capture_elevated;
use codex_windows_sandbox::run_windows_sandbox_capture_for_permission_profile_elevated;
use codex_windows_sandbox::run_windows_sandbox_capture_with_filesystem_overrides;
let ExecParams {
@@ -596,7 +609,8 @@ async fn exec_windows_sandbox(
"failed to serialize Windows sandbox policy: {err}"
)))
})?;
let sandbox_cwd = cwd.clone();
let sandbox_cwd = windows_sandbox_policy_cwd.clone();
let permission_profile = permission_profile.clone();
let codex_home = find_codex_home().map_err(|err| {
CodexErr::Io(io::Error::other(format!(
"windows sandbox: failed to resolve codex_home: {err}"
@@ -620,10 +634,10 @@ async fn exec_windows_sandbox(
.and_then(|overrides| overrides.write_roots_override.clone());
let spawn_res = tokio::task::spawn_blocking(move || {
if use_elevated {
run_windows_sandbox_capture_elevated(
codex_windows_sandbox::ElevatedSandboxCaptureRequest {
policy_json_or_preset: policy_str.as_str(),
sandbox_policy_cwd: &sandbox_cwd,
run_windows_sandbox_capture_for_permission_profile_elevated(
codex_windows_sandbox::ElevatedSandboxProfileCaptureRequest {
permission_profile: &permission_profile,
permission_profile_cwd: &sandbox_cwd,
codex_home: codex_home.as_ref(),
command,
cwd: &cwd,
@@ -901,8 +901,8 @@ impl UnifiedExecProcessManager {
.and_then(|overrides| overrides.write_roots_override.clone());
let spawned = match request.windows_sandbox_level {
codex_protocol::config_types::WindowsSandboxLevel::Elevated => {
codex_windows_sandbox::spawn_windows_sandbox_session_elevated(
policy_json.as_str(),
codex_windows_sandbox::spawn_windows_sandbox_session_elevated_for_permission_profile(
&request.permission_profile,
request.windows_sandbox_policy_cwd.as_path(),
codex_home.as_ref(),
request.command.clone(),