ci: sign the Windows release executable with SignPath - #394
Merged
Conversation
SignPath's OSS tier requires every job leading up to a signing request to run on a GitHub-hosted agent, but the Windows release runs entirely on the self-hosted runner. Split the workflow instead of moving the whole build: - New `sign-exe` job on `windows-latest` builds only StemDeck.exe, uploads it as a workflow artifact, submits it to SignPath, and republishes the signed binary as an artifact. Version files are stamped before the build because SignPath restricts Foundation projects on PE product name and version. - `build-and-upload` now depends on it, downloads the signed executable, and packages both variants around it via a new `-PrebuiltExe` flag on make-portable.ps1. That also removes the redundant second Rust build the CPU package used to trigger. - make-portable.ps1 rejects an unsigned prebuilt binary before it reaches the zip, and the scan step reports the Authenticode status of what was packaged. - workflow_dispatch entry point plus a release-only guard on the upload step so the integration can be exercised against a test-signing policy without cutting a tag. Requires repo secret SIGNPATH_API_TOKEN and repo variable SIGNPATH_ORGANIZATION_ID. Adds the code signing policy and attribution required by the SignPath Foundation terms.
thcp
marked this pull request as ready for review
August 19, 2026 09:42
1 task
thcp
added a commit
that referenced
this pull request
Aug 20, 2026
SIGNPATH_API_TOKEN and SIGNPATH_ORGANIZATION_ID aren't configured in the repo yet, so a release-triggered run of the sign-exe job added in #394 fails on main today, not just waits on approval. That blocks cutting any release directly from main until SignPath is finished. This reverts #394 so main goes back to the pre-SignPath, working Windows release path. That's what let v0.11.2 skip the blocker (cut from a branch off the v0.11.1 tag) instead of going through main; with this reverted, main itself is unblocked for normal direct-to-main work and future patch releases. Re-apply when picking SignPath back up: git revert this commit (or cherry-pick 7eba634 again) once the secrets/variable are set and the SignPath project/policy is approved, then cut v0.12.0. ## Test plan - [x] Clean revert, no conflicts beyond the already-open Unraid pin PR (#398), which targets a different file section
meefs
pushed a commit
to meefs/stemdeck
that referenced
this pull request
Aug 20, 2026
…ckapp#394)" This reverts commit 7eba634.
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.
Signs
StemDeck.exein both Windows release zips using SignPath.io with a SignPath Foundation OSS certificate.Why the workflow had to be split
SignPath's OSS tier requires that all jobs leading up to a signing request run on GitHub-hosted agents (docs). The Windows release runs entirely on the self-hosted runner, so it could not submit a request as-is.
Rather than move the whole build (ClamAV needs a Linux Docker image, the zips are near the 2 GiB release-asset cap, torch venvs are heavy), only the executable build moves to
windows-latest:sign-exe(GitHub-hosted): stamp version ->tauri build-> uploadstemdeck.exe-> submit to SignPath -> upload signed exebuild-and-upload(self-hosted,needs: sign-exe): download signed exe -> package both zips around it -> ClamAV -> release uploadOnly
StemDeck.exeis signed. The zips are not Authenticode containers; they stay covered by the published.sha256. Bundledpython.exe/*.dllkeep their python.org signatures.Side effect: the CPU package no longer triggers a second full Rust rebuild, since both variants reuse the one signed binary.
Changes
.github/workflows/windows-release.yml- newsign-exejob;build-and-uploadconsumes its artifact;workflow_dispatchdry-run entry point with arelease-only guard on the upload step; Authenticode status reported in the scan step.scripts/windows/make-portable.ps1- new-PrebuiltExeparameter that skips the npm/Tauri build and packages a supplied executable, throwing if it carries no signature..signpath/policies/stemdeck/release-signing.yml-disallow_reruns: true. Branch rulesets left out until the repo has matching rulesets configured, since SignPath rejects requests that do not satisfy them.README.md,packaging/windows/README-WINDOWS.txt- code signing policy and attribution required by the SignPath Foundation terms.Required before this can run
Portal side (not in this PR):
stemdeck) and link theGitHub.comtrusted build system.upload-artifactzips by default, so the root element iszip-file:test-signingandrelease-signing.Repo side:
SIGNPATH_API_TOKENSIGNPATH_ORGANIZATION_IDVerification
workflow_dispatchon this branch withsigning_policy: test-signing- nothing is published; confirm the signing request appears in the SignPath console and the scan step reports a non-NotSignedstatus.StemDeck.exereportsStatus: Validwith a SignPath Foundation signer.Risk
SignPath's origin check is documented as covering jobs "leading up to" the request.
build-and-uploadis self-hosted but runs strictly after vianeeds:, so it should be out of scope. If SignPath rejects it anyway, the fallback is movingsign-exeinto its own workflow file.