Skip to content

Never ship a macOS download Gatekeeper refuses - #257

Merged
danielehrhardt merged 1 commit into
mainfrom
fix/macos-signing-guard
Oct 28, 2026
Merged

danielehrhardt merged 1 commit into
mainfrom
fix/macos-signing-guard

Conversation

@danielehrhardt

Copy link
Copy Markdown
Contributor

Problem

On a Mac a download could end in "can't be opened, move it to the Trash". I checked every macOS file v0.2.30 ships:

Download Result
Godmode.Bot_0.2.30_aarch64.dmg / _x64.dmg + the app inside Developer ID Application: Codext GmbH, notarized, stapled, syspolicy_check passes
Update bundles (.app.tar.gz, in-app updater) same, pass
godmode-darwin-arm64 / -x64 (headless server, on the download page) ad-hoc signed, Gatekeeper rejects it

Releases were also only protected by a warning: without the Apple secrets the workflow built an unsigned app and still published it.

Changes

  • Standalone macOS binaries are signed with the Codext GmbH Developer ID (hardened runtime, secure timestamp, the same JIT entitlements as the app's core sidecar) and notarized (scripts/macos-sign-binaries.sh, temporary keychain, notarytool status must be Accepted, log printed otherwise). Tested locally on the v0.2.30 binary: notarization Accepted, godmode version still runs.
  • Official releases fail instead of shipping unsigned: create-release checks that every Apple secret exists, the identity is a Developer ID of the team, the .p12 opens, belongs to the team and isn't expired (warning 45 days before; the current certificate runs until 2027-11-15).
  • One check for everything a user downloads: scripts/macos-verify.sh (signer = Codext GmbH team, hardened runtime, timestamp, deep strict verify, stapled ticket, spctl says "Notarized Developer ID", syspolicy_check, mounts DMGs incl. the licence prompt). It runs on the built app + update bundle, on the notarized DMG before upload and on the signed binaries.
  • Daily watchdog verify-downloads.yml: every morning and after each published release it downloads what usegodmode.com and the update feed serve, marks the files as browser downloads, runs the same check and opens or updates an issue when a download would be refused.

Verification

  • scripts/macos-verify.sh on the live v0.2.30 DMGs and update bundles: pass. On the live server binary: fails with "not signed with a Developer ID of team STSYBH724K (Signature=adhoc)". So the watchdog goes green with the next release.
  • actionlint clean (only the existing SC2012 info notes).

The standalone macOS binaries were only signed ad hoc, so a browser download
could only be moved to the Trash. They are now signed with the Codext GmbH
Developer ID (hardened runtime, timestamp) and notarized.

Official releases fail instead of shipping unsigned: the Apple secrets, the
certificate's team and expiry are checked up front, and every DMG, app,
update bundle and binary goes through scripts/macos-verify.sh. A daily
workflow downloads what usegodmode.com serves, checks it the same way and
opens an issue when a download would be refused.
@danielehrhardt
danielehrhardt merged commit 1079678 into main Oct 28, 2026
8 checks passed
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.

1 participant