Skip to content

Add unsigned Windows reproducibility proofs#563

Merged
AnthonyRonning merged 1 commit into
masterfrom
fix/windows-reproducibility
Jun 3, 2026
Merged

Add unsigned Windows reproducibility proofs#563
AnthonyRonning merged 1 commit into
masterfrom
fix/windows-reproducibility

Conversation

@AnthonyRonning
Copy link
Copy Markdown
Contributor

@AnthonyRonning AnthonyRonning commented Jun 3, 2026

Summary

  • move the Windows PR build into scripts/ci/desktop-windows-pr.sh
  • stage ONNX Runtime and VC++ runtime DLLs from pinned, SHA-verified inputs instead of runner-local Visual Studio/System32 copies
  • emit and verify unsigned Windows PR artifact proof manifests
  • align the Windows PR Rust toolchain with the crate/flake pin at 1.88.0

Scope

This handles unsigned Windows PR builds only. Windows master/release signing is intentionally left for a later phase.

Verification

  • nix flake check
  • actionlint .github/workflows/desktop-pr-build.yml
  • bash -n scripts/ci/_common.sh scripts/ci/desktop-windows-pr.sh frontend/src-tauri/scripts/onnxruntime-pins.sh scripts/ci/verify-release-artifacts.sh
  • synthetic scripts/ci/verify-release-artifacts.sh artifacts windows test

Open in Devin Review

Summary by CodeRabbit

  • Documentation

    • Updated Windows bundling docs with revised staging, local build steps, and reproducibility guidance.
  • Chores

    • Streamlined Windows PR build into a single orchestration step.
    • PR builds now stage and publish expanded Windows artifacts (installer, exe, runtime DLLs).
    • CI runs automated verification and reproducibility checks for Windows artifacts.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds pinned VC++/WiX helpers, a PowerShell DLL-staging script, a Windows CI orchestration script, workflow updates to invoke it and upload .exe/.dll artifacts, sccache environment adjustments, and extends artifact verification to validate Windows reproducibility proofs.

Changes

Windows Desktop PR Build and Artifact Verification

Layer / File(s) Summary
Windows VC++ redistributable pinning
frontend/src-tauri/scripts/onnxruntime-pins.sh, frontend/src-tauri/resources/windows/README.md
Adds pinned VC++ redistributable and WiX CLI helper functions (version, URL, SHA-256); documents CI staging and PR reproducibility proof artifacts.
Windows runtime DLL staging script
frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1, frontend/src-tauri/resources/windows/README.md
PowerShell script downloads, SHA-256 verifies, expands, and stages VC redist and ONNX runtime DLLs with retry/backoff, MSI/CAB extraction, recursive DLL lookup, and prints sorted sha256 of staged DLLs; local README updated to use the script.
CI sccache environment configuration
scripts/ci/_common.sh
Reorders sccache-related exports and confines SCCACHE_SERVER_UDS/socket_root setup to non-Windows branches; Windows branch no longer exports SCCACHE_SERVER_UDS and sets SCCACHE_DIR to a Windows-appropriate path.
Windows CI build orchestration
scripts/ci/desktop-windows-pr.sh, .github/workflows/desktop-pr-build.yml
Adds a Windows-only CI entrypoint that prepares ONNX Runtime, stages runtime DLLs, builds frontend/Tauri (no-sign), collects .exe and .dll artifacts and reproducibility manifests; workflow replaces inline Windows build steps and pins Windows Rust toolchain to 1.88.0.
Windows artifact verification support
scripts/ci/verify-release-artifacts.sh, .github/workflows/desktop-pr-build.yml
Adds verify_windows() and windows target to the verifier, updates verify_present() dispatch, and the workflow adds a verify-windows-artifacts job that downloads artifacts and runs verification.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as GitHub Actions (.github/workflows/desktop-pr-build.yml)
  participant Script as scripts/ci/desktop-windows-pr.sh
  participant OrtSetup as scripts/provide-windows-onnxruntime.sh
  participant DllStaging as frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1
  participant Tauri as bun tauri build
  participant VerifyArtifacts as scripts/ci/verify-release-artifacts.sh
  Workflow->>Script: invoke Windows PR build step
  Script->>OrtSetup: prepare ONNX runtime (export ORT_* values)
  Script->>DllStaging: stage VC redist and copy onnxruntime.dll into resources/windows
  Script->>Tauri: build frontend dist and unsigned Windows bundle
  Script->>Script: collect .exe and .dll artifacts, generate SHA-256 manifests
  Workflow->>VerifyArtifacts: download artifacts and run verifier (windows)
  VerifyArtifacts->>Workflow: confirm final and runtime DLL proof verification
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • OpenSecretCloud/Maple#547: Modifies scripts/ci/verify-release-artifacts.sh target dispatch and proof-verification logic, overlapping with Windows verifier changes here.
  • OpenSecretCloud/Maple#520: Related to Windows ONNX Runtime provisioning and pinning helpers that this PR builds upon.
  • OpenSecretCloud/Maple#533: Touches shared CI plumbing in scripts/ci/_common.sh, related to SCCACHE/env wiring adjusted in this PR.

"🐰 I hopped through build and script,
Downloaded VC redist with a twirl,
DLLs staged, hashes unfurled,
CI checks the proofs with care,
Windows builds now dance in air."

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Add unsigned Windows reproducibility proofs' directly and accurately summarizes the main objective of the changeset, which adds Windows artifact verification and reproducibility proof manifests to the CI workflow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/windows-reproducibility

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jun 3, 2026

Deploying maple with  Cloudflare Pages  Cloudflare Pages

Latest commit: 73f4453
Status: ✅  Deploy successful!
Preview URL: https://c1bb27c6.maple-ca8.pages.dev
Branch Preview URL: https://fix-windows-reproducibility.maple-ca8.pages.dev

View logs

coderabbitai[bot]

This comment was marked as resolved.

@AnthonyRonning AnthonyRonning force-pushed the fix/windows-reproducibility branch from 6272646 to c6661e9 Compare June 3, 2026 17:10
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/ci/desktop-windows-pr.sh (1)

79-98: 💤 Low value

Optional: guard against empty artifact/DLL sets before writing the proof manifests.

find runs inside a process substitution, so a missing bundle/nsis tree (or zero matches) is silently swallowed and yields an empty array. The resulting *.sha256 manifests would then be empty proofs rather than failing loudly. Adding a non-empty check makes the reproducibility proof self-validating.

♻️ Proposed guard
+if [ "${`#windows_artifacts`[@]}" -eq 0 ]; then
+  echo "No Windows .exe artifacts found under target/release/bundle/nsis" >&2
+  exit 1
+fi
+if [ "${`#windows_runtime_dlls`[@]}" -eq 0 ]; then
+  echo "No staged runtime DLLs found under resources/windows" >&2
+  exit 1
+fi
 write_sha256_manifest "${repro_dir}/desktop-pr-windows-final.sha256" "${windows_artifacts[@]}"
 write_sha256_manifest "${repro_dir}/desktop-pr-windows-runtime-dlls.sha256" "${windows_runtime_dlls[@]}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/desktop-windows-pr.sh` around lines 79 - 98, The script currently
calls write_sha256_manifest and print_file_hashes unconditionally, which can
produce empty proof files when windows_artifacts or windows_runtime_dlls are
empty; add guards that check the arrays (windows_artifacts and
windows_runtime_dlls) are non-empty before calling write_sha256_manifest and
print_file_hashes and, if empty, emit a clear error message (including the
variable name and TAURI_DIR context) and exit non‑zero to fail the job;
implement these checks right before the write_sha256_manifest calls so
write_sha256_manifest and print_file_hashes are only invoked for non-empty sets
while leaving verify_frontend_dist_unchanged unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/ci/desktop-windows-pr.sh`:
- Around line 79-98: The script currently calls write_sha256_manifest and
print_file_hashes unconditionally, which can produce empty proof files when
windows_artifacts or windows_runtime_dlls are empty; add guards that check the
arrays (windows_artifacts and windows_runtime_dlls) are non-empty before calling
write_sha256_manifest and print_file_hashes and, if empty, emit a clear error
message (including the variable name and TAURI_DIR context) and exit non‑zero to
fail the job; implement these checks right before the write_sha256_manifest
calls so write_sha256_manifest and print_file_hashes are only invoked for
non-empty sets while leaving verify_frontend_dist_unchanged unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 701b5da5-a2d8-4a8f-8330-686c00da4b1d

📥 Commits

Reviewing files that changed from the base of the PR and between 6272646 and c6661e9.

📒 Files selected for processing (7)
  • .github/workflows/desktop-pr-build.yml
  • frontend/src-tauri/resources/windows/README.md
  • frontend/src-tauri/scripts/onnxruntime-pins.sh
  • frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1
  • scripts/ci/_common.sh
  • scripts/ci/desktop-windows-pr.sh
  • scripts/ci/verify-release-artifacts.sh
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src-tauri/resources/windows/README.md
  • .github/workflows/desktop-pr-build.yml
  • scripts/ci/_common.sh
  • scripts/ci/verify-release-artifacts.sh

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 6 additional findings.

Open in Devin Review

@AnthonyRonning AnthonyRonning force-pushed the fix/windows-reproducibility branch from c6661e9 to 20f01a2 Compare June 3, 2026 17:26
coderabbitai[bot]

This comment was marked as resolved.

@AnthonyRonning AnthonyRonning force-pushed the fix/windows-reproducibility branch 2 times, most recently from de911a1 to 3f160b8 Compare June 3, 2026 17:40
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (3)
frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1 (2)

307-323: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear previously staged DLLs before copying the new set.

desktop-windows-pr.sh hashes every resources/windows/*.dll, so any leftover DLL from an earlier run becomes part of the uploaded and verified proof set. Remove existing *.dll files in $Destination before staging the new runtime set.

Suggested fix
 New-Item -ItemType Directory -Force -Path $Destination, $redistDir | Out-Null
+Get-ChildItem -LiteralPath $Destination -Filter "*.dll" -File -ErrorAction SilentlyContinue |
+  Remove-Item -Force
 
 if (!(Test-Path -LiteralPath $redistExe)) {
   Invoke-Download -Url $vcRedistUrl -OutFile $redistExe
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1` around lines 307 -
323, Before copying the new runtime DLLs, delete any existing DLLs in the target
folder to avoid stale files being included in the uploaded hash set: add a step
in stage-windows-runtime-dlls.ps1 that removes existing *.dll entries from
$Destination (use the $Destination variable and wildcard *.dll) prior to the
Copy-Item of $OrtDllPath and the foreach loop over $dllNames so the directory
contains only the freshly staged runtime DLLs.

219-246: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Constrain DLL resolution to x64 payloads.

This still returns the first name/metadata match across every extracted root, so vc_redist.x64.exe can stage an ARM64 runtime DLL when both architectures are present. Filter candidates by PE machine type, or by a known x64 subtree, before both return paths.

Suggested fix
+function Test-PortableExecutableMachineAmd64 {
+  param([Parameter(Mandatory = $true)][string] $Path)
+
+  $stream = [IO.File]::OpenRead($Path)
+  try {
+    $reader = New-Object IO.BinaryReader($stream)
+    if ($reader.ReadUInt16() -ne 0x5A4D) {
+      return $false
+    }
+
+    $stream.Position = 0x3C
+    $peOffset = $reader.ReadInt32()
+    $stream.Position = $peOffset + 4
+    return $reader.ReadUInt16() -eq 0x8664
+  } finally {
+    $stream.Dispose()
+  }
+}
+
   $match = $files |
-    Where-Object { $_.Name -ieq $Name } |
+    Where-Object { ($_.Name -ieq $Name) -and (Test-PortableExecutableMachineAmd64 -Path $_.FullName) } |
     Sort-Object FullName |
     Select-Object -First 1
...
     if (
-      ($versionInfo.OriginalFilename -ieq $Name) -or
-      ($versionInfo.InternalName -ieq $Name) -or
-      ($versionInfo.FileDescription -ieq $Name)
+      (
+        ($versionInfo.OriginalFilename -ieq $Name) -or
+        ($versionInfo.InternalName -ieq $Name) -or
+        ($versionInfo.FileDescription -ieq $Name)
+      ) -and
+      (Test-PortableExecutableMachineAmd64 -Path $file.FullName)
     ) {
       Write-Host ("resolved-windows-runtime-dll  {0}  {1}" -f $Name, $file.FullName)
       return $file.FullName
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1` around lines 219 -
246, The current resolver picks the first filename/metadata match from $files
(via $match and the subsequent foreach over $file/ $versionInfo) without
ensuring the binary is x64; update the logic to pre-filter candidates to
x64-only before any early-return. Constrain the search by filtering $files to an
x64 subtree (e.g. paths containing an x64 folder) or inspect each candidate's PE
machine type (when iterating $file, validate the PE header indicates
IMAGE_FILE_MACHINE_AMD64) and only consider those for the initial $match check
and the metadata-based return paths that call return $file.FullName.
scripts/ci/desktop-windows-pr.sh (1)

55-58: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Convert ORT_DYLIB_PATH before passing it to PowerShell.

If provide-windows-onnxruntime.sh emits an MSYS path like /c/..., Copy-Item -LiteralPath in stage-windows-runtime-dlls.ps1 can fail before any runtime manifest is produced. Pass the DLL path through to_windows_path here too.

Suggested fix
   pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass \
     -File "$(to_windows_path "${TAURI_DIR}/scripts/stage-windows-runtime-dlls.ps1")" \
-    -OrtDllPath "${ORT_DYLIB_PATH:?ORT_DYLIB_PATH is required}" \
+    -OrtDllPath "$(to_windows_path "${ORT_DYLIB_PATH:?ORT_DYLIB_PATH is required}")" \
     -Destination "$(to_windows_path "${TAURI_DIR}/resources/windows")"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/desktop-windows-pr.sh` around lines 55 - 58, The pwsh call is
passing ORT_DYLIB_PATH as a POSIX/MSYS path which can break Copy-Item in
stage-windows-runtime-dlls.ps1; wrap the variable with to_windows_path before
passing it to PowerShell so the DLL path is converted to a Windows-style path.
Update the pwsh invocation argument -OrtDllPath
"${ORT_DYLIB_PATH:?ORT_DYLIB_PATH is required}" to use to_windows_path (i.e.
call to_windows_path on ORT_DYLIB_PATH) so the script
stage-windows-runtime-dlls.ps1 receives a proper Windows path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1`:
- Around line 307-323: Before copying the new runtime DLLs, delete any existing
DLLs in the target folder to avoid stale files being included in the uploaded
hash set: add a step in stage-windows-runtime-dlls.ps1 that removes existing
*.dll entries from $Destination (use the $Destination variable and wildcard
*.dll) prior to the Copy-Item of $OrtDllPath and the foreach loop over $dllNames
so the directory contains only the freshly staged runtime DLLs.
- Around line 219-246: The current resolver picks the first filename/metadata
match from $files (via $match and the subsequent foreach over $file/
$versionInfo) without ensuring the binary is x64; update the logic to pre-filter
candidates to x64-only before any early-return. Constrain the search by
filtering $files to an x64 subtree (e.g. paths containing an x64 folder) or
inspect each candidate's PE machine type (when iterating $file, validate the PE
header indicates IMAGE_FILE_MACHINE_AMD64) and only consider those for the
initial $match check and the metadata-based return paths that call return
$file.FullName.

In `@scripts/ci/desktop-windows-pr.sh`:
- Around line 55-58: The pwsh call is passing ORT_DYLIB_PATH as a POSIX/MSYS
path which can break Copy-Item in stage-windows-runtime-dlls.ps1; wrap the
variable with to_windows_path before passing it to PowerShell so the DLL path is
converted to a Windows-style path. Update the pwsh invocation argument
-OrtDllPath "${ORT_DYLIB_PATH:?ORT_DYLIB_PATH is required}" to use
to_windows_path (i.e. call to_windows_path on ORT_DYLIB_PATH) so the script
stage-windows-runtime-dlls.ps1 receives a proper Windows path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a260229-9b46-4b45-be1a-59a0e99583fa

📥 Commits

Reviewing files that changed from the base of the PR and between de911a1 and 3f160b8.

📒 Files selected for processing (7)
  • .github/workflows/desktop-pr-build.yml
  • frontend/src-tauri/resources/windows/README.md
  • frontend/src-tauri/scripts/onnxruntime-pins.sh
  • frontend/src-tauri/scripts/stage-windows-runtime-dlls.ps1
  • scripts/ci/_common.sh
  • scripts/ci/desktop-windows-pr.sh
  • scripts/ci/verify-release-artifacts.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • scripts/ci/verify-release-artifacts.sh
  • frontend/src-tauri/scripts/onnxruntime-pins.sh
  • frontend/src-tauri/resources/windows/README.md
  • .github/workflows/desktop-pr-build.yml
  • scripts/ci/_common.sh

@AnthonyRonning AnthonyRonning force-pushed the fix/windows-reproducibility branch from 3f160b8 to d84d200 Compare June 3, 2026 19:15
@AnthonyRonning AnthonyRonning force-pushed the fix/windows-reproducibility branch from d84d200 to 73f4453 Compare June 3, 2026 19:18
@AnthonyRonning AnthonyRonning merged commit 281031f into master Jun 3, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant