From ab82cddd049a4c72d3e23a1ebeb0c63c0d9c530b Mon Sep 17 00:00:00 2001 From: zm-oai Date: Thu, 20 Aug 2026 01:37:58 +0000 Subject: [PATCH] Resolve bundled Windows helpers through bin junctions (#39649) ## Why Installer `bin` directories can be junctions, so looking for bundled helpers relative to the apparent executable path can miss the package's `codex-resources` directory. ## What changed Retry bundled executable lookup from the canonical executable path when lookup from the original path fails. ## Testing Add a Windows regression test that creates a `bin` junction and verifies that the sandbox setup helper is resolved from the package resources directory. GitOrigin-RevId: f2f20ce1ccfa95ae65171a03a986d10e2560e696 --- .../src/helper_materialization.rs | 67 ++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/codex-rs/windows-sandbox-rs/src/helper_materialization.rs b/codex-rs/windows-sandbox-rs/src/helper_materialization.rs index bcc09f1250..7532d191ea 100644 --- a/codex-rs/windows-sandbox-rs/src/helper_materialization.rs +++ b/codex-rs/windows-sandbox-rs/src/helper_materialization.rs @@ -192,23 +192,28 @@ fn sibling_source_path(kind: HelperExecutable) -> Result { } pub(crate) fn bundled_executable_path_for_exe(exe: &Path, file_name: &str) -> Option { - let dir = exe.parent()?; - let direct_candidate = dir.join(file_name); - if direct_candidate.is_file() { - return Some(direct_candidate); - } - - if dir.file_name() == Some(OsStr::new(BIN_DIRNAME)) - && let Some(package_dir) = dir.parent() - { - let package_resource_candidate = package_dir.join(RESOURCES_DIRNAME).join(file_name); - if package_resource_candidate.is_file() { - return Some(package_resource_candidate); + let find = |exe: &Path| { + let dir = exe.parent()?; + let direct_candidate = dir.join(file_name); + if direct_candidate.is_file() { + return Some(direct_candidate); } - } - let resource_candidate = dir.join(RESOURCES_DIRNAME).join(file_name); - resource_candidate.is_file().then_some(resource_candidate) + if dir.file_name() == Some(OsStr::new(BIN_DIRNAME)) + && let Some(package_dir) = dir.parent() + { + let package_resource_candidate = package_dir.join(RESOURCES_DIRNAME).join(file_name); + if package_resource_candidate.is_file() { + return Some(package_resource_candidate); + } + } + + let resource_candidate = dir.join(RESOURCES_DIRNAME).join(file_name); + resource_candidate.is_file().then_some(resource_candidate) + }; + + // Installer bin directories can be junctions, so retry beside the real executable once. + find(exe).or_else(|| find(&dunce::canonicalize(exe).ok()?)) } fn helper_destination_for_source( @@ -500,6 +505,38 @@ mod tests { assert_eq!(resolved, helper); } + #[test] + fn helper_source_lookup_resolves_bin_junctions() { + let tmp = TempDir::new().expect("tempdir"); + let package_dir = tmp.path().join("package"); + let bin_dir = package_dir.join(BIN_DIRNAME); + let resources_dir = package_dir.join(RESOURCES_DIRNAME); + let install_dir = tmp.path().join("install"); + fs::create_dir_all(&bin_dir).expect("create bin dir"); + fs::create_dir_all(&resources_dir).expect("create resources dir"); + fs::create_dir_all(&install_dir).expect("create install dir"); + fs::write(bin_dir.join("codex.exe"), b"codex").expect("write exe"); + let helper = resources_dir.join("codex-windows-sandbox-setup.exe"); + fs::write(&helper, b"setup").expect("write helper"); + + let junction = install_dir.join(BIN_DIRNAME); + let output = std::process::Command::new("cmd") + .args(["/c", "mklink", "/J"]) + .arg(&junction) + .arg(&bin_dir) + .output() + .expect("create bin junction"); + assert!(output.status.success()); + + assert_eq!( + bundled_executable_path_for_exe( + &junction.join("codex.exe"), + /*file_name*/ "codex-windows-sandbox-setup.exe" + ), + Some(dunce::canonicalize(&helper).expect("canonical helper")) + ); + } + #[test] fn helper_source_lookup_prefers_package_resource_dir_over_bin_resource_dir() { let tmp = TempDir::new().expect("tempdir");