Skip to content

feat(release): sign Windows installer via Azure Trusted Signing#694

Open
huntharo wants to merge 1 commit into
mainfrom
claude/windows-code-signing
Open

feat(release): sign Windows installer via Azure Trusted Signing#694
huntharo wants to merge 1 commit into
mainfrom
claude/windows-code-signing

Conversation

@huntharo

@huntharo huntharo commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Recreates #674, which GitHub auto-closed when main's history was rewritten. Same change, rebased onto current main.

What & why

Adds optional Authenticode signing for the Windows NSIS installer using
Azure Trusted Signing (electron-builder 26's native cloud-signing support) —
no hardware token, GitHub-hosted-runner friendly, removes the SmartScreen
"unknown publisher" warning. Follow-up to the Windows port (#670), which shipped
the installer unsigned.

Signed-when-configured, unsigned-otherwise — degrades gracefully so local,
sandbox, and label-gated PR builds keep working with no secrets.

Changes

  • release.mjs: resolveWindowsAzureSigning() reads WIN_AZURE_SIGN_* (config)
    • AZURE_TENANT_ID/CLIENT_ID/CLIENT_SECRET (service-principal creds, read by
      electron-builder's bundled TrustedSigning module). When all present, injects
      --config.win.azureSignOptions.{publisherName,endpoint,codeSigningAccountName,certificateProfileName}
      into the --win electron-builder invocation; otherwise builds unsigned
      with a clear warning.
  • release.mjs: runChecked uses a shell only for pnpm on Windows (the .cmd
    shim), not node — so the publisherName=PwrDrvr LLC override (which has a
    space) isn't word-split by shell:true.
  • release.yml (windows-package, release tags only): passes the signing config
    from repo variables and creds from repo secrets; empty → unsigned.
  • docs/desktop-windows-signing.md: setup runbook.

Activation

No behavior change until configured. Once these are set, the next release tag
produces a signed installer:

  • Variables: WIN_AZURE_SIGN_PUBLISHER_NAME, WIN_AZURE_SIGN_ENDPOINT, WIN_AZURE_SIGN_ACCOUNT, WIN_AZURE_SIGN_PROFILE
  • Secrets: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET

Notes

  • Eligibility (your action): Azure Trusted Signing needs a paid Azure sub and
    a US/Canada org 3+ yrs (or US/Canada individual, or EU/UK org) — see runbook.
  • Label-gated PR installer builds (ci:windows-package) stay unsigned by
    design (secrets aren't exposed to PR validation).
  • Publishing the signed installer to the GitHub Release (today a workflow
    artifact) is a separate follow-up.

🤖 Generated with Claude Code

Wire optional Authenticode signing for the Windows NSIS installer using Azure
Trusted Signing (electron-builder 26 native support). Signed when configured,
unsigned otherwise — so local/sandbox/label-gated builds keep working with no
secrets.

- release.mjs: resolveWindowsAzureSigning() reads WIN_AZURE_SIGN_* + AZURE_*
  env and, when complete, injects --config.win.azureSignOptions.* into the
  electron-builder --win invocation; otherwise builds UNSIGNED with a warning.
- release.mjs: runChecked now uses a shell only for `pnpm` on Windows (the .cmd
  shim), not `node` — so args with spaces (the publisherName override) pass
  through intact.
- release.yml: windows-package job passes the signing config (repo vars) +
  service-principal creds (secrets); empty -> unsigned.
- docs/desktop-windows-signing.md: Azure Trusted Signing setup runbook
  (eligibility, account/profile, service principal + Signer role, repo
  vars/secrets, verification).

PR-label installer builds intentionally stay unsigned (secrets not exposed to
PR validation). Publishing the signed installer to the GitHub Release is a
follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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