Skip to content

feat(switchdash): build unsigned Windows releases (CHOO-1468) - #204

Merged
amaudruz merged 2 commits into
mainfrom
feature-request/switchdash-windows-support
Aug 12, 2026
Merged

feat(switchdash): build unsigned Windows releases (CHOO-1468)#204
amaudruz merged 2 commits into
mainfrom
feature-request/switchdash-windows-support

Conversation

@amaudruz

@amaudruz amaudruz commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Jira: CHOO-1468

First slice of the Windows umbrella: produce a Windows build that people can actually install. Signing is explicitly out of scope — the agreed tradeoff is that users click through a SmartScreen warning.

Why there was no Windows build

Not a missing runner. The config demanded signing and there was nothing to sign with.

electron-builder.config.ts set azureSignOptions unconditionally — publisher General Action, Inc., account switchdash, profile switchdash-public, all inherited from the upstream fork and none of them ours. electron-builder picks its signing backend from that key's presence, never checking whether credentials exist, so every --win build committed to Azure Trusted Signing and died in PowerShell.

macOS already solves the same problem (hasDeveloperIdCert gates notarization, ad-hoc signs otherwise). Windows never got an equivalent.

The non-obvious part

Dropping the signing isn't sufficient on its own. publisherName also gets stamped into app-update.yml, and NsisUpdater.verifySignature checks a downloaded installer's Authenticode signature against it. An unsigned build that still named a publisher would reject every update it downloaded.

Removing the key fixes both: computedPublisherName resolves to null, so the manifest carries no publisher and the updater skips verification.

Verified against app-builder-lib@26.15.2 rather than assumed — WindowsSignToolManager.initialize() is a no-op, cscInfo resolves to null without a cert, and signFile logs no signing info identified, signing is skipped and returns.

Why remove rather than gate on an env var

An AZURE_CLIENT_ID gate would have kept a config that cannot work (wrong publisher, wrong account) and made build success depend on ambient environment — that variable appearing on a runner for any unrelated reason would flip the build to the Azure path and hard-fail it. Restoring signing means supplying a real identity, which means editing these lines regardless.

Changes

  • Remove azureSignOptions from electron-builder.config.ts and electron-builder.canary.config.ts, with a comment on why it must not return unaccompanied.
  • Add a build-windows job on windows-latest to switchdash-release.yml, mirroring the macOS job. Publishes .exe, .msi, .blockmap, latest.yml. shell: bash at job level (runner defaults to pwsh).
  • INSTALL.md: Windows install steps, the SmartScreen click-through, AV quarantine, and that AppLocker/WDAC block unsigned binaries outright with no click-through. Notes Docker-backed features stay macOS/Linux only.
  • Release notes cover both platforms.

Testing

The Windows job has not run yet. It can't be exercised locally — no Wine, and the msi target needs it off-Windows. Native module rebuild (better-sqlite3, node-pty compiling against MSVC) is the likeliest failure point. Suggest a workflow_dispatch run before tagging.

Out of scope

Docker CLI resolution on Windows (per product decision — managed local/remote servers aren't needed on Windows yet), orphaned child processes on session teardown, SSH key auth, secrets file permissions. Each is a separate slice under the umbrella.

Noticed, not fixed

  • INSTALL.md says macOS builds are unsigned and need a Gatekeeper bypass; the workflow's release notes say signed and notarized. Contradiction predates this branch.
  • The workflow header cites VITE_SWITCHDASH_AUTOUPDATE=off as disabling auto-update. That variable exists nowhere in the repo; auto-update is live.

🤖 Generated with Claude Code

@semgrep-code-sandbox-quantum

Copy link
Copy Markdown

Semgrep found 4 github-actions-mutable-action-tag findings:

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.

Windows was configured for Azure Trusted Signing but no Authenticode
identity exists, and electron-builder selects its signing backend from the
presence of `azureSignOptions` rather than from whether credentials are
available. Any `--win` build therefore committed to the Azure path and
failed in PowerShell, so no Windows artifact could be produced at all.

Drop the key so the signtool backend is selected instead: it finds no
certificate and skips signing. That also keeps `publisherName` out of
app-update.yml, which matters because electron-updater verifies an
installer's Authenticode signature whenever the manifest names a publisher
— an unsigned build that named one would reject every update it downloaded.

Add a windows-latest job alongside the other platform builds, publishing
the .exe/.msi with latest.yml and the blockmaps. It carries no secrets, so
unlike the macOS job it stays dispatchable from a branch. Add it to
publish-release's gate and require latest.yml among the channel manifests,
so a tagged Release cannot go public without the Windows update feed.

Windows installs now warn via SmartScreen and are blocked outright by
AppLocker/WDAC on managed machines; both are documented in INSTALL.md,
along with Docker-backed features remaining macOS/Linux only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@amaudruz
amaudruz force-pushed the feature-request/switchdash-windows-support branch from 01861a0 to 195bba0 Compare August 11, 2026 18:36
…ts (CHOO-1468)

publish-release refuses to publish a tagged Release without latest.yml, so a
dispatch run should be able to show whether the Windows build produced one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@amaudruz
amaudruz merged commit b996490 into main Aug 12, 2026
14 checks passed
amaudruz added a commit that referenced this pull request Aug 12, 2026
- Linux arm64 desktop artifacts, built + published alongside x64 (#202)
- Windows x64 releases, built + published unsigned (CHOO-1468, #204)
- Codex session runtime version derives from the artifact registry; drop the
  SWITCH_AGENT_RUNTIME_VERSION constant + parity test (#198)

Version mirrored in artifacts.yaml; derived modules regenerated;
artifacts-check passes. No contract revisions changed.

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