Skip to content

Sign releases with a Developer ID and notarise them - #5

Merged
radiosilence merged 3 commits into
mainfrom
notarise
Sep 29, 2026
Merged

radiosilence merged 3 commits into
mainfrom
notarise

Conversation

@radiosilence

@radiosilence radiosilence commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Release DMGs were ad-hoc signed, so Gatekeeper refused them and the cask ran xattr -cr in a postflight step (and manual installs had to do it by hand). This signs and notarises releases so neither is needed.

What changes

  • create-app-bundle signs with SIGN_IDENTITY when set: hardened runtime, secure timestamp, and the bundled browser-schedule-cli signed before the bundle (no --deep, which Apple advises against for distribution signing). Unset, it ad-hoc signs as before, so task install and PR builds are unchanged.

  • New task notarize signs the DMG, submits it with notarytool using an App Store Connect API key, staples and validates the ticket, and checks it with spctl.

  • Release job no longer reuses the build job's ad-hoc DMG. When a version bump triggers a release, it imports the Developer ID certificate into a per-job keychain with a random password, builds the DMG signed, and notarises it. PR builds and non-release pushes never touch the secrets or the notary service.

  • Cask drops the postflight_steps xattr block; release notes drop the manual xattr step.

  • Toolchain: CI runs on the xcode-27 runner image (Xcode 27.0, Swift 6.4) with Xcode's bundled Swift, replacing swift-actions/setup-swift. Its pinned Swift 6.1 could not build against the SDK in the runner's Xcode, which has failed every build on main. macos-latest still defaults to Xcode 26.6, so it would leave the build a major version behind. Package.swift moves to swift-tools-version: 6.4; dependencies were already at their latest compatible versions.

  • Action pins: actions/checkout v7.0.1, actions/upload-artifact v7.0.1, softprops/action-gh-release v3.0.3, matching koan.

Risk

If the secrets are missing, the release job fails at the certificate import rather than shipping an ad-hoc build. That is deliberate: the regenerated cask no longer strips quarantine, so an unsigned release published through it would be blocked by Gatekeeper for every Homebrew user. Nothing runs until VERSION is bumped.

xcode-27 is a GitHub preview image. If it becomes unavailable, macos-26 plus sudo xcode-select -s /Applications/Xcode_26.6.app is the fallback, along with dropping the manifest to tools 6.3.

Required before the next release

Repository secrets on this repo (same names and encoding as koan's):

  • MACOS_CERTIFICATE_P12: base64 of the Developer ID Application .p12
  • MACOS_CERTIFICATE_PASSWORD
  • APPLE_API_KEY_P8: base64 of the App Store Connect .p8
  • APPLE_API_KEY_ID, APPLE_API_ISSUER_ID

Verifying

Locally, both signing paths of create-app-bundle produce a bundle that passes codesign --verify --strict --deep; with an identity, both binaries carry the runtime flag and a timestamp, and the hardened CLI runs. The notarisation step itself is only exercised by the first release after merge; watch the Notarise step's notarytool log.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YXLtjqcyvZ1VP9uK9jnMuR

The release job builds the DMG itself with the Developer ID identity from
repository secrets, notarises and staples it. The cask no longer strips the
quarantine attribute, and manual installs no longer need xattr.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXLtjqcyvZ1VP9uK9jnMuR
@radiosilence radiosilence added the enhancement New feature or request label Sep 29, 2026
radiosilence and others added 2 commits September 29, 2026 13:06
The pinned Swift 6.1 toolchain cannot build against the macOS 26.5 SDK
in the runner's Xcode, so every build failed at the first import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXLtjqcyvZ1VP9uK9jnMuR
CI moves to the xcode-27 runner image, since macos-latest defaults to
Xcode 26.6. The manifest requires Swift tools 6.4, and the checkout,
upload-artifact and action-gh-release pins move to their current majors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXLtjqcyvZ1VP9uK9jnMuR
@radiosilence
radiosilence merged commit d1a174f into main Sep 29, 2026
2 checks passed
@radiosilence
radiosilence deleted the notarise branch September 29, 2026 12:10
@radiosilence radiosilence mentioned this pull request Sep 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant