Skip to content

feat: upstream Electron's squirrel.mac patches#312

Merged
MarshallOfSound merged 6 commits into
mainfrom
sam/upstream-electron-patches
May 3, 2026
Merged

feat: upstream Electron's squirrel.mac patches#312
MarshallOfSound merged 6 commits into
mainfrom
sam/upstream-electron-patches

Conversation

@MarshallOfSound

@MarshallOfSound MarshallOfSound commented May 3, 2026

Copy link
Copy Markdown
Collaborator

Upstreams the remaining electron/patches/squirrel.mac/ patches into this repo so Electron can eventually drop them. Six commits, 8 files, +537/−51, 63 → 74 tests.

Commit Upstreams Tests added
feat: SquirrelMacEnableDirectContentsWrite feat_add_new_squirrel_mac_bundle_installation_method_behind_flag parent-dir-untouched e2e
fix: abort install if app running; resolve target path once fix_abort_installation_attempt_at_the_final_mile_if_the_app_is + fix_resolve_target_bundle_path_once_at_start_of_install symlink-target rejected, abort-if-running
feat: ElectronSquirrelPreventDowngrades feat_add_ability_to_prevent_version_downgrades +isVersionAllowedForUpdate:from: units
refactor: harden ShipIt launch refactor_use_posix_spawn_instead_of_nstask… + fix_trigger_shipit_mach_service_after_smjobsubmit… + chore_turn_off_launchapplicationaturl_deprecation… (existing remote-ShipIt spec exercises new path)
refactor: non-deprecated NSKeyedArchiver refactor_use_non-deprecated_nskeyedarchiver_apis SQRLInstallerOwnedBundle round-trip
fix: prune orphaned staged updates fix_clean_up_orphaned_staged_updates_before_downloading_new_update unit prune + e2e bounded-count; replaces xit

Fixes #124. Fixes #196. Fixes #264.

Note

Two adaptations should be backported to Electron's patches:

  • SQRLUpdater.m: BOOL launchPrivileged = !targetWritable in the original direct-contents-write patch shadowed the outer var — it was a dead store
  • SQRLInstaller.m: runningApplicationsWithBundleIdentifier: throws on nil; guarded it

Replaces the stacked #303 / #304 / #305 / #306 / #307 / #309. #302 (strict codesign validation) stays separate — it touches only SQRLCodeSignature.m.

…flag

[upstream] electron/patches/squirrel.mac/feat_add_new_squirrel_mac_bundle_installation_method_behind_flag.patch

When the user default is set, install by atomically renaming the
Contents/ folder rather than swapping the .app directory itself, so
the updating process only needs write access to its own bundle (not
the parent /Applications folder).

Fixes a variable-shadowing bug from the original patch where the
'ignore parent writability' branch in SQRLUpdater wrote to a new
local instead of the outer launchPrivileged.

Adds a spec that tags the .app dir with an xattr, runs an in-process
install with the flag enabled, and asserts the xattr survived.
[upstream] electron/patches/squirrel.mac/fix_abort_installation_attempt_at_the_final_mile_if_the_app_is.patch
[upstream] electron/patches/squirrel.mac/fix_resolve_target_bundle_path_once_at_start_of_install.patch

The first patch closes a race between ShipIt launching and performing
the atomic rename by checking running applications immediately before
the move. The second resolves the target bundle URL once up front,
rejects requests whose path traverses symlinks, and threads the
canonical URL through the rest of the chain so every step operates on
the location validation saw.

Adapted: guard the running-app check with a nil bundleIdentifier check
(NSRunningApplication throws when passed nil; existing fixtures use
nil intentionally).

Adds specs for: install rejected when targetBundleURL is a symlink;
install aborted with SQRLInstallerErrorAppStillRunning while the
target app is running.
[upstream] electron/patches/squirrel.mac/feat_add_ability_to_prevent_version_downgrades.patch

When the running app's Info.plist sets ElectronSquirrelPreventDowngrades
to true, refuse to install update bundles whose CFBundleShortVersionString
is lower than the current version (or where either side is not a simple
A.B.C version).

Adds unit specs for +isVersionAllowedForUpdate:from:. The end-to-end
'should not update to lower version numbers' / 'not a valid version
string' cases require Info.plist mutation on the running host bundle
and are covered by Electron's integration suite.
[upstream] electron/patches/squirrel.mac/refactor_use_posix_spawn_instead_of_nstask_so_we_can_disclaim_the.patch
[upstream] electron/patches/squirrel.mac/fix_trigger_shipit_mach_service_after_smjobsubmit_to_unblock.patch
[upstream] electron/patches/squirrel.mac/chore_turn_off_launchapplicationaturl_deprecation_errors_in_squirrel.patch

- ShipIt-main.m: use posix_spawn with the responsibility-disclaim flag
  when re-spawning the post-install relauncher so a hot-swapped binary
  can't inherit the parent's TCC permissions
- SQRLShipItLauncher.m: after SMJobSubmit, send a one-shot Mach message
  to the registered service so launchd starts the job even when the
  user domain is in on-demand-only mode (pending OS update)
- ShipIt-main.m: pragma-suppress the launchApplicationAtURL deprecation
  (replacement is 10.15+; tracked at electron/electron#43168)

No new specs: launchd / TCC / mach-port behaviour isn't reachable in a
unit test. Existing remote-ShipIt SQRLInstallerSpec specs continue to
exercise the new spawn path.
[upstream] electron/patches/squirrel.mac/refactor_use_non-deprecated_nskeyedarchiver_apis.patch

unarchiveObjectWithData: -> initForReadingFromData:error: + decodeObjectForKey:
archivedDataWithRootObject: -> archivedDataWithRootObject:requiringSecureCoding:error:

Adds a spec asserting SQRLInstallerOwnedBundle round-trips through the
ownedBundle property accessor pair (which is what writes/reads the
CFPreferences blob between ShipIt invocations).
[upstream] electron/patches/squirrel.mac/fix_clean_up_orphaned_staged_updates_before_downloading_new_update.patch

When checkForUpdates is called while an update is already staged,
Squirrel created a new temporary directory for the download without
cleaning up the old one. Chain a pruneOrphanedUpdateDirectories step
before uniqueTemporaryDirectoryForUpdate that reads the current
ShipItState.plist, preserves the directory it references, and deletes
every other update.* directory — keeping the on-disk footprint bounded
while quitAndInstall remains safe to call.

Adds specs:
- removeUpdateDirectoriesInStorageURL:excludingURL: deletes all
  update.* dirs except the excluded one and leaves non-prefixed files
  alone
- end-to-end via TestApplication: 3 sequential checks leave at most 2
  update directories on disk

Replaces the previously-xit'd 'should remove downloaded archives after
updating' (asserted 0, never matched the 7dffc4b semantics).
@MarshallOfSound MarshallOfSound merged commit 0f51b13 into main May 3, 2026
6 of 26 checks passed
@MarshallOfSound MarshallOfSound deleted the sam/upstream-electron-patches branch May 3, 2026 09:39
MarshallOfSound added a commit to electron/electron that referenced this pull request May 13, 2026
Bumps squirrel.mac from 0e5d146ba1 to 8d808803bc and removes 14 patches
that have been upstreamed into Squirrel/Squirrel.Mac (mainly via
Squirrel/Squirrel.Mac#312, plus Squirrel/Squirrel.Mac#298,
Squirrel/Squirrel.Mac#302, Squirrel/Squirrel.Mac#308). Only
build_add_gn_config.patch remains, slimmed down to GN-only changes
since Squirrel/Squirrel.Mac#298 upstreamed the ReactiveCocoa ->
ReactiveObjC import renames it was carrying.
jkleinsc pushed a commit to electron/electron that referenced this pull request May 14, 2026
* fix: don't return a `nullptr` from `TargetForRect`

Co-authored-by: Noah Gregory <nmggithub@electronjs.org>

* fix: address concerns

Co-authored-by: Noah Gregory <nmggithub@electronjs.org>

* chore: use promise's context for memory dump callback. (#51570)

Co-authored-by: BILL SHEN <15865969+cucbin@users.noreply.github.com>

* build: only fallback to CHROMIUM_BUILDTOOLS_PATH if needed (#51558)

* build: only fallback to CHROMIUM_BUILDTOOLS_PATH if needed

* ci: fix lint workflow detection of src/buildtools

* ci: bump build-tools SHA

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

* build: update squirrel.mac to 8d808803, drop upstreamed patches (#51584)

Bumps squirrel.mac from 0e5d146ba1 to 8d808803bc and removes 14 patches
that have been upstreamed into Squirrel/Squirrel.Mac (mainly via
Squirrel/Squirrel.Mac#312, plus Squirrel/Squirrel.Mac#298,
Squirrel/Squirrel.Mac#302, Squirrel/Squirrel.Mac#308). Only
build_add_gn_config.patch remains, slimmed down to GN-only changes
since Squirrel/Squirrel.Mac#298 upstreamed the ReactiveCocoa ->
ReactiveObjC import renames it was carrying.

Co-authored-by: Samuel Attard <sam@electronjs.org>

* Revert "build: update squirrel.mac to 8d808803, drop upstreamed patches (#51584)"

This reverts commit d4e9004.

* Revert "build: only fallback to CHROMIUM_BUILDTOOLS_PATH if needed (#51558)"

This reverts commit 090b568.

* Revert "chore: use promise's context for memory dump callback. (#51570)"

This reverts commit a74d8a1.

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Noah Gregory <nmggithub@electronjs.org>
Co-authored-by: BILL SHEN <15865969+cucbin@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
Co-authored-by: Samuel Attard <sam@electronjs.org>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected Version Comparison Result SMJobSubmit will fail on some osx App can crash if relaunched manually during update installation

1 participant