From da3922586ab9bf7796a3a7b6849328a5acd95a80 Mon Sep 17 00:00:00 2001 From: Hampus Date: Tue, 25 Aug 2026 23:54:33 +0200 Subject: [PATCH] fix(desktop): restore Windows canary builds (#2017) --- tools/ci/src/desktop.rs | 145 +++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 39 deletions(-) diff --git a/tools/ci/src/desktop.rs b/tools/ci/src/desktop.rs index 9765ba3f1..b0ce02c6d 100644 --- a/tools/ci/src/desktop.rs +++ b/tools/ci/src/desktop.rs @@ -897,10 +897,32 @@ fn apt_get(args: &[&str]) -> Result<()> { } fn install_msvc_arm64_tools_step() -> Result<()> { - let installer = - Path::new(r"C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe"); - let install_path = Path::new(r"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"); - run_command(CommandSpec::new(installer).args([ + let program_files_x86 = env::var_os("ProgramFiles(x86)") + .map(PathBuf::from) + .ok_or_else(|| anyhow!("ProgramFiles(x86) is not set on the Windows runner"))?; + let installer_dir = program_files_x86 + .join("Microsoft Visual Studio") + .join("Installer"); + let installer = installer_dir.join("setup.exe"); + let vswhere = installer_dir.join("vswhere.exe"); + ensure!( + vswhere.is_file(), + "Visual Studio locator not found: {}", + vswhere.display() + ); + + let install_path = resolve_visual_studio_install_path(&vswhere)?; + if let Some(linker) = find_msvc_arm64_linker(&install_path)? { + println!("ARM64 cross link.exe: {}", linker.display()); + return Ok(()); + } + ensure!( + installer.is_file(), + "Visual Studio installer not found: {}", + installer.display() + ); + + run_command(CommandSpec::new(&installer).args([ "modify", "--installPath", install_path.to_string_lossy().as_ref(), @@ -924,30 +946,66 @@ fn install_msvc_arm64_tools_step() -> Result<()> { "VS installer did not finish within the timeout." ); - let mut found = false; + let linker = find_msvc_arm64_linker(&install_path)?.ok_or_else(|| { + anyhow!( + "ARM64 cross-build tools were not installed under {}\\VC\\Tools\\MSVC\\*\\bin\\HostX64\\arm64", + install_path.display() + ) + })?; + println!("ARM64 cross link.exe: {}", linker.display()); + Ok(()) +} + +fn resolve_visual_studio_install_path(vswhere: &Path) -> Result { + let output = output_text(CommandSpec::new(vswhere).args([ + "-products", + "*", + "-latest", + "-prerelease", + "-property", + "installationPath", + ]))?; + let paths = output + .lines() + .map(str::trim) + .filter(|line| !line.is_empty()) + .collect::>(); + ensure!( + paths.len() == 1, + "vswhere returned {} Visual Studio installation paths; expected exactly one", + paths.len() + ); + let install_path = PathBuf::from(paths[0]); + ensure!( + install_path.is_dir(), + "vswhere returned a missing Visual Studio installation: {}", + install_path.display() + ); + println!("Visual Studio installation: {}", install_path.display()); + Ok(install_path) +} + +fn find_msvc_arm64_linker(install_path: &Path) -> Result> { let msvc_root = install_path.join("VC").join("Tools").join("MSVC"); - if msvc_root.exists() { - for entry in fs::read_dir(&msvc_root) - .with_context(|| format!("Failed to read {}", msvc_root.display()))? - { - let candidate = entry? - .path() - .join("bin") - .join("HostX64") - .join("arm64") - .join("link.exe"); - if candidate.exists() { - println!("ARM64 cross link.exe: {}", candidate.display()); - found = true; - } + if !msvc_root.is_dir() { + return Ok(None); + } + let mut linkers = Vec::new(); + for entry in fs::read_dir(&msvc_root) + .with_context(|| format!("Failed to read {}", msvc_root.display()))? + { + let candidate = entry? + .path() + .join("bin") + .join("HostX64") + .join("arm64") + .join("link.exe"); + if candidate.is_file() { + linkers.push(candidate); } } - ensure!( - found, - "ARM64 cross-build tools were not installed under {}\\*\\bin\\HostX64\\arm64.", - msvc_root.display() - ); - Ok(()) + linkers.sort(); + Ok(linkers.pop()) } fn windows_installer_process_running() -> Result { @@ -1823,7 +1881,16 @@ fn create_portable_zip_windows_step() -> Result<()> { } const FLUXER_WINDOWS_SIGNER_COMMON_NAME: &str = "Fluxer Platform AB"; -const THIRD_PARTY_PUBLISHER_ALLOWLIST: &[&str] = &[]; +const THIRD_PARTY_WINDOWS_SIGNATURE_ALLOWLIST: &[(&str, &str)] = &[ + ( + "d3dcompiler_47.dll", + "CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", + ), + ( + "dxil.dll", + "CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", + ), +]; const KNOWN_OPTIONAL_WINDOWS_PE_INVENTORY: &[&str] = &["fluxer-vulkan-layer.win32-ia32-msvc.dll"]; const WINDOWS_NATIVE_ADDON_STEMS: &[&str] = &[ "hardware-encoder", @@ -2144,7 +2211,7 @@ fn assert_fluxer_signed(row: &SignatureRow) -> Result<()> { Ok(()) } -fn assert_third_party_signed(row: &SignatureRow) -> Result<()> { +fn assert_third_party_signed(row: &SignatureRow, relative: &str) -> Result<()> { ensure!( row.status == "Valid", "Authenticode status is {} (expected Valid)", @@ -2154,11 +2221,13 @@ fn assert_third_party_signed(row: &SignatureRow) -> Result<()> { .subject .as_deref() .ok_or_else(|| anyhow!("Authenticode signature has no signer certificate subject"))?; - let common_name = certificate_common_name(subject) - .ok_or_else(|| anyhow!("Signer subject has no CN= component: {subject}"))?; ensure!( - THIRD_PARTY_PUBLISHER_ALLOWLIST.contains(&common_name), - "Signer CN '{common_name}' is not an allowlisted third-party publisher" + THIRD_PARTY_WINDOWS_SIGNATURE_ALLOWLIST + .iter() + .any(|(allowed_path, allowed_subject)| { + relative.eq_ignore_ascii_case(allowed_path) && subject == *allowed_subject + }), + "Signer subject '{subject}' is not allowlisted for {relative}" ); ensure!( row.ts_subject.is_some(), @@ -2167,10 +2236,10 @@ fn assert_third_party_signed(row: &SignatureRow) -> Result<()> { Ok(()) } -fn assert_signed_by_known_publisher(row: &SignatureRow) -> Result<()> { +fn assert_signed_by_known_publisher(row: &SignatureRow, relative: &str) -> Result<()> { match assert_fluxer_signed(row) { Ok(()) => Ok(()), - Err(fluxer_error) => assert_third_party_signed(row) + Err(fluxer_error) => assert_third_party_signed(row, relative) .map_err(|third_party_error| anyhow!("{fluxer_error}; {third_party_error}")), } } @@ -2333,22 +2402,20 @@ fn verify_windows_pe_signatures( )); continue; }; - if let Err(error) = assert_signed_by_known_publisher(row) { + if let Err(error) = assert_signed_by_known_publisher(row, &relative) { failures.push(format!("{relative}: {error}")); } } ensure!( failures.is_empty(), - "{label}: {} of {} Windows binaries are not signed by '{}':\n{}", + "{label}: {} of {} Windows binaries do not have an approved signature:\n{}", failures.len(), files.len(), - FLUXER_WINDOWS_SIGNER_COMMON_NAME, failures.join("\n") ); println!( - "{label}: verified {} Windows binaries signed by '{}'.", - files.len(), - FLUXER_WINDOWS_SIGNER_COMMON_NAME + "{label}: verified {} Windows binary signatures.", + files.len() ); Ok(()) }