Skip to content

feat(updater): fix manifest sha512 hash-encoding sniffing, add opt-in Linux package-signature verification#9990

Open
mmaietta wants to merge 5 commits into
masterfrom
v27/t1-part1
Open

feat(updater): fix manifest sha512 hash-encoding sniffing, add opt-in Linux package-signature verification#9990
mmaietta wants to merge 5 commits into
masterfrom
v27/t1-part1

Conversation

@mmaietta

@mmaietta mmaietta commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Requested by Mike Maietta · Slack thread

Summary

  • Manifest sha512 hex encoding is now strictly detected and deprecated. The download verifier previously sniffed whether a manifest's sha512 was hex- or base64-encoded with a fuzzy heuristic (sha512.length === 128 && !includes('+') && !includes('Z') && !includes('=')). It now uses a strict check: a value that is exactly 128 hexadecimal characters is treated as legacy hex (with a deprecation debug log — support will be removed in v28); anything else is decoded as base64, which is what electron-builder has emitted since 19.x. The two forms cannot collide (base64-encoded sha512 is always 88 characters ending in ==), and a wrong pick can only fail closed with a checksum mismatch. SHA-256 (sha2) acceptance is unchanged and remains under its existing v28-removal grace period.

  • NEW — AppUpdater.allowUnverifiedLinuxPackages (default true). Because electron-builder does not sign Linux packages, this defaults to true to preserve today's behavior: .deb/.rpm auto-updates install with the package manager's signature/GPG checks bypassed where a bypass flag exists. Set it to false (for pipelines that sign their own packages and whose targets trust the keys) to enforce verification where the package manager supports it.

    • The flag threads through DebUpdater/RpmUpdater into their static installWithCommandRunner methods as a trailing optional parameter (allowUnverified = true), so existing 6.x call sites remain source- and runtime-compatible (no API break).
    • What false enforces depends on the package manager on the target system: dpkg (the default for .deb) — no effect, dpkg performs no signature verification (a warning is logged; .deb enforcement requires a debsig-verify/debsigs policy on the target system); apt (.deb fallback) — --allow-unauthenticated is omitted; zypper — enforced, unsigned/untrusted packages fail to install; dnf/yum — enforced via --setopt=localpkg_gpgcheck=1, since local package files are governed by localpkg_gpgcheck (default off) and merely omitting --nogpgcheck would enforce nothing; bare rpm (no-resolver fallback) — cannot be enforced via the CLI (a warning is logged; the default %_pkgverify_level is digest, admins must configure %_pkgverify_level signature).
    • rpm --nodeps is left in place unconditionally: it is a dependency-resolution bypass, not a signature bypass, and the bare-rpm branch is the no-resolver fallback.
    • Install-time logging is per-branch and states only what is actually true for that package manager: bypass/enforce messages for apt/zypper/dnf/yum, and explicit warnings for dpkg and bare rpm where the setting cannot change behavior.
  • The deprecated UpdateCheckResult.versionInfo alias is retained. (This branch previously removed it; that removal has been reverted, so versionInfo — a @deprecated alias of updateInfo — continues to be populated by checkForUpdates() for backward compatibility.)

Changesets

  • builder-util-runtime: patch (plus an electron-updater patch note so it lands in the changelog updater users read) — strict legacy-hex detection with deprecation, removal planned for v28.
  • electron-updater: minor — allowUnverifiedLinuxPackages.

Design notes

Default is true, not false. Flipping the default to enforce verification would break every existing electron-builder Linux auto-updater, since electron-builder does not sign Linux packages. The safe-by-default posture here is "preserve working updates"; enforcement is strictly opt-in for projects that sign packages out-of-band.

Why the hash-encoding change is not breaking. Within the electron-builder ecosystem, sha512 in latest*.yml is always base64, so no real electron-builder manifest changes behavior. Hex values (pre-19.x manifests or hand-rolled manifests built from raw sha512sum output) keep working in v27 — they are now detected strictly instead of fuzzily, logged as deprecated, and will be removed in v28. Nothing breaks in this release, which is why this is a patch; the versionInfo alias removal (reverted here) was the only genuinely breaking part of the original change.

Tests

  • linuxUpdaterUnitTest asserts the exact install argv (toEqual) for both allowUnverifiedLinuxPackages modes across apt, zypper, dnf, yum, and rpm — including --setopt=localpkg_gpgcheck=1 in dnf/yum enforce mode and rpm --nodeps remaining regardless. It also covers the dpkg branch (direct dpkg -i plus the apt-get install -f -y fallback), the trailing-default 6.x call-site compatibility, the dpkg/bare-rpm warning paths, and doInstall wiring tests proving the instance field is threaded through DebUpdater (apt) and RpmUpdater (zypper).
  • httpExecutorTest covers detectSha512Encoding (128-char hex vs 88-char base64) and DigestTransform end-to-end for both encodings, plus the fail-closed mismatch path.
  • Related updater unit suites (nsisUpdaterTest, macUpdaterTest, macUpdaterLogicTest, linuxUpdaterUnitTest, updateUtilTest) pass with the restored versionInfo alias — the field is additive and no snapshot captures the full check-result object (the helper snapshots only updateInfo).

…ing, add Linux package-verification opt-in

Tier-1 v27 changes. The legacy path/sha512 gating is split into its own follow-up commit; sha2/SHA-256 removal is deferred to v28 per the existing grace period.

- Remove the deprecated UpdateCheckResult.versionInfo alias (use updateInfo). (BREAKING)
- Always treat manifest sha512 as base64 instead of heuristically sniffing hex vs base64, removing a crafted-manifest mis-parse vector. SHA-256 (sha2) acceptance is retained under its existing v28-removal grace period.
- Add AppUpdater.allowUnverifiedLinuxPackages. Because electron-builder does not sign Linux packages, this defaults to true (preserving today's behavior: unsigned .deb/.rpm install). Set it to false to enforce package signature/GPG verification, which gates --allow-unauthenticated (apt), --allow-unsigned-rpm (zypper) and --nogpgcheck (dnf/yum). rpm --nodeps is left in place (dependency, not signature, bypass).

BREAKING CHANGE: UpdateCheckResult.versionInfo removed; use updateInfo.

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

changeset-bot Bot commented Jun 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 474def7

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

This PR includes changesets to release 12 packages
Name Type
electron-updater Minor
builder-util-runtime Patch
app-builder-lib Patch
builder-util Patch
dmg-builder Patch
electron-builder Patch
electron-publish Patch
electron-builder-squirrel-windows 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

@mmaietta mmaietta changed the title feat(updater): remove deprecated versionInfo, fix manifest hash-encoding, add Linux package-verification opt-in (BREAKING, due to versionInfo`) feat(updater): fix manifest sha512 hash-encoding sniffing, add opt-in Linux package-signature verification Jul 10, 2026
claude added 3 commits July 11, 2026 07:24
…nd enforce per package manager

- Move the new allowUnverified parameter of DebUpdater/RpmUpdater.installWithCommandRunner
  to the last position with a default of true, restoring source and runtime compatibility
  for existing 6.x callers; doInstall still threads this.allowUnverifiedLinuxPackages.
- dnf/yum enforce mode now passes --setopt=localpkg_gpgcheck=1: local package files are
  governed by localpkg_gpgcheck (default False on dnf4/dnf5/yum), so omitting --nogpgcheck
  alone enforced nothing.
- Log enforce/bypass per branch instead of unconditionally: dpkg warns that the setting has
  no effect (dpkg performs no signature verification); bare rpm warns that enforcement
  cannot be applied via the CLI (default %_pkgverify_level is "digest").
- Rewrite the allowUnverifiedLinuxPackages JSDoc with the per-package-manager reality.
- Revert the blackbox test call sites now that the added positional argument is gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZTrgpZ9bNcWZ3BuamMhnz
…removing support

Replace the hard-coded base64 encoding with strict legacy-hex detection: a manifest sha512
that is exactly 128 hexadecimal characters is decoded as hex with a deprecation debug log
(removal planned for v28); anything else is decoded as base64, which electron-builder has
emitted since 19.x (2017). Detection cannot collide: base64-encoded sha512 is always 88
characters ending in "==", and a wrong pick only fails closed with ERR_CHECKSUM_MISMATCH.
Also drop the unsound "crafted-manifest mis-parsing vector" rationale from the comment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZTrgpZ9bNcWZ3BuamMhnz
…; docs: changesets + troubleshooting

- linuxUpdaterUnitTest: assert exact argv with toEqual for every enforce/bypass branch,
  add dpkg-branch tests (dpkg -i + apt-get -f fallback), a trailing-default compatibility
  test, warning-path tests for dpkg and bare rpm, and doInstall wiring tests proving
  this.allowUnverifiedLinuxPackages is threaded through DebUpdater (apt) and RpmUpdater
  (zypper); drop the (A2) marker and use NoOpLogger instead of an any-cast stub.
- httpExecutorTest: cover detectSha512Encoding (128-char hex vs base64) and DigestTransform
  end-to-end for both encodings plus the fail-closed mismatch path.
- Changesets: scope the enforcement claims per package manager, note the trailing optional
  parameter, replace the hash-encoding security claim with the strict-detection/deprecation
  description, and add electron-updater to the hash-encoding changeset front-matter.
- troubleshooting.md: note that manifest sha512 should be base64 as of v27 (hex is
  deprecated, removed in v28) with a conversion hint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZTrgpZ9bNcWZ3BuamMhnz
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.

2 participants