Skip to content

fix(win): recover signing queue after transient errors#9657

Open
davidebaraldo wants to merge 4 commits intoelectron-userland:masterfrom
davidebaraldo:fix/signing-queue-error-recovery
Open

fix(win): recover signing queue after transient errors#9657
davidebaraldo wants to merge 4 commits intoelectron-userland:masterfrom
davidebaraldo:fix/signing-queue-error-recovery

Conversation

@davidebaraldo
Copy link
Copy Markdown

@davidebaraldo davidebaraldo commented Mar 24, 2026

Summary

Fixes #9656.

When multiple files are signed in sequence, WinPackager.signIf() chains them through this.signingQueue using .then(). If any _sign(file) rejects, the queue enters a permanently rejected state and every subsequent .then() is skipped — so files queued after the failing one are silently never signed. With forceCodeSigning: false the build then completes shipping unsigned binaries instead of signing the rest.

Fix

Decouple the queue's internal state from the per-file result:

const promise = this.signingQueue.then(() => this._sign(file))
this.signingQueue = promise.catch(() => false)
return promise
  • this.signingQueue is reset to a resolved promise after each operation (success or failure), so the next _sign always runs.
  • The original promise is returned to the caller, so rejections still propagate — forceCodeSigning: true still throws, and the failing file's caller still sees its error.

Test plan

  • Manual verification: transient rejection on one file no longer blocks signing of subsequent files
  • Manual verification: forceCodeSigning: true still throws on signing failure
  • Manual verification: normal signing flow (no errors) is unaffected
  • Unit/integration test — open question, see PR comment

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 24, 2026

🦋 Changeset detected

Latest commit: c8a4894

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
app-builder-lib Patch
dmg-builder Patch
electron-builder-squirrel-windows Patch
electron-builder Patch
electron-forge-maker-appimage Patch
electron-forge-maker-nsis-web Patch
electron-forge-maker-nsis Patch
electron-forge-maker-snap Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Add a rejection handler to the signingQueue promise chain so that a
failure signing one file does not prevent subsequent files from being
attempted. Each caller still receives the rejection for its own file.

Closes electron-userland#9656
@davidebaraldo davidebaraldo force-pushed the fix/signing-queue-error-recovery branch from a8165ce to b9c2992 Compare March 24, 2026 23:58
@mmaietta
Copy link
Copy Markdown
Collaborator

Has this been tested per your PR description? I noticed the suggested code in the Description doesn't match the actual code change. Can you please clarify which approach is intended?

Copy link
Copy Markdown
Collaborator

@mmaietta mmaietta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking Request Changes until previous question is addressed

@davidebaraldo
Copy link
Copy Markdown
Author

Hi @mmaietta — apologies for the confusion. The snippet in the description was from an earlier draft I revised before pushing; the committed code is the intended fix:

const promise = this.signingQueue.then(() => this._sign(file))
this.signingQueue = promise.catch(() => false)
return promise

I went with this shape rather than the (onFulfilled, onRejected) variant for two reasons:

  1. Caller still observes the real outcome. promise is returned untouched, so await this.signIf(file) in signAndEditResources / signApp still throws on a real signing error and forceCodeSigning: true still aborts the build.
  2. Only the internal queue is healed. Resetting this.signingQueue to promise.catch(() => false) means the next _sign starts from a resolved state, so a transient failure on one file no longer poisons the chain for every file queued after it. The onRejected form would have re-invoked _sign on the current file when the previous one failed, which conflates two unrelated files.

I've updated the PR description to match the committed code.

On testing: I haven't been able to commit a unit test yet. The queue lives inside WinPackager and signIf depends on signingManager.value / signWindows, so a meaningful test needs non-trivial mocking of the signing infrastructure — and a standalone test that just replicates the queue logic would drift from the real code. I verified the behavior manually against the original failure mode from #9656 (transient rejection on file A no longer skips files B, C, …; forceCodeSigning: true still throws).

Happy to invest in a proper integration test (e.g. mocking signWindows via jest module mock) if you'd like that gating the merge — just confirm the approach you'd prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Signing queue in WinPackager breaks after rejection — subsequent files are skipped

2 participants