feat: in-app auto-updates via Sparkle#17
Merged
Merged
Conversation
Add a "Check for Updates..." item and an "Automatically check for updates" toggle to the menu, backed by Sparkle. Updates are EdDSA-signed and pulled from GitHub Releases. Sparkle is vendored on demand: `make sparkle` fetches a pinned, checksum- verified Sparkle.framework into gitignored third_party/. The framework is embedded in the bundle and its nested XPC services / Updater.app / Autoupdate are re-signed inside-out with the Developer ID (hardened runtime + timestamp) before the app is sealed. `import Sparkle` is guarded by canImport, so the SwiftPM/test build compiles a no-op stub and stays free of the binary framework. The appcast (appcast.xml) lives on a pinned `appcast` GitHub release (stable URL); enclosures point at each version's own release. `make appcast` refreshes and signs it; `make sparkle-keys` handles one-time key setup. The cask gets `auto_updates true` so brew defers to the in-app updater. Co-Authored-By: Claude
GregTheGreek
marked this pull request as ready for review
July 10, 2026 16:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds in-UI auto-updates: a "Check for Updates…" item and an "Automatically check for updates" toggle in the menu, backed by Sparkle. Updates are EdDSA-signed and served from GitHub Releases.
make sparklefetches a pinned, checksum-verifiedSparkle.frameworkinto gitignoredthird_party/. No binary blob in git.Updater.app/Autoupdateare re-signed inside-out with the Developer ID (hardened runtime + timestamp) before the app is sealed.codesign --verify --deep --strictpasses.import Sparkleis behindcanImport, so the SwiftPM/swift testbuild compiles a no-op stub and needs no framework.appcast.xmllives on a pinnedappcastrelease (stable URL); enclosures point at each version's ownvX.Y.Zrelease.make appcastrefreshes + signs it;make sparkle-keysdoes one-time key setup. Cask getsauto_updates true.Notes for reviewer
main(pre-dmg), so it wires the appcast/enclosure to the current.zipartifact. It will need a trivial rebase after feat: distribute a notarized .dmg instead of a .zip #16 (dmg) merges -$(ZIP)→$(DMG)in the enclosure/cask URL. Sparkle updates from either equally.SUPublicEDKeyin Info.plist was generated during setup; the private key is in the release machine's keychain. See "One-time setup" below.Test plan
make bundlebuilds, embeds, and signs Sparkle;codesign --verify --deep --strictclean@rpath/Sparkle.frameworkswift build+swift test(9 tests) pass via the no-op stubgenerate_appcastverified to preserve prior versioned entries when appending a new onegh release create appcast …, then a realmake release && make appcastcycle end-to-end