From c9ff067e31496caf563e0cd7ab7adee62cdd868c Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 20 May 2026 17:25:31 -0700 Subject: [PATCH] windows-sandbox: add profile-native elevated APIs (#23714) ## Why This is the next step after #23167 in the Windows sandbox `PermissionProfile` migration. The elevated Windows backend still exposed policy-string entry points, which forced callers to pass a compatibility `SandboxPolicy` before the command-runner IPC could receive a profile. Adding profile-native APIs first keeps the core switch in the next PR small: reviewers can see that the Windows crate can prepare elevated setup, capability SIDs, and runner IPC from a resolved `PermissionProfile` without changing core behavior yet. ## What - Adds `ElevatedSandboxProfileCaptureRequest` and `run_windows_sandbox_capture_for_permission_profile_elevated` for one-shot elevated capture. - Adds `spawn_windows_sandbox_session_elevated_for_permission_profile` for unified exec sessions. - Factors elevated spawn prep through `prepare_elevated_spawn_context_for_permissions`, so both new APIs operate from `ResolvedWindowsSandboxPermissions` directly. - Keeps the existing legacy policy-string APIs as adapters for callers that have not moved yet. ## Verification - `cargo test -p codex-windows-sandbox` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23714). * #23715 * __->__ #23714 --- .../windows-sandbox-rs/src/elevated_impl.rs | 106 ++++++++++++++---- codex-rs/windows-sandbox-rs/src/lib.rs | 6 + .../src/resolved_permissions.rs | 56 ++++++++- codex-rs/windows-sandbox-rs/src/spawn_prep.rs | 55 +++++---- .../src/unified_exec/backends/elevated.rs | 72 +++++++++--- .../src/unified_exec/mod.rs | 39 +++++++ 6 files changed, 268 insertions(+), 66 deletions(-) diff --git a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs index dd343a22ce..f8a059918a 100644 --- a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs +++ b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs @@ -1,3 +1,4 @@ +use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; use std::collections::HashMap; use std::path::Path; @@ -20,8 +21,26 @@ pub struct ElevatedSandboxCaptureRequest<'a> { pub deny_write_paths_override: &'a [AbsolutePathBuf], } +pub struct ElevatedSandboxProfileCaptureRequest<'a> { + pub permission_profile: &'a PermissionProfile, + pub permission_profile_cwd: &'a Path, + pub codex_home: &'a Path, + pub command: Vec, + pub cwd: &'a Path, + pub env_map: HashMap, + pub timeout_ms: Option, + pub use_private_desktop: bool, + pub proxy_enforced: bool, + pub read_roots_override: Option<&'a [PathBuf]>, + pub read_roots_include_platform_defaults: bool, + pub write_roots_override: Option<&'a [PathBuf]>, + pub deny_read_paths_override: &'a [AbsolutePathBuf], + pub deny_write_paths_override: &'a [AbsolutePathBuf], +} + mod windows_impl { use super::ElevatedSandboxCaptureRequest; + use super::ElevatedSandboxProfileCaptureRequest; use crate::acl::allow_null_device; use crate::cap::load_or_create_cap_sids; use crate::cap::workspace_write_cap_sid_for_root; @@ -37,7 +56,6 @@ mod windows_impl { use crate::logging::log_failure; use crate::logging::log_start; use crate::logging::log_success; - use crate::policy::SandboxPolicy; use crate::policy::parse_policy; use crate::resolved_permissions::ResolvedWindowsSandboxPermissions; use crate::runner_client::spawn_runner_transport; @@ -54,12 +72,12 @@ mod windows_impl { /// Launches the command runner under the sandbox user and captures its output. #[allow(clippy::too_many_arguments)] - pub fn run_windows_sandbox_capture( - request: ElevatedSandboxCaptureRequest<'_>, + pub fn run_windows_sandbox_capture_for_permission_profile( + request: ElevatedSandboxProfileCaptureRequest<'_>, ) -> Result { - let ElevatedSandboxCaptureRequest { - policy_json_or_preset, - sandbox_policy_cwd, + let ElevatedSandboxProfileCaptureRequest { + permission_profile, + permission_profile_cwd, codex_home, command, cwd, @@ -73,6 +91,10 @@ mod windows_impl { deny_read_paths_override, deny_write_paths_override, } = request; + let permissions = ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_cwd( + permission_profile, + permission_profile_cwd, + )?; let deny_read_paths_override = deny_read_paths_override .iter() .map(AbsolutePathBuf::to_path_buf) @@ -81,11 +103,6 @@ mod windows_impl { .iter() .map(AbsolutePathBuf::to_path_buf) .collect::>(); - let policy = parse_policy(policy_json_or_preset)?; - let permissions = ResolvedWindowsSandboxPermissions::from_legacy_policy_for_cwd( - &policy, - sandbox_policy_cwd, - ); normalize_null_device_env(&mut env_map); ensure_non_interactive_pager(&mut env_map); inherit_path_env(&mut env_map); @@ -109,12 +126,6 @@ mod windows_impl { proxy_enforced, )?; // Build capability SID for ACL grants. - if matches!( - &policy, - SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } - ) { - anyhow::bail!("DangerFullAccess and ExternalSandbox are not supported for sandboxing") - } let caps = load_or_create_cap_sids(codex_home)?; let (sid_for_null, cap_sids) = if permissions.uses_write_capabilities_for_cwd(cwd, &env_map) { @@ -143,14 +154,12 @@ mod windows_impl { } (|| -> Result { - let permission_profile = - PermissionProfile::from_legacy_sandbox_policy_for_cwd(&policy, sandbox_policy_cwd); let spawn_request = SpawnRequest { command: command.clone(), cwd: cwd.to_path_buf(), env: env_map.clone(), - permission_profile, - permission_profile_cwd: sandbox_policy_cwd.to_path_buf(), + permission_profile: permission_profile.clone(), + permission_profile_cwd: permission_profile_cwd.to_path_buf(), codex_home: sandbox_base.clone(), real_codex_home: codex_home.to_path_buf(), cap_sids, @@ -210,6 +219,48 @@ mod windows_impl { })() } + /// Legacy policy-string adapter for callers that have not moved to permission profiles yet. + #[allow(clippy::too_many_arguments)] + pub fn run_windows_sandbox_capture( + request: ElevatedSandboxCaptureRequest<'_>, + ) -> Result { + let ElevatedSandboxCaptureRequest { + policy_json_or_preset, + sandbox_policy_cwd, + codex_home, + command, + cwd, + env_map, + timeout_ms, + use_private_desktop, + proxy_enforced, + read_roots_override, + read_roots_include_platform_defaults, + write_roots_override, + deny_read_paths_override, + deny_write_paths_override, + } = request; + let policy = parse_policy(policy_json_or_preset)?; + let permission_profile = + PermissionProfile::from_legacy_sandbox_policy_for_cwd(&policy, sandbox_policy_cwd); + run_windows_sandbox_capture_for_permission_profile(ElevatedSandboxProfileCaptureRequest { + permission_profile: &permission_profile, + permission_profile_cwd: sandbox_policy_cwd, + codex_home, + command, + cwd, + env_map, + timeout_ms, + use_private_desktop, + proxy_enforced, + read_roots_override, + read_roots_include_platform_defaults, + write_roots_override, + deny_read_paths_override, + deny_write_paths_override, + }) + } + #[cfg(test)] mod tests { use crate::policy::SandboxPolicy; @@ -242,10 +293,13 @@ mod windows_impl { #[cfg(target_os = "windows")] pub use windows_impl::run_windows_sandbox_capture; +#[cfg(target_os = "windows")] +pub use windows_impl::run_windows_sandbox_capture_for_permission_profile; #[cfg(not(target_os = "windows"))] mod stub { use super::ElevatedSandboxCaptureRequest; + use super::ElevatedSandboxProfileCaptureRequest; use anyhow::Result; use anyhow::bail; @@ -264,7 +318,17 @@ mod stub { ) -> Result { bail!("Windows sandbox is only available on Windows") } + + /// Stub implementation for non-Windows targets; sandboxing only works on Windows. + #[allow(clippy::too_many_arguments)] + pub fn run_windows_sandbox_capture_for_permission_profile( + _request: ElevatedSandboxProfileCaptureRequest<'_>, + ) -> Result { + bail!("Windows sandbox is only available on Windows") + } } #[cfg(not(target_os = "windows"))] pub use stub::run_windows_sandbox_capture; +#[cfg(not(target_os = "windows"))] +pub use stub::run_windows_sandbox_capture_for_permission_profile; diff --git a/codex-rs/windows-sandbox-rs/src/lib.rs b/codex-rs/windows-sandbox-rs/src/lib.rs index e3365a2c8f..43b3f71955 100644 --- a/codex-rs/windows-sandbox-rs/src/lib.rs +++ b/codex-rs/windows-sandbox-rs/src/lib.rs @@ -139,8 +139,12 @@ pub use dpapi::unprotect as dpapi_unprotect; #[cfg(target_os = "windows")] pub use elevated_impl::ElevatedSandboxCaptureRequest; #[cfg(target_os = "windows")] +pub use elevated_impl::ElevatedSandboxProfileCaptureRequest; +#[cfg(target_os = "windows")] pub use elevated_impl::run_windows_sandbox_capture as run_windows_sandbox_capture_elevated; #[cfg(target_os = "windows")] +pub use elevated_impl::run_windows_sandbox_capture_for_permission_profile as run_windows_sandbox_capture_for_permission_profile_elevated; +#[cfg(target_os = "windows")] pub use helper_materialization::resolve_current_exe_for_launch; #[cfg(target_os = "windows")] pub use hide_users::hide_current_user_profile_dir; @@ -258,6 +262,8 @@ pub use token::get_current_token_for_restriction; #[cfg(target_os = "windows")] pub use unified_exec::spawn_windows_sandbox_session_elevated; #[cfg(target_os = "windows")] +pub use unified_exec::spawn_windows_sandbox_session_elevated_for_permission_profile; +#[cfg(target_os = "windows")] pub use unified_exec::spawn_windows_sandbox_session_legacy; #[cfg(target_os = "windows")] pub use wfp::install_wfp_filters_for_account; diff --git a/codex-rs/windows-sandbox-rs/src/resolved_permissions.rs b/codex-rs/windows-sandbox-rs/src/resolved_permissions.rs index ba5a4ca615..dbb08b2115 100644 --- a/codex-rs/windows-sandbox-rs/src/resolved_permissions.rs +++ b/codex-rs/windows-sandbox-rs/src/resolved_permissions.rs @@ -41,8 +41,10 @@ pub fn token_mode_for_permission_profile( cwd: &Path, env_map: &HashMap, ) -> Result { - let permissions = - ResolvedWindowsSandboxPermissions::try_from_permission_profile(permission_profile)?; + let permissions = ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_cwd( + permission_profile, + cwd, + )?; if permissions.file_system.has_full_disk_write_access() { anyhow::bail!( "permission profile requests full-disk filesystem writes, which cannot be enforced by the Windows sandbox" @@ -82,6 +84,19 @@ impl ResolvedWindowsSandboxPermissions { }) } + /// Resolves a managed permission profile and binds symbolic `:workspace_roots` + /// entries to the permission root supplied by the caller. + pub fn try_from_permission_profile_for_cwd( + permission_profile: &PermissionProfile, + cwd: &Path, + ) -> Result { + let mut permissions = Self::try_from_permission_profile(permission_profile)?; + permissions.file_system = permissions + .file_system + .materialize_project_roots_with_cwd(cwd); + Ok(permissions) + } + pub(crate) fn should_apply_network_block(&self) -> bool { !self.network.is_enabled() } @@ -259,6 +274,43 @@ mod tests { ); } + #[test] + fn permission_profile_workspace_root_stays_bound_to_profile_cwd() { + let tmp = TempDir::new().expect("tempdir"); + let profile_cwd = tmp.path().join("workspace"); + let command_cwd = profile_cwd.join("subdir"); + std::fs::create_dir_all(&command_cwd).expect("create command cwd"); + + let permission_profile = PermissionProfile::Managed { + file_system: ManagedFileSystemPermissions::Restricted { + entries: vec![FileSystemSandboxEntry { + path: FileSystemPath::Special { + value: FileSystemSpecialPath::project_roots(/*subpath*/ None), + }, + access: FileSystemAccessMode::Write, + }], + glob_scan_max_depth: None, + }, + network: NetworkSandboxPolicy::Restricted, + }; + let permissions = ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_cwd( + &permission_profile, + &profile_cwd, + ) + .expect("managed permission profile"); + + let roots = permissions + .writable_roots_for_cwd(&command_cwd, &HashMap::new()) + .into_iter() + .map(|root| root.root) + .collect::>(); + + assert_eq!( + roots, + vec![dunce::canonicalize(&profile_cwd).expect("canonical profile cwd")] + ); + } + #[test] fn token_mode_for_profile_without_writable_roots_uses_readonly_capability() { let tmp = TempDir::new().expect("tempdir"); diff --git a/codex-rs/windows-sandbox-rs/src/spawn_prep.rs b/codex-rs/windows-sandbox-rs/src/spawn_prep.rs index f4f0779742..f16e964308 100644 --- a/codex-rs/windows-sandbox-rs/src/spawn_prep.rs +++ b/codex-rs/windows-sandbox-rs/src/spawn_prep.rs @@ -44,13 +44,13 @@ pub(crate) struct SpawnContext { pub(crate) policy: SandboxPolicy, pub(crate) permissions: ResolvedWindowsSandboxPermissions, pub(crate) current_dir: PathBuf, - pub(crate) sandbox_base: PathBuf, pub(crate) logs_base_dir: Option, pub(crate) uses_write_capabilities: bool, } pub(crate) struct ElevatedSpawnContext { - pub(crate) common: SpawnContext, + pub(crate) sandbox_base: PathBuf, + pub(crate) logs_base_dir: Option, pub(crate) sandbox_creds: SandboxCreds, pub(crate) cap_sids: Vec, } @@ -109,7 +109,7 @@ fn prepare_spawn_context_common( ensure_codex_home_exists(codex_home)?; let sandbox_base = codex_home.join(".sandbox"); std::fs::create_dir_all(&sandbox_base)?; - let logs_base_dir = Some(sandbox_base.clone()); + let logs_base_dir = Some(sandbox_base); log_start(command, logs_base_dir.as_deref()); let permissions = @@ -120,7 +120,6 @@ fn prepare_spawn_context_common( policy, permissions, current_dir: cwd.to_path_buf(), - sandbox_base, logs_base_dir, uses_write_capabilities, }) @@ -362,9 +361,8 @@ pub(crate) fn apply_legacy_session_acl_rules( } #[allow(clippy::too_many_arguments)] -pub(crate) fn prepare_elevated_spawn_context( - policy_json_or_preset: &str, - sandbox_policy_cwd: &Path, +pub(crate) fn prepare_elevated_spawn_context_for_permissions( + permissions: ResolvedWindowsSandboxPermissions, codex_home: &Path, cwd: &Path, env_map: &mut HashMap, @@ -375,33 +373,33 @@ pub(crate) fn prepare_elevated_spawn_context( deny_read_paths_override: &[PathBuf], deny_write_paths_override: &[PathBuf], ) -> Result { - let common = prepare_spawn_context_common( - policy_json_or_preset, - sandbox_policy_cwd, - codex_home, - cwd, - env_map, - command, - SpawnPrepOptions { - inherit_path: true, - add_git_safe_directory: true, - }, - )?; + normalize_null_device_env(env_map); + ensure_non_interactive_pager(env_map); + inherit_path_env(env_map); + inject_git_safe_directory(env_map, cwd); + + // Use a temp-based log dir that the sandbox user can write. + let sandbox_base = codex_home.join(".sandbox"); + ensure_codex_home_exists(&sandbox_base)?; + let logs_base_dir = Some(sandbox_base.clone()); + log_start(command, logs_base_dir.as_deref()); + + let uses_write_capabilities = permissions.uses_write_capabilities_for_cwd(cwd, env_map); let AllowDenyPaths { allow, deny } = - compute_allow_paths_for_permissions(&common.permissions, &common.current_dir, env_map); + compute_allow_paths_for_permissions(&permissions, cwd, env_map); let write_roots: Vec = allow.into_iter().collect(); let deny_write_paths: Vec = deny.into_iter().collect(); - let computed_write_roots_override = if common.uses_write_capabilities { + let computed_write_roots_override = if uses_write_capabilities { Some(write_roots.as_slice()) } else { None }; let write_roots_for_setup = write_roots_override.or(computed_write_roots_override); - let effective_write_roots = if common.uses_write_capabilities { + let effective_write_roots = if uses_write_capabilities { effective_write_roots_for_permissions( - &common.permissions, - &common.current_dir, + &permissions, + cwd, env_map, codex_home, write_roots_for_setup, @@ -409,13 +407,13 @@ pub(crate) fn prepare_elevated_spawn_context( } else { Vec::new() }; - let setup_write_roots_override = if common.uses_write_capabilities { + let setup_write_roots_override = if uses_write_capabilities { Some(effective_write_roots.as_slice()) } else { write_roots_override }; let sandbox_creds = require_logon_sandbox_creds( - &common.permissions, + &permissions, cwd, env_map, codex_home, @@ -431,7 +429,7 @@ pub(crate) fn prepare_elevated_spawn_context( /*proxy_enforced*/ false, )?; let caps = load_or_create_cap_sids(codex_home)?; - let (psid_to_use, cap_sids) = if common.uses_write_capabilities { + let (psid_to_use, cap_sids) = if uses_write_capabilities { let cap_sids = root_capability_sids(codex_home, cwd, effective_write_roots)? .into_iter() .map(|root_sid| root_sid.sid_str) @@ -452,7 +450,8 @@ pub(crate) fn prepare_elevated_spawn_context( } Ok(ElevatedSpawnContext { - common, + sandbox_base, + logs_base_dir, sandbox_creds, cap_sids, }) diff --git a/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs b/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs index 352226644d..1e13e45cc0 100644 --- a/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs +++ b/codex-rs/windows-sandbox-rs/src/unified_exec/backends/elevated.rs @@ -8,8 +8,10 @@ use crate::ipc_framed::FramedMessage; use crate::ipc_framed::IPC_PROTOCOL_VERSION; use crate::ipc_framed::Message; use crate::ipc_framed::SpawnRequest; +use crate::policy::parse_policy; +use crate::resolved_permissions::ResolvedWindowsSandboxPermissions; use crate::runner_client::spawn_runner_transport; -use crate::spawn_prep::prepare_elevated_spawn_context; +use crate::spawn_prep::prepare_elevated_spawn_context_for_permissions; use anyhow::Result; use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; @@ -23,9 +25,9 @@ use tokio::sync::mpsc; use tokio::sync::oneshot; #[allow(clippy::too_many_arguments)] -pub(crate) async fn spawn_windows_sandbox_session_elevated( - policy_json_or_preset: &str, - sandbox_policy_cwd: &Path, +pub(crate) async fn spawn_windows_sandbox_session_elevated_for_permission_profile( + permission_profile: &PermissionProfile, + permission_profile_cwd: &Path, codex_home: &Path, command: Vec, cwd: &Path, @@ -48,9 +50,12 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated( .iter() .map(AbsolutePathBuf::to_path_buf) .collect::>(); - let elevated = prepare_elevated_spawn_context( - policy_json_or_preset, - sandbox_policy_cwd, + let permissions = ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_cwd( + permission_profile, + permission_profile_cwd, + )?; + let elevated = prepare_elevated_spawn_context_for_permissions( + permissions, codex_home, cwd, &mut env_map, @@ -62,17 +67,13 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated( &deny_write_paths_override, )?; - let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd( - &elevated.common.policy, - sandbox_policy_cwd, - ); let spawn_request = SpawnRequest { command: command.clone(), cwd: cwd.to_path_buf(), env: env_map.clone(), - permission_profile, - permission_profile_cwd: sandbox_policy_cwd.to_path_buf(), - codex_home: elevated.common.sandbox_base.clone(), + permission_profile: permission_profile.clone(), + permission_profile_cwd: permission_profile_cwd.to_path_buf(), + codex_home: elevated.sandbox_base.clone(), real_codex_home: codex_home.to_path_buf(), cap_sids: elevated.cap_sids.clone(), timeout_ms, @@ -83,7 +84,7 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated( let codex_home = codex_home.to_path_buf(); let cwd = cwd.to_path_buf(); let sandbox_creds = elevated.sandbox_creds.clone(); - let logs_base_dir = elevated.common.logs_base_dir.clone(); + let logs_base_dir = elevated.logs_base_dir.clone(); let transport = tokio::task::spawn_blocking(move || -> Result<_> { spawn_runner_transport( &codex_home, @@ -144,3 +145,44 @@ pub(crate) async fn spawn_windows_sandbox_session_elevated( stdin_open, )) } + +#[allow(clippy::too_many_arguments)] +pub(crate) async fn spawn_windows_sandbox_session_elevated( + policy_json_or_preset: &str, + sandbox_policy_cwd: &Path, + codex_home: &Path, + command: Vec, + cwd: &Path, + env_map: HashMap, + timeout_ms: Option, + read_roots_override: Option<&[PathBuf]>, + read_roots_include_platform_defaults: bool, + write_roots_override: Option<&[PathBuf]>, + deny_read_paths_override: &[AbsolutePathBuf], + deny_write_paths_override: &[AbsolutePathBuf], + tty: bool, + stdin_open: bool, + use_private_desktop: bool, +) -> Result { + let policy = parse_policy(policy_json_or_preset)?; + let permission_profile = + PermissionProfile::from_legacy_sandbox_policy_for_cwd(&policy, sandbox_policy_cwd); + spawn_windows_sandbox_session_elevated_for_permission_profile( + &permission_profile, + sandbox_policy_cwd, + codex_home, + command, + cwd, + env_map, + timeout_ms, + read_roots_override, + read_roots_include_platform_defaults, + write_roots_override, + deny_read_paths_override, + deny_write_paths_override, + tty, + stdin_open, + use_private_desktop, + ) + .await +} diff --git a/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs b/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs index adb653b6fe..ceb4bd03b6 100644 --- a/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs +++ b/codex-rs/windows-sandbox-rs/src/unified_exec/mod.rs @@ -10,6 +10,7 @@ mod backends; use anyhow::Result; +use codex_protocol::models::PermissionProfile; use codex_utils_absolute_path::AbsolutePathBuf; use codex_utils_pty::SpawnedProcess; use std::collections::HashMap; @@ -48,6 +49,44 @@ pub async fn spawn_windows_sandbox_session_legacy( .await } +#[allow(clippy::too_many_arguments)] +pub async fn spawn_windows_sandbox_session_elevated_for_permission_profile( + permission_profile: &PermissionProfile, + permission_profile_cwd: &Path, + codex_home: &Path, + command: Vec, + cwd: &Path, + env_map: HashMap, + timeout_ms: Option, + read_roots_override: Option<&[PathBuf]>, + read_roots_include_platform_defaults: bool, + write_roots_override: Option<&[PathBuf]>, + deny_read_paths_override: &[AbsolutePathBuf], + deny_write_paths_override: &[AbsolutePathBuf], + tty: bool, + stdin_open: bool, + use_private_desktop: bool, +) -> Result { + backends::elevated::spawn_windows_sandbox_session_elevated_for_permission_profile( + permission_profile, + permission_profile_cwd, + codex_home, + command, + cwd, + env_map, + timeout_ms, + read_roots_override, + read_roots_include_platform_defaults, + write_roots_override, + deny_read_paths_override, + deny_write_paths_override, + tty, + stdin_open, + use_private_desktop, + ) + .await +} + #[allow(clippy::too_many_arguments)] pub async fn spawn_windows_sandbox_session_elevated( policy_json_or_preset: &str,