feat(packaging): wire Windows Authenticode signing, activated by repo secrets (#36, #37) - #480
Open
lmanchu wants to merge 1 commit into
Open
feat(packaging): wire Windows Authenticode signing, activated by repo secrets (#36, #37)#480lmanchu wants to merge 1 commit into
lmanchu wants to merge 1 commit into
Conversation
Windows installers ship unsigned today (andrewyng#36, andrewyng#37): SmartScreen trains users to click through, and Smart App Control machines block the app outright with no override. The maintainer position is that no signing account exists yet - so this change makes signing a repo-secret away without requiring one now. build_windows.ps1 resolves credentials from the environment (custom sign-command template > cert-store thumbprint > base64 PFX import), signs the PyInstaller sidecar explicitly - Tauri's bundler only signs its own outputs, and SAC evaluates every PE at run time, so an unsigned sidecar fails on SAC machines even inside a signed installer - then hands Tauri the signing config through the existing --config overlay mechanism. Every produced artifact is verified signed, and the build fails if one is not. With no credentials in the environment the build is byte-for-byte the current unsigned behavior. release.yml passes the new secrets through (empty = absent), and docs/windows-signing.md is the procurement decision guide (Trusted Signing vs OV cloud-HSM vs EV token), the runbook, and the field notes from shipping a Tauri + PyInstaller-sidecar app through OEM QA. Deliberately NOT in tauri.conf.json: a hardcoded certificateThumbprint breaks tauri build on every machine without that cert. 🤖 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Towards #36 / #37 (Windows builds are unsigned). Per the maintainer note in #36 there is no signing account yet — so this PR does not require one. It makes the release pipeline signing-ready: when a signing credential lands as a repo secret, the next release comes out fully signed; until then (and on forks / scratch runs) every build is byte-for-byte the current unsigned behavior. The included doc is the procurement decision guide for when that account gets opened.
This deliberately mirrors the two patterns the repo already uses: the macOS
APPLE_*block inrelease.yml(secrets present → signed; absent → degrade gracefully) and the existingTAURI_SIGNING_PRIVATE_KEYoverlay mechanism inbuild_windows.ps1.What changed
packaging/build_windows.ps1— resolves credentials from the environment, first match wins, all-absent = no-op:WINDOWS_SIGN_COMMAND— custom command template (%1= file), the escape hatch that fits any cloud signing CLI (Azure Trusted Signing, KeyLocker, eSigner, …)WINDOWS_CERTIFICATE_THUMBPRINT—signtoolagainst a cert already in the store (hardware token / pre-provisioned runner)WINDOWS_CERTIFICATE(+_PASSWORD) — base64 PFX, imported for the build and then signed by thumbprint, so the password never reaches a command line or config fileIt signs the PyInstaller sidecar explicitly before
tauri build: the sidecar ships viaresources, which the bundler copies verbatim — and Smart App Control evaluates every PE at run time, so a signed installer with an unsigned sidecar installs fine and then dies at first backend start (a failure mode that presents exactly like #382). After the build, every produced.exe/.msiis verified to carry a valid signature and the build fails otherwise — a sign step that silently no-ops is worse than an unsigned build..github/workflows/release.yml— passes the new secrets through (unset secrets arrive as empty strings and count as absent) and documents them in the header, mirroring theAPPLE_*block.docs/windows-signing.md— procurement decision matrix (Trusted Signing ~$10/mo with immediate SmartScreen reputation, vs OV cloud-HSM, vs EV token and why tokens don't fit CI), the runbook, verification commands, and field notes from shipping a Tauri + PyInstaller-sidecar app through OEM QA on SAC-enabled machines.README.md— the Windows download caption now points at the doc.Deliberately NOT in
tauri.conf.json: a hardcodedcertificateThumbprintmakestauri buildfail on every machine that doesn't hold that cert. Signing config travels through a generated--configoverlay only; dev builds stay green with zero setup.Validation
Ran this branch's full Release workflow on a fork (no secrets configured → exercises the no-credentials path end-to-end on real runners): all three build jobs green, Windows included — https://github.com/lmanchu/openworker/actions/runs/31314011128
The Windows job log shows the degradation behaving as documented:
Also:
release.ymlYAML validated; repo CI (pytest / gui-unit / gui-e2e) green on the branch. The signed path needs a run by whoever holds real credentials — happy to iterate if anything surfaces there.Not closing #36/#37 with this PR: those should stay open until a credential is procured and a signed release actually ships.
🤖 Generated with Claude Code