feat(updater): robust PowerShell invocation for Windows code-signature verification - #9764
feat(updater): robust PowerShell invocation for Windows code-signature verification#9764mmaietta wants to merge 13 commits into
Conversation
…Encoding = [Console]::OutputEncoding = [Text.Encoding]::UTF8` for windows signing verification via powershell
🦋 Changeset detectedLatest commit: 2e4e003 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
There was a problem hiding this comment.
Pull request overview
This PR updates how electron-updater invokes PowerShell to verify Windows Authenticode signatures, aiming to improve reliability on newer Windows Server versions and to ensure UTF-8 output handling without going through cmd.exe.
Changes:
- Refactor PowerShell invocation to use
shell: false+-EncodedCommand, and configure UTF-8 output inside PowerShell. - Adjust module-loading /
PSModulePathhandling intended to avoid autoload issues on newer Windows Server versions. - Add unit + Windows-only e2e tests (with a snapshot) covering invocation parameters, escaping, and key verification behaviors.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
packages/electron-updater/src/windowsExecutableCodeSignatureVerifier.ts |
Refactors preparePowerShellExec to use -EncodedCommand, sets shell: false, and moves encoding/module setup into the PowerShell script. |
test/src/updater/windowsExecutableCodeSignatureVerifierTest.ts |
Adds comprehensive unit tests (mocked) and Windows-only e2e tests (real PowerShell) for signature verification and command construction/escaping. |
test/snapshots/updater/windowsExecutableCodeSignatureVerifierTest.js.snap |
Adds snapshot for the PowerShell executable + args (including encoded command). |
.changeset/late-results-grab.md |
Declares a minor changeset for electron-updater reflecting the PowerShell invocation change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… not changing the snapshot (e.g. encodedcommand) every run
shell: false and -EncodedCommand for windows signing verification via powershell|
Is this going to get merged? I have users reporting errors upgrading and I'm hoping this fixes it. |
|
I do plan to revisit this PR, but I had to pause work due to personal events. Hoping to reapply focus here soon. There was additional testing I was looking to do. |
Resolves conflict in windowsExecutableCodeSignatureVerifier.ts: master's inline verifySignature body (removed by this PR's helper extraction) conflicted with the restructured version. Kept the PR's helper-based structure and ported master's new fail-open deprecation warning (#9979) into checkLiteralPath's catch block. The other two deprecation warnings in handleError and the ESM types.js import auto-merged cleanly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cb9bMJZft1o1hHc9P6jp2W
…slint curly rule) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cb9bMJZft1o1hHc9P6jp2W
Fixes #9688 —
Get-AuthenticodeSignaturefailures on Windows 10 / Electron 40 / Node 24 configurations.Summary
Core fix —
shell: false+-EncodedCommand: PowerShell is now invoked directly viaexecFileinstead of being chained throughcmd.exe. The command is passed as a Base64-encoded UTF-16LE string via-EncodedCommand, removing the cmd.exe invocation and thechcp 65001 >NUL &pipeline entirely.UTF-8 output encoding: Moved from the
chcp 65001shell command to$OutputEncoding = [Console]::OutputEncoding = [Text.Encoding]::UTF8configured inside the PowerShell script. Both variables must be set together forConvertTo-Jsonto emit UTF-8 when stdout is captured by Node (fixes Certificates with special characters are not accepted anymore since electron-updater v1.6.9 #8162 class of errors — non-ASCII characters in the update path).Module loading hardened:
Import-Moduleuses"$PSHOME\Modules\Microsoft.PowerShell.Security"(PowerShell's own trusted install directory) before$env:PSModulePathis cleared, so the correct module is loaded even on Windows Server 2025 where auto-loading requires PSModulePath at import time. PSModulePath is also deleted from the Node-sideenvoption as belt-and-suspenders.Progress-stream suppression:
$ProgressPreference = 'SilentlyContinue'is set first in the script so the "Preparing modules for first use." CLIXML record is never written to stderr, eliminating false-positive error detection on first-run environments.Bug fix — double-reject in
handleError: The previousif (error) { reject() } if (stderr) { reject() }pattern could settle the Promise twice when both fields were set. Corrected toelse if.Typo fix:
normlaizedUpdateFilePath→normalizedUpdateFilePath.Reduced cyclomatic complexity: Extracted three private helpers to flatten
verifySignature(CC 6 → 3):checkLiteralPath— validatesdata.Pathagainst the expected update path and callsreject()directly on mismatch (removes the spurious ConvertTo-Json probe on path-mismatch failures).matchPublisher— DN matching loop.evaluateSignatureResult— parses the PS JSON output and coordinates the LiteralPath + publisher checks.Path injection comment trimmed: Multi-line example block replaced with a 2-line explanation (WHY only — PowerShell single-quoted strings make
$,`, and\literal; only'needs escaping).Test —
vi.importActualmoved tobeforeAll: In the e2e describe block, the expensivevi.importActualcalls for realchild_processandosimplementations are obtained once inbeforeAllrather than re-fetched before every test inbeforeEach.Test coverage (unit, platform-agnostic): 46 tests pass, up from 41. New cases cover:
"") rejects via the catch path (JSON.parse throws).$in path is passed verbatim inside the single-quoted PS string.Test coverage (e2e, Windows-only
describe.ifWindows): 4 new real-PowerShell tests validate that directory names containing&,%VAR%,$, and backtick characters — which were dangerous under the oldcmd.exe-based invocation — now complete without crash or spurious rejection.Changed Files
packages/electron-updater/src/windowsExecutableCodeSignatureVerifier.tsshell: false,-EncodedCommand, helper extraction, bug fixes, comment cleanuptest/src/updater/windowsExecutableCodeSignatureVerifierTest.tsvi.importActualmoved tobeforeAlltest/snapshots/updater/windowsExecutableCodeSignatureVerifierTest.js.snap