use super::windows_common::finish_driver_spawn;use super::windows_common::make_runner_resizer;use super::windows_common::start_runner_pipe_writer;use super::windows_common::start_runner_stdin_writer;use super::windows_common::start_runner_stdout_reader;use crate::identity::SandboxCreds;use crate::identity::refresh_logon_sandbox_creds;use crate::ipc_framed::EmptyPayload;use crate::ipc_framed::FramedMessage;use crate::ipc_framed::IPC_PROTOCOL_VERSION;use crate::ipc_framed::Message;use crate::ipc_framed::SpawnRequest;use crate::resolved_permissions::ResolvedWindowsSandboxPermissions;use crate::runner_client::RunnerTransport;use crate::runner_client::is_stale_sandbox_creds_error;use crate::runner_client::spawn_runner_transport;use crate::spawn_prep::prepare_elevated_spawn_context_for_permissions;use anyhow::Result;use codex_protocol::models::PermissionProfile;use codex_utils_absolute_path::AbsolutePathBuf;use codex_utils_pty::ProcessDriver;use codex_utils_pty::SpawnedProcess;use std::collections::HashMap;use std::path::Path;use std::path::PathBuf;use tokio::sync::broadcast;use tokio::sync::mpsc;use tokio::sync::oneshot;async fn spawn_runner_transport_task( codex_home: PathBuf, cwd: PathBuf, sandbox_creds: SandboxCreds, logs_base_dir: Option<PathBuf>, spawn_request: SpawnRequest,) -> Result<RunnerTransport> { tokio::task::spawn_blocking(move || -> Result<_> { spawn_runner_transport( &codex_home, &cwd, &sandbox_creds, logs_base_dir.as_deref(), spawn_request, ) }) .await .map_err(|err| anyhow::anyhow!("runner handshake task failed: {err}"))?}#[allow(clippy::too_many_arguments)]pub(crate) async fn spawn_windows_sandbox_session_elevated_for_permission_profile( permission_profile: &PermissionProfile, workspace_roots: &[AbsolutePathBuf], codex_home: &Path, command: Vec<String>, cwd: &Path, mut env_map: HashMap<String, String>, proxy_enforced: bool, timeout_ms: Option<u64>, 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<SpawnedProcess> { let deny_read_paths_override = deny_read_paths_override .iter() .map(AbsolutePathBuf::to_path_buf) .collect::<Vec<_>>(); let deny_write_paths_override = deny_write_paths_override .iter() .map(AbsolutePathBuf::to_path_buf) .collect::<Vec<_>>(); let permissions = ResolvedWindowsSandboxPermissions::try_from_permission_profile_for_workspace_roots( permission_profile, workspace_roots, )?; let elevated = prepare_elevated_spawn_context_for_permissions( permissions.clone(), codex_home, cwd, &mut env_map, &command, read_roots_override, read_roots_include_platform_defaults, write_roots_override, &deny_read_paths_override, &deny_write_paths_override, proxy_enforced, )?; let spawn_request = SpawnRequest { command: command.clone(), cwd: cwd.to_path_buf(), env: env_map.clone(), permission_profile: permission_profile.clone(), workspace_roots: workspace_roots.to_vec(), codex_home: elevated.sandbox_base.clone(), real_codex_home: codex_home.to_path_buf(), cap_sids: elevated.cap_sids.clone(), timeout_ms, tty, stdin_open, use_private_desktop, }; let codex_home = codex_home.to_path_buf(); let cwd = cwd.to_path_buf(); let sandbox_creds = elevated.sandbox_creds; let logs_base_dir = elevated.logs_base_dir.clone(); let transport = match spawn_runner_transport_task( codex_home.clone(), cwd.clone(), sandbox_creds, logs_base_dir.clone(), spawn_request.clone(), ) .await { Ok(transport) => transport, Err(err) if is_stale_sandbox_creds_error(&err) => { let sandbox_creds = refresh_logon_sandbox_creds( &permissions, &cwd, &env_map, &codex_home, read_roots_override, read_roots_include_platform_defaults, write_roots_override, &deny_read_paths_override, &deny_write_paths_override, /*proxy_enforced*/ false, )?; spawn_runner_transport_task( codex_home, cwd, sandbox_creds, logs_base_dir, spawn_request, ) .await? } Err(err) => return Err(err), }; let (pipe_write, pipe_read) = transport.into_files(); let (writer_tx, writer_rx) = mpsc::channel::<Vec<u8>>(128); let (stdout_tx, stdout_rx) = broadcast::channel::<Vec<u8>>(256); let stderr_rx = if tty { None } else { Some(broadcast::channel::<Vec<u8>>(256)) }; let (exit_tx, exit_rx) = oneshot::channel::<i32>(); let outbound_tx = start_runner_pipe_writer(pipe_write); let writer_handle = start_runner_stdin_writer(writer_rx, outbound_tx.clone(), tty, stdin_open); let terminator = { let outbound_tx = outbound_tx.clone(); Some(Box::new(move || { let _ = outbound_tx.send(FramedMessage { version: IPC_PROTOCOL_VERSION, message: Message::Terminate { payload: EmptyPayload::default(), }, }); }) as Box<dyn FnMut() + Send + Sync>) }; start_runner_stdout_reader( pipe_read, stdout_tx, stderr_rx.as_ref().map(|(tx, _rx)| tx.clone()), exit_tx, ); Ok(finish_driver_spawn( ProcessDriver { writer_tx, stdout_rx, stderr_rx: stderr_rx.map(|(_tx, rx)| rx), exit_rx, terminator, writer_handle: Some(writer_handle), resizer: if tty { Some(make_runner_resizer(outbound_tx)) } else { None }, }, stdin_open, ))}