From c11bb87fe1b8b0edebaa3f542af25f7b097865dd Mon Sep 17 00:00:00 2001 From: Rhys Sullivan <39114868+RhysSullivan@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:30:58 -0700 Subject: [PATCH] desktop: keep the mac signing cert off the windows build CSC_LINK is electron-builder cross-platform, not mac-only: WinPackager falls back to it when WIN_CSC_LINK is unset. Setting it unconditionally handed the Apple Developer ID cert to the windows leg, which wrote its subject CN into app-update.yml as publisherName. Every Windows client then rejected the update it downloaded because the installer carries no signature Windows trusts. Scope CSC_LINK/CSC_KEY_PASSWORD to the mac legs, and set win.verifyUpdateCodeSignature so the updater manifest stops claiming a publisher the build cannot back up. --- .github/workflows/publish-desktop.yml | 18 ++++++++++++++++-- apps/desktop/electron-builder.config.ts | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-desktop.yml b/.github/workflows/publish-desktop.yml index 54f22c7ce7..87705c9a1c 100644 --- a/.github/workflows/publish-desktop.yml +++ b/.github/workflows/publish-desktop.yml @@ -155,8 +155,22 @@ jobs: # → notarytool authentication for the notarization upload # When the secrets aren't set (forks, local), electron-builder # silently produces an unsigned build. - CSC_LINK: ${{ secrets.CSC_LINK }} - CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + # + # CSC_LINK / CSC_KEY_PASSWORD MUST stay scoped to the mac legs. + # Despite the name used here, CSC_LINK is electron-builder's + # cross-platform certificate variable: WinPackager falls back to it + # whenever WIN_CSC_LINK is unset, via + # platformPackager.getCscLink("WIN_CSC_LINK"). Handing the Apple + # Developer ID .p12 to the windows leg made electron-builder read its + # subject and write `publisherName: Developer ID Application: ...` + # into app-update.yml, so every Windows client rejected the update it + # had just downloaded with "New version is not signed by the + # application owner". Empty string is the documented "no certificate" + # value — WindowsSignToolManager treats `cscLink === ""` exactly like + # unset. The APPLE_* vars below need no such guard: they are only + # read by notarytool on darwin and are inert elsewhere. + CSC_LINK: ${{ matrix.platform == 'mac' && secrets.CSC_LINK || '' }} + CSC_KEY_PASSWORD: ${{ matrix.platform == 'mac' && secrets.CSC_KEY_PASSWORD || '' }} APPLE_API_KEY: ${{ env.APPLE_API_KEY_PATH }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} diff --git a/apps/desktop/electron-builder.config.ts b/apps/desktop/electron-builder.config.ts index 2766833954..831b92a5a8 100644 --- a/apps/desktop/electron-builder.config.ts +++ b/apps/desktop/electron-builder.config.ts @@ -46,6 +46,27 @@ const config: Configuration = { // artifact only exists once a leg stages an arm64 executor for it. win: { target: ["nsis"], + // There is no Windows code-signing certificate yet, so these installers + // ship unsigned, and this flag records that fact for the updater. + // + // Left at its `true` default, electron-builder writes a `publisherName` + // into app-update.yml derived from the signing certificate's subject CN + // (PublishManager.getAppUpdatePublishConfiguration, gated on + // WinPackager.isForceCodeSigningVerification). electron-updater then + // requires every downloaded installer to carry an Authenticode signature + // matching that name and refuses the update otherwise + // (NsisUpdater.verifySignature). An unsigned build that still claims a + // publisher can therefore never update itself. + // + // With this false no `publisherName` is emitted, `verifySignature` + // returns null early, and unsigned installers update as intended. It does + // not disable signing: `isForceCodeSigningVerification` is only ever read + // when computing the updater manifest. + // + // Delete this line when a real Windows certificate lands (signtoolOptions + // or azureSignOptions); leaving it would keep verification off for a + // signed build. + verifyUpdateCodeSignature: false, }, nsis: { oneClick: true,