Sign Windows release binaries via SignPath#70
Draft
jamescrosswell wants to merge 2 commits into
Draft
Conversation
Mirrors the macOS signing pattern: a secret-presence env gate (HAVE_WINDOWS_SIGNING) so the step auto-enables once a cert is configured and no-ops otherwise. Signs TuiCode.exe between Publish and Archive on the win-* matrix legs so the zipped binary is the signed one. Uses a local .pfx (base64 GitHub secret) + signtool. signtool ships with the Windows SDK but isn't on PATH, so the step locates it under Windows Kits; its own arch is irrelevant, so the same lookup covers the windows-11-arm leg without a cross-sign. Always RFC3161-timestamps so signatures survive cert expiry, then verifies with `verify /pa`. Cert provisioning + the WINDOWS_PFX_BASE64 / WINDOWS_PFX_PASSWORD secrets are a manual follow-up; until they exist the step no-ops, exactly like macOS signing does today. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the local-.pfx + signtool approach with SignPath (Foundation plan, free for OSS). Since the June-2023 CA/Browser Forum baseline requirements, publicly-trusted OV/EV code-signing keys must live on FIPS-140 hardware, so a freely-exportable .pfx for CI is no longer a realistic route. SignPath signs in the cloud — no key material on the runner — and is the closest OSS equivalent to "free, properly trusted". Flow on the win-* legs: upload the unsigned TuiCode.exe as an `unsigned-<rid>` artifact, submit a SignPath signing request that pulls it, and drop the returned signed binary back into publish/ before Archive. The release job's download now filters `pattern: tuicode-*` so the unsigned signing inputs never ship in the release. Gating moves to SIGNPATH_API_TOKEN (secret); the non-secret identifiers (org id + slugs) are repo variables. Step no-ops until the token exists, same as macOS signing. Documented in AGENTS.md § Release workflow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 4, 2026
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.
Adds Authenticode signing for the Windows release binaries via SignPath (Foundation plan — free for OSS), mirroring the macOS signing gating pattern. Split out of #43 (Windows distribution ships unsigned in the interim).
What this does
HAVE_WINDOWS_SIGNINGenv gate — derived fromsecrets.SIGNPATH_API_TOKENpresence, same shape asHAVE_SIGNING_CERT/HAVE_NOTARY. Auto-enables once the token exists, no-ops otherwise.win-*matrix legs, after Publish / before Archive:Upload unsigned Windows binary— uploadspublish/TuiCode.exeas anunsigned-<rid>GitHub artifact (1-day retention).Sign Windows binary via SignPath—signpath/github-action-submit-signing-request@v1submits a signing request that pulls that artifact, signs it in SignPath's cloud, and drops the signed binary back intopublish/so Archive zips the signed one. No key material touches the runner.download-artifactwithpattern: tuicode-*, so theunsigned-*signing inputs never get swept into the published release.Configuration surface
SIGNPATH_API_TOKENSIGNPATH_ORGANIZATION_IDSIGNPATH_PROJECT_SLUGSIGNPATH_SIGNING_POLICY_SLUGrelease-signing.SIGNPATH_ARTIFACT_CONFIGURATION_SLUGOnly the token is secret; the identifiers are non-sensitive repo variables.
Next steps to go live with SignPath
1. Apply to the SignPath Foundation (free OSS) program
2. Set up the SignPath organization (in the SignPath web portal)
SIGNPATH_ORGANIZATION_ID.mentaldesk/TuiCode. SignPath origin-verifies every signing request against the repo/workflow via this App — without it the action can't fetch the artifact or prove provenance.SIGNPATH_PROJECT_SLUG.TuiCode.exe) and Authenticode-signs that PE →SIGNPATH_ARTIFACT_CONFIGURATION_SLUG.release-signing) bound to the Foundation certificate →SIGNPATH_SIGNING_POLICY_SLUG. Decide approval mode (see caveats).SIGNPATH_API_TOKEN.3. Wire the GitHub repo
SIGNPATH_API_TOKEN.SIGNPATH_ORGANIZATION_ID,SIGNPATH_PROJECT_SLUG,SIGNPATH_SIGNING_POLICY_SLUG,SIGNPATH_ARTIFACT_CONFIGURATION_SLUG.4. Trigger and verify
v*tag (or Actions → Release → Run workflow on an existing tag).wait-for-completion(timeout 1800s).Sign Windows binary via SignPathsucceeded and the archivedwin-*zip contains a signedTuiCode.exe.Caveats to decide on
Acceptance criteria
release.ymlsigns bothwin-x64andwin-arm64TuiCode.exebefore archiving, gated on secret presence.unsigned-*signing inputs excluded from the published release.SIGNPATH_API_TOKENsecret + 4SIGNPATH_*variables set; GitHub App installed.win-*binary (verified in logs).🤖 Generated with Claude Code