From c1605ffebf411d54ac9cbe8e99db2d5a2a666c77 Mon Sep 17 00:00:00 2001 From: David Wiesen Date: Sat, 21 Mar 2026 10:36:42 -0700 Subject: [PATCH] Materialize Windows sandbox setup helper --- .../src/helper_materialization.rs | 24 ++++++++++++++++++- .../src/setup_orchestrator.rs | 22 ++++++++--------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/codex-rs/windows-sandbox-rs/src/helper_materialization.rs b/codex-rs/windows-sandbox-rs/src/helper_materialization.rs index 37db3c59c2..feb31de9cf 100644 --- a/codex-rs/windows-sandbox-rs/src/helper_materialization.rs +++ b/codex-rs/windows-sandbox-rs/src/helper_materialization.rs @@ -16,18 +16,21 @@ use crate::sandbox_bin_dir; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub(crate) enum HelperExecutable { CommandRunner, + SetupHelper, } impl HelperExecutable { fn file_name(self) -> &'static str { match self { Self::CommandRunner => "codex-command-runner.exe", + Self::SetupHelper => "codex-windows-sandbox-setup.exe", } } fn label(self) -> &'static str { match self { Self::CommandRunner => "command-runner", + Self::SetupHelper => "setup-helper", } } } @@ -376,5 +379,24 @@ mod tests { fs::read(&runner_destination).expect("read runner") ); } -} + #[test] + fn copy_setup_helper_into_shared_bin_dir() { + let tmp = TempDir::new().expect("tempdir"); + let codex_home = tmp.path().join("codex-home"); + let source_dir = tmp.path().join("sibling-source"); + fs::create_dir_all(&source_dir).expect("create source dir"); + let setup_source = source_dir.join("codex-windows-sandbox-setup.exe"); + let setup_destination = helper_bin_dir(&codex_home).join("codex-windows-sandbox-setup.exe"); + fs::write(&setup_source, b"setup").expect("setup helper"); + + let setup_outcome = + copy_from_source_if_needed(&setup_source, &setup_destination).expect("setup copy"); + + assert_eq!(CopyOutcome::ReCopied, setup_outcome); + assert_eq!( + b"setup".as_slice(), + fs::read(&setup_destination).expect("read setup helper") + ); + } +} diff --git a/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs b/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs index 317a4d467c..5dc7de5641 100644 --- a/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs +++ b/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs @@ -12,6 +12,8 @@ use std::process::Stdio; use crate::allow::compute_allow_paths; use crate::allow::AllowDenyPaths; use crate::helper_materialization::helper_bin_dir; +use crate::helper_materialization::resolve_helper_for_launch; +use crate::helper_materialization::HelperExecutable; use crate::logging::log_note; use crate::path_normalization::canonical_path_key; use crate::policy::SandboxPolicy; @@ -155,7 +157,7 @@ fn run_setup_refresh_inner( }; let json = serde_json::to_vec(&payload)?; let b64 = BASE64_STANDARD.encode(json); - let exe = find_setup_exe(); + let exe = find_setup_exe(codex_home); // Refresh should never request elevation; ensure verb isn't set and we don't trigger UAC. let mut cmd = Command::new(&exe); cmd.arg(&b64).stdout(Stdio::null()).stderr(Stdio::null()); @@ -431,16 +433,12 @@ fn quote_arg(arg: &str) -> String { out } -fn find_setup_exe() -> PathBuf { - if let Ok(exe) = std::env::current_exe() { - if let Some(dir) = exe.parent() { - let candidate = dir.join("codex-windows-sandbox-setup.exe"); - if candidate.exists() { - return candidate; - } - } - } - PathBuf::from("codex-windows-sandbox-setup.exe") +fn find_setup_exe(codex_home: &Path) -> PathBuf { + resolve_helper_for_launch( + HelperExecutable::SetupHelper, + codex_home, + Some(&sandbox_dir(codex_home)), + ) } fn report_helper_failure( @@ -473,7 +471,7 @@ fn run_setup_exe( use windows_sys::Win32::UI::Shell::ShellExecuteExW; use windows_sys::Win32::UI::Shell::SEE_MASK_NOCLOSEPROCESS; use windows_sys::Win32::UI::Shell::SHELLEXECUTEINFOW; - let exe = find_setup_exe(); + let exe = find_setup_exe(codex_home); let payload_json = serde_json::to_string(payload).map_err(|err| { failure( SetupErrorCode::OrchestratorPayloadSerializeFailed,