Skip to content

feat(squirrel-windows): inline installer logic; remove electron-winstaller dependency and its vendored binaries#9830

Draft
mmaietta wants to merge 23 commits into
masterfrom
feat/migrate-electron-winstaller
Draft

feat(squirrel-windows): inline installer logic; remove electron-winstaller dependency and its vendored binaries#9830
mmaietta wants to merge 23 commits into
masterfrom
feat/migrate-electron-winstaller

Conversation

@mmaietta

@mmaietta mmaietta commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Closes #9077. This migration is driven by the need to workaround upstream CVE related to electron-winstaller's vendor directory. electron-builder uses an updated winCodeSign bundle from electron-builder-binaries that pulls directly from latest Windows Kits SDK.

Summary

  • Removes electron-winstaller as a runtime dependency of electron-builder-squirrel-windows and as a dev dependency of the test package, eliminating the vendored binaries (Squirrel.exe, nuget.exe, SyncReleases.exe, Squirrel-Mono.exe) that were flagged by dependency scanners.
  • Inlines the installer creation logic into a new windowsInstaller.ts module, replacing the call to createWindowsInstaller from electron-winstaller. Logic is sourced from electron/windows-installer@main src/index.ts and trimmed to what electron-builder actually uses (usePackageJson: false, signing handled externally via packager.signIf).
  • Simplifies vendor setup: prepareSignedVendorDirectory now only downloads from our maintained squirrel.windows@1.0.0 bundle, removing the parallel copy from the electron-winstaller npm package's own vendor/ directory.
  • Fixes os.archos.arch() bug in select7zipArch — the bare property reference returned a function object instead of the arch string, silently breaking the 7z-<arch>.exe filename construction on non-Windows cross-compile hosts.
  • Replaces lodash template engine with a zero-dependency split/join substitution. The template.nuspectemplate <% additionalFiles.forEach(...) %> loop is replaced by an <%- additionalFilesXml %> placeholder; the XML fragment is pre-built in buildAdditionalFilesXml, preserving swiftshader/vk_swiftshader_icd.json support.
  • Fixes remoteToken config forwarding — user-configured squirrelWindows.remoteToken is now included in the options object; previously it was silently dropped in favor of env vars only.
  • Updates packTester.ts to import convertVersion from our module instead of electron-winstaller.

Changed Files

File Change
packages/electron-builder-squirrel-windows/src/windowsInstaller.ts New — exports convertVersion, escapeXml, renderNuspecTemplate, buildAdditionalFilesXml, createWindowsInstaller, InstallerOptions
packages/electron-builder-squirrel-windows/src/SquirrelWindowsTarget.ts Import from ./windowsInstaller; simplified prepareSignedVendorDirectory; simplified computeEffectiveDistOptions; fix os.arch()
packages/electron-builder-squirrel-windows/template.nuspectemplate Replace forEach block with <%- additionalFilesXml %>
packages/electron-builder-squirrel-windows/package.json Remove electron-winstaller, @types/archiver, @types/fs-extra
test/package.json Remove electron-winstaller dev dependency
test/src/helpers/packTester.ts Import convertVersion from electron-builder-squirrel-windows/out/windowsInstaller
test/src/windows/squirrelWindowsInstallerTest.ts New — 31 unit tests for all exported helpers
.changeset/remove-electron-winstaller-dep.md Changeset: electron-builder-squirrel-windows minor bump

Design Notes

No new runtime dependencies. Lodash's template() engine (an electron-winstaller transitive dep) is replaced by split/join key substitution. The nuspec template is now owned entirely by this package, with the one dynamic section (additionalFiles) handled by pre-building the XML in buildAdditionalFilesXml.

Mono/Wine execution unchanged. On Windows, nuget.exe, SyncReleases.exe, and Squirrel.exe are called directly. On Linux/macOS, nuget.exe and SyncReleases.exe run under mono, and Squirrel-Mono.exe replaces Squirrel.exe — identical to the behavior of the removed electron-winstaller.

XML injection protection. All user-supplied metadata fields (name, title, version, authors, description, copyright, iconUrl, exe) pass through escapeXml before template substitution. The additionalFilesXml fragment is constructed from hardcoded strings and is inserted verbatim.

@changeset-bot

changeset-bot Bot commented Jun 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 921b53f

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

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

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates electron-builder-squirrel-windows off electron-winstaller by inlining the Windows Squirrel installer creation logic and removing the upstream dependency (and its vendored binaries) to address CVE/dependency-scanner findings, while keeping the existing packaging/signing flow within electron-builder.

Changes:

  • Added a new windowsInstaller.ts module that implements the required installer/nuspec generation helpers and createWindowsInstaller.
  • Updated SquirrelWindowsTarget to use the new module, simplify vendor preparation, and adjust option computation/forwarding.
  • Updated the nuspec template and added Vitest unit coverage for the new helper functions; removed the electron-winstaller dependency from relevant package manifests and lockfile.

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/electron-builder-squirrel-windows/src/windowsInstaller.ts New inlined Squirrel.Windows installer implementation and helper utilities.
packages/electron-builder-squirrel-windows/src/SquirrelWindowsTarget.ts Switch to the inlined installer module; simplify vendor setup and option computation.
packages/electron-builder-squirrel-windows/template.nuspectemplate Replace loop-based template section with a prebuilt additionalFilesXml placeholder.
packages/electron-builder-squirrel-windows/package.json Remove electron-winstaller and related type dependencies.
test/src/windows/squirrelWindowsInstallerTest.ts New unit tests covering the new helper utilities.
test/src/helpers/packTester.ts Import convertVersion from the new module instead of electron-winstaller.
test/package.json Remove electron-winstaller dev dependency.
pnpm-lock.yaml Lockfile cleanup reflecting removed dependencies.
.changeset/remove-electron-winstaller-dep.md Changeset for the electron-builder-squirrel-windows minor bump.
.gitignore Add ignore entry for Vitest smart cache file (now redundant with existing pattern).
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/electron-builder-squirrel-windows/src/windowsInstaller.ts Outdated
Comment thread packages/electron-builder-squirrel-windows/src/windowsInstaller.ts
Comment thread packages/electron-builder-squirrel-windows/src/SquirrelWindowsTarget.ts Outdated
@mmaietta mmaietta linked an issue Jun 10, 2026 that may be closed by this pull request
mmaietta and others added 4 commits June 20, 2026 15:00
Resolves conflicts by adopting the post-merge ESM conventions (import.meta,
/internal barrel subpaths, dist/ output, packager getters without .info.)
while keeping the inlined Squirrel installer (no electron-winstaller dep):

- SquirrelWindowsTarget.ts: rewritten against new API surface; vendor from
  getSquirrelToolsetPath() bundle + runtime nuget/rcedit provisioning
- toolset.ts: ESM imports; inlined env-dir validation (resolveEnvToolsetPath
  was removed upstream); added prepareNugetExe() runtime download
- indexInternal.ts (app-builder-lib): export getRceditBundle
- test.yaml: dropped temporary squirrel toolset CI scaffolding (replaced by
  runtime nuget download)
- tests: import package src/ subpaths instead of out/
- pnpm-lock.yaml: reconciled (electron-winstaller removed)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t + default spinner

- BREAKING: remove squirrelWindows.customSquirrelVendorDir. The vendor toolset
  source is overridden via ELECTRON_BUILDER_SQUIRREL_TOOLSET_DIR (same nuget/rcedit
  provisioning). prepareSignedVendorDirectory collapses to one code path.
- nuget download is offline/mirror-friendly: skips when a real (multi-MB) nuget.exe
  is already present (future bundle / pre-staged toolset), and is redirectable via
  ELECTRON_BUILDER_SQUIRREL_NUGET_URL (+ _SHA256). Adds a network-free skip test.
- bundle install-spinner.gif and use it as the loadingGif fallback, restoring
  electron-winstaller parity (default fresh-install spinner).
- regenerate scheme.json; changeset bumped to major with the breaking note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oval

Add the v27 breaking-change entry for the removed customSquirrelVendorDir option
(at-a-glance row + detail section) and a manual-step bullet in the v26→v27 guide,
explaining the ELECTRON_BUILDER_SQUIRREL_TOOLSET_DIR replacement, its different
directory layout, and the offline nuget options.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nload

Mark prepareNugetExe/isUsableNuget/NUGET_* for removal once squirrel.windows@1.1.1
(electron-builder-binaries#203) bundles the pinned nuget.exe; the skip-if-real-nuget
logic already makes the runtime download a no-op against such a bundle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mmaietta and others added 9 commits June 20, 2026 16:35
…uirrel config

Replace the bespoke ELECTRON_BUILDER_SQUIRREL_TOOLSET_DIR / ELECTRON_BUILDER_SQUIRREL_NUGET_*
env vars with the standard ToolsetConfig pattern:

- add a `squirrel` field to ToolsetConfig ("1.1.0" | ToolsetCustom | "latest"), resolved
  exactly like the other toolsets (version -> downloadBuilderToolset, object -> getCustomToolsetPath)
- export getCustomToolsetPath + resolveToolsetVersion from app-builder-lib/internal
- getSquirrelToolsetPath(toolset, resourcesDir) reads packager.config.toolsets.squirrel
- offline/custom bundles now use toolsets.squirrel (a ToolsetCustom whose vendor/ may ship a
  real nuget.exe, which the skip-if-real check keeps); drop the nuget URL/SHA env overrides
- rewrite the toolset test (custom-dir resolution + invalid-url) ; keep the nuget skip test
- regenerate scheme.json; update v26->v27 + v27-breaking-changes docs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…equested MSI

- InstallerOptions uses `msi` (positive form) instead of `noMsi`; createWindowsInstaller
  passes --no-msi when !msi. Removes the redundant runtime noMsi deprecation shim
  (migrate-schema already rewrites the deprecated squirrelWindows.noMsi config to msi).
- fixUpPaths: the Setup.msi rename only runs when MSI output was requested, so a missing
  Setup.msi is a real failure — throw an explicit error instead of swallowing it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…squirrel

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t win32

Squirrel-Mono.exe also shells out to rcedit.exe during --releasify (setPEVersionInfoAndIcon)
to stamp version info + the app icon into Setup.exe, so the win32-only gate left rcedit.exe
missing from the vendor dir on Linux/macOS, failing the build under mono/wine with
"Failed to modify resources / ShellExecuteEx failed". electron-winstaller's vendor shipped a
32-bit rcedit.exe on all platforms; match that — use the 32-bit rcedit under wine (alongside
the Win32 Squirrel vendor exes wine already runs), host-arch rcedit on Windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uilds

Squirrel's createMsiPackage (msi: true) runs candle.exe/light.exe from its vendor dir and reads
template.wxs there; the squirrel.windows bundle ships neither, so MSI builds failed at
pathToWixTools(). When msi is requested, download the shared WiX 3.11 toolset (wix-4.0.0.5512.2 —
the same candle/light electron-builder's MSI target uses) and merge it into the vendor dir, and ship
Squirrel's template.wxs in the package and copy it alongside. Gated on msi so non-MSI builds skip the
~4MB download.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on missing Squirrel.exe

- Select rcedit by host arch (x64 for x64/arm64, x86 only for ia32) instead of forcing 32-bit on
  non-Windows: the 32-bit build fails on arm64 macOS even under Rosetta (which translates x64, not x86).
- Throw when Squirrel.exe is absent from the vendor dir instead of warn-and-skip: it always ships in
  the bundle, and skipping signing both produces a broken installer and bypasses the forceCodeSigning
  enforcement in signIf.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…4 namespace

The shared wix-4.0.0.5512.2 toolset (the one electron-builder's MSI target uses) is a transitional
WiX 4: its candle accepts the v3-style element structure but requires the v4 namespace, so Squirrel's
WiX 3 template was rejected with CNDL0199. Swap template.wxs to http://wixtoolset.org/schemas/v4/wxs
(dropping the unused util/netfx namespace decls — only the core <PropertyRef Id="NETFRAMEWORK45"> is
used, supplied by candle's -ext WixNetFxExtension). Structure is unchanged, matching MsiTarget's
template which compiles with the same toolset.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Open CVEs with electron-winstaller addition to electron-builder "npm install electron-builder" fails on Armbian Linux (arm7l)

2 participants