Skip to content

Latest commit

 

History

History
116 lines (89 loc) · 4.35 KB

File metadata and controls

116 lines (89 loc) · 4.35 KB

Releasing Agent Notch

Production releases are Apple Silicon ZIP archives. They are signed with a Developer ID Application certificate, notarized by Apple, stapled, and shipped with a SHA-256 checksum. Unsigned prereleases are ad-hoc signed and labeled as previews. Never present them as notarized builds.

Prepare the release

  1. Move the relevant CHANGELOG.md entries from Unreleased into a versioned section.

  2. Update VERSION using semantic versioning.

  3. Run:

    swift test
    swift test -c release
    ./script/package_release.sh --adhoc
    ./script/check_repository.sh
  4. Commit those changes and create a signed tag matching v$(cat VERSION).

Local signed and notarized package

Store App Store Connect credentials in a notarytool keychain profile once:

xcrun notarytool store-credentials agent-notch-notary

Then package with the exact Developer ID identity shown by security find-identity -p codesigning -v:

AGENT_NOTCH_BUILD_NUMBER=1 ./script/package_release.sh \
  --identity "Developer ID Application: Example Name (TEAMID)" \
  --notarize \
  --keychain-profile agent-notch-notary

The script builds the release configuration for arm64, signs nested code (including Sparkle) and the app with hardened runtime, verifies the bundle, notarizes and staples it, re-verifies Gatekeeper acceptance, and writes the ZIP plus .sha256 file under dist/.

Signed releases also publish a Sparkle appcast.xml. Generate it from the ZIP with the EdDSA private key that matches Resources/SparklePublicEDKey:

SPARKLE_ED_PRIVATE_KEY="$(cat /path/to/sparkle-ed-private-key)" \
  ./script/generate_appcast.sh

The private key is the 32-byte EdDSA seed, base64-encoded. Never commit it. The appcast enclosure URL is the GitHub release asset for that ZIP. In-app updates read https://github.com/Aforno/AgentNotch/releases/latest/download/appcast.xml.

GitHub release workflow

The Release workflow requires these repository Actions secrets:

  • MACOS_CERTIFICATE: base64-encoded Developer ID Application .p12
  • MACOS_CERTIFICATE_PASSWORD: password for that .p12
  • MACOS_SIGNING_IDENTITY: full Developer ID Application identity
  • APPLE_API_KEY_ID: App Store Connect API key ID
  • APPLE_API_ISSUER_ID: App Store Connect issuer ID
  • APPLE_API_PRIVATE_KEY: complete .p8 private-key contents
  • SPARKLE_ED_PRIVATE_KEY: base64 EdDSA seed that matches Resources/SparklePublicEDKey

Push a signed vX.Y.Z tag only after CI passes. All tags share one release concurrency group, so one GitHub release runs at a time. The workflow validates that the tag matches VERSION, imports the temporary certificate, builds and notarizes the app, creates the checksum, signs a Sparkle appcast, and publishes the ZIP, checksum, and appcast.xml to the GitHub release. After the GitHub files are up, it points Casks/agent-notch.rb at that ZIP and checksum and pushes the cask bump to the default branch unless the cask already names a newer version. Homebrew users on this tap pick that up with brew update. Packaged apps check the appcast on launch and once a day, then wait for the user to download and restart. The cask sets auto_updates true so Homebrew does not fight the in-app updater.

If the cask commit cannot push, update it locally from the published checksum:

./script/update_cask.sh --version "$(tr -d '[:space:]' < VERSION)" \
  --checksum-file "dist/Agent-Notch-$(tr -d '[:space:]' < VERSION)-macOS-arm64.zip.sha256"

Do not rewrite the cask SHA-256 during release prep. The checksum belongs to the notarized GitHub artifact, not a local ad-hoc rebuild.

Signing credentials are an external release gate. Never commit them to this repository or print them in workflow logs.

Unsigned prerelease

When signing credentials are unavailable and an unsigned preview is explicitly approved, opt in before pushing the tag:

gh variable set RELEASE_MODE --repo Aforno/AgentNotch \
  --body unsigned-prerelease
git tag -a "v$(cat VERSION)" -m "Agent Notch $(cat VERSION)"
git push origin "v$(cat VERSION)"

The workflow ad-hoc signs the app, marks the GitHub release as a prerelease, and puts a notarization and Gatekeeper warning at the top of its notes. After the release succeeds, remove the temporary opt-in so later tags default back to the signed release path:

gh variable delete RELEASE_MODE --repo Aforno/AgentNotch