$ cat blog/updates

Verifiable macOS Updates

A latest-release URL is convenient. A signature is what makes the downloaded update trustworthy.

The macOS build uses Sparkle 2. On launch and on a daily cadence, the app checks an XML appcast attached to the latest non-prerelease GitHub Release. The appcast declares the available version and the downloadable artifact.

Agent Island running in the macOS top bar
The macOS app receives signed updates through its public Sparkle appcast; the visible status surface remains local.

One public feed

https://github.com/tristan666666/agent-island/releases/latest/download/appcast.xml

GitHub redirects that stable URL to the appcast asset on the newest public release. This keeps installed builds from depending on a version-specific URL.

The signature is the boundary

A download URL alone is not sufficient. Sparkle verifies each update with an EdDSA signature against the public key embedded in the app. A redirected or replaced URL cannot produce a valid update without the matching private signing key.

The private key belongs in the maintainer's keychain or the release workflow secret. It is never committed to the repository. Losing it is operationally serious because existing installs trust the embedded public key.

How a release reaches an install

  1. The version is bumped and tagged.
  2. The release workflow builds and signs the macOS artifact.
  3. The workflow generates the matching appcast.
  4. Both artifacts are attached to the public release.
  5. An installed app checks the feed and verifies the signature before installation.

Manual checks still matter

The app exposes a manual update check in Settings. Maintainers can also run the release script locally and inspect the unpublished DMG and appcast before tagging a release.

This update path applies to the macOS build. Windows packaging follows its own release path.

← All posts