Skip to content

Sign releases with TAM's Developer ID and notarize them - #8

Merged
javiertoledo merged 1 commit into
mainfrom
release-signing
Oct 9, 2026
Merged

javiertoledo merged 1 commit into
mainfrom
release-signing

Conversation

@javiertoledo

Copy link
Copy Markdown
Member

Downloads now open like any other app from the internet: no more Privacy & Security → Open Anyway for an ad hoc signed app.

What changes

  • scripts/package-release.sh signs with the Developer ID, the hardened runtime and a secure timestamp. It notarizes and staples the app (so the ZIP's copy opens offline too), packages the stapled app, then signs, notarizes and staples the DMG. It stops unless Apple answers Accepted and the team, stapled tickets and Gatekeeper's verdict check out. Packages are assembled outside dist/, so a failed notarization leaves nothing to upload. Without SHEPHERDR_SIGN_IDENTITY it still makes ad hoc packages for local testing.
  • release.yml checks that signing is configured before the tests run. It imports the .p12 into a temporary keychain, picks the Developer ID identity of APPLE_TEAM_ID by hash, and has Apple check the notarization credentials before building. It deletes the keychain afterwards. The job uses the release environment, which only v* tags and main may deploy to. The timeout is now 60 minutes, because notarization runs twice.
  • Docs: RELEASING.md documents the secrets and how to set up a certificate. INSTALL.txt, the README, the guide and the release notes drop the Open Anyway instructions.

Setup already done

  • Developer ID Application certificate (G2) of The Agile Monkeys SL, team 67266UR7NA, issued from a CSR whose key stays in the maintainer's keychain.
  • The release environment holds DEVELOPER_ID_P12_BASE64, DEVELOPER_ID_P12_PASSWORD, NOTARY_APPLE_ID, NOTARY_PASSWORD and the variable APPLE_TEAM_ID. The .p12 holds only that identity and was tested by importing it into a throwaway keychain.

Verified

  • A local signed build was notarized for both the app and the DMG. A quarantined copy of the DMG and the app inside it pass Gatekeeper as source=Notarized Developer ID, origin The Agile Monkeys SL (67266UR7NA), with stapled tickets, runtime flags and the microphone entitlement.
  • The ad hoc path still builds and verifies.
  • A missing notarization profile stops the release, and Gatekeeper rejects an ad hoc app.
  • The workflow's CI path runs for the first time on the next tag. If it fails, nothing is published, and Run workflow on the same tag resumes it.

🤖 Generated with Claude Code

Downloads open like any other app from the internet: no more trip to
Privacy & Security to allow an ad hoc signed app.

The packaging script signs with the Developer ID, the hardened runtime
and a secure timestamp. It notarizes and staples the app, packages the
stapled app, then signs, notarizes and staples the DMG. It stops unless
Apple accepts both and the team, tickets and Gatekeeper's verdict check
out, and nothing reaches dist/ before that. Without an identity it still
makes ad hoc packages for local testing.

The release workflow imports the certificate into a temporary keychain,
lets Apple check the notarization credentials before building, and
removes the keychain afterwards. Its secrets live in the release
environment, which only v* tags and main may use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T17:31:54.417858Z 5ec608d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ec608d3a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +100 to 101
- name: Build, sign, notarize and verify release packages
run: bash scripts/package-release.sh "$RELEASE_TAG"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject tags without the signing-aware packager

When a workflow-dispatch run targets a tag predating this commit, checkout at lines 49–52 replaces scripts/package-release.sh with that tag's ad-hoc-only version. The new credential setup still succeeds, but this step invokes the old script and the later publish step can make the resulting unnotarized artifacts public; this is especially reachable because docs/RELEASING.md explicitly recommends rerunning the workflow with an existing tag to resume a draft. Reject tags lacking the signing implementation or independently verify the produced app and DMG before publication.

Useful? React with 👍 / 👎.

runs-on: macos-15
timeout-minutes: 30
# Notarization waits for Apple twice: once for the app, once for the disk image.
timeout-minutes: 60

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Leave headroom for both notarization waits

The packaging script performs two sequential notarization submissions, each allowed to wait up to 30 minutes, while this 60-minute job limit also includes checkout, dependency resolution, tests, compilation, signing, packaging, stapling, verification, and publishing. If Apple's two responses consume nearly their configured limits, GitHub terminates an otherwise successful release before it can publish; set the job timeout above the combined notarization limits plus build overhead.

Useful? React with 👍 / 👎.

@javiertoledo
javiertoledo merged commit da26279 into main Oct 9, 2026
2 checks passed
@javiertoledo
javiertoledo deleted the release-signing branch October 9, 2026 17:34
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