mac-release-verify checks a macOS release artifact before you publish it — the signature, the notarization ticket on the app and on the disk image, the appcast, the build number Sparkle actually compares, the dSYM. It only reads. It never signs, uploads, publishes or modifies anything, and it never asks for credentials.
None of these fail a build. The archive succeeds, the upload goes through, CI stays green. You find out from a user, or from a crash you cannot read, or from an update that never arrives.
| What shipped | What the user got |
|---|---|
The .app was notarized, then wrapped in a DMG. The DMG never was. |
Gatekeeper inspects the disk image at download time. Nobody could open it. |
The marketing version was bumped. CFBundleVersion was not. |
Sparkle compares the build number. Every existing user was told they were already up to date. |
| The appcast was generated from build settings instead of from the built artifact. | The feed advertised a version that did not match the binary behind it. |
| The dSYM was not kept. | Every crash report from that version arrived as raw addresses, for the whole life of the release. A dSYM cannot be produced afterwards. |
| A config file stayed in Copy Bundle Resources. | The key was inside every copy downloaded, and a released build cannot be recalled. |
Every failure states the consequence, not just the rule. Exit code is 0 when
everything passed and 1 when something failed, so it gates a release script directly.
--deep --strictSUPublicEDKey present, so Sparkle can verify at allNo signing, no notarizing, no uploading, no publishing, no tagging, no modifying. Disk images are mounted read-only and unmounted on exit — there is a test that asserts nothing is left mounted. It never asks for an Apple ID, an App Store Connect key, or any other credential, and it reports nothing anywhere. It is one file of shell script using only tools that already ship with macOS, so you can read the whole thing before you run it.
A checker that only ever reports PASS is indistinguishable from one that does nothing. So every check is exercised against a deliberately broken artifact built on the fly — an unsigned app, an unstapled disk image, an appcast that disagrees with the binary, a build number that did not move, a missing dSYM, a credential left in Resources. 18 assertions, no signing identity or Apple account required, run in CI on every push.
Shipping a Mac app is one action in your head and four or more separate switches in reality — the release, the appcast, the download page, the release notes. Forget one and nothing turns red. This checker is the first piece of a tool for that whole problem.
Writing → — the failures above, each one in full: what shipped, what the user saw, and what could have been read from the artifact instead.
A written playbook — shipping to the Mac App Store and directly at the same time, and every way it goes wrong — is in progress. If you want it when it lands, or you have a failure mode that should be a check, say hello or open an issue.