Agent Skills: Apple macOS CI/CD & Auto-Updater

Establish GitHub Actions macOS CI/CD for signing, notarization, GitHub Releases, and auto-updates. Use when setting up Apple app release pipelines, Developer ID signing, notarization, DMG/ZIP distribution, Sparkle (native), or electron-updater (Electron). Trigger phrases include "mac release CI", "notarize app", "auto-updater", "GitHub Actions macOS".

UncategorizedID: tomlord1122/tomtom-skill/apple-mac-cicd

Install this agent skill to your local

pnpm dlx add-skill https://github.com/Tomlord1122/tomtom-skill/tree/HEAD/skills/apple-mac-cicd

Skill Files

Browse the full folder contents for apple-mac-cicd.

Download Skill

Loading file tree…

skills/apple-mac-cicd/SKILL.md

Skill Metadata

Name
apple-mac-cicd
Description
Establish GitHub Actions macOS CI/CD for signing, notarization, GitHub Releases, and auto-updates. Use when setting up Apple app release pipelines, Developer ID signing, notarization, DMG/ZIP distribution, Sparkle (native), or electron-updater (Electron). Trigger phrases include "mac release CI", "notarize app", "auto-updater", "GitHub Actions macOS".

Apple macOS CI/CD & Auto-Updater

Expert workflow for shipping signed, notarized macOS apps via GitHub Actions with automatic updates. Grounded in the Cometrans (native Swift) and Cometode (Electron) repos in this workspace.

Reference Projects

| App | Stack | Release trigger | Auto-update | |-----|-------|-----------------|-------------| | Cometrans | Swift CLI → .app + DMG | workflow_dispatch with version input | Sparkle-ready build numbers (not wired yet) | | Cometode | Electron + Svelte | Push tag v* | electron-updater + latest-mac.yml |

Read the reference files when implementing:

Thinking Process

Step 1: Identify App Type

Goal: Pick the correct release and updater stack.

Decision Matrix:

| App type | Build tool | CI runner | Updater | |----------|-----------|-----------|---------| | Native Swift / SwiftPM | build_dmg.sh or Xcode | macos-26 (pin Xcode via DEVELOPER_DIR) | Sparkle + appcast | | Electron + electron-builder | pnpm build:mac | macos-latest | electron-updater + GitHub Releases |

Decision Point: State "This is a [native|electron] app; updater will use [Sparkle|electron-updater]."

Step 2: Apple Developer Prerequisites

Goal: Ensure signing and notarization credentials exist before touching CI.

Checklist:

  • [ ] Apple Developer Program membership
  • [ ] Developer ID Application certificate (not Mac App Store)
  • [ ] .p12 exported and base64-encoded for CI
  • [ ] App-specific password at appleid.apple.com (for notarytool)
  • [ ] Team ID from developer.apple.com

Actions:

  1. Run bash /mnt/skills/user/apple-mac-cicd/scripts/validate-secrets.sh to audit local env
  2. Configure GitHub repo secrets (see github-secrets.md)

Step 3: Local Build Script

Goal: One script produces reproducible signed artifacts locally and in CI.

Native (Cometrans pattern):

  • build_dmg.sh builds Swift release, assembles .app, codesigns with --options runtime, creates DMG
  • CFBundleVersion derived as major*10000 + minor*100 + patch for Sparkle semver comparison
  • NOTARIZE=1 triggers scripts/notarize.sh via xcrun notarytool submit --wait + stapler staple

Electron (Cometode pattern):

  • electron-builder.yml: hardenedRuntime: true, notarize: true, publish: github
  • mac targets: dmg + zip (zip required for electron-updater)
  • Entitlements in build/entitlements.mac.plist (JIT, unsigned executable memory for Electron)

Step 4: GitHub Actions Release Workflow

Goal: CI builds, signs, notarizes, and publishes to GitHub Releases.

Native workflow shape (Cometrans .github/workflows/release.yml):

  1. prepare job — resolve version, create/push tag
  2. build job — import P12 to ephemeral keychain, run ./build_dmg.sh, upload artifacts
  3. release job — download artifacts, softprops/action-gh-release with DMG + sha256

Electron workflow shape (Cometode .github/workflows/release.yml):

  1. Trigger on push: tags: ['v*']
  2. Sync package.json version from tag
  3. pnpm build:mac with signing env vars
  4. Upload dist/*.dmg, dist/*.zip, dist/*.blockmap, dist/latest-mac.yml (critical for auto-update)

Required secrets by stack:

| Secret | Native | Electron | |--------|--------|----------| | APPLE_DEVELOPER_ID_P12_BASE64 | ✓ | — | | APPLE_DEVELOPER_ID_P12_PASSWORD | ✓ | — | | KEYCHAIN_PASSWORD | ✓ | — | | DEVELOPER_ID_APPLICATION | ✓ | — | | CSC_LINK | — | ✓ (base64 p12) | | CSC_KEY_PASSWORD | — | ✓ | | APPLE_ID | ✓ | ✓ | | APPLE_APP_SPECIFIC_PASSWORD | ✓ | ✓ | | APPLE_TEAM_ID | ✓ | ✓ |

Step 5: Auto-Updater Integration

Goal: Users receive updates without manual DMG downloads.

Electron (Cometode — fully wired):

  • electron-updater reads latest-mac.yml from GitHub Releases
  • electron-builder.yml publish.provider: github must match repo owner/name
  • Main process: autoUpdater.autoDownload = true, check on startup + every 4h
  • Release workflow must attach latest-mac.yml, .zip, and .blockmap
  • Only enable in production (if (!is.dev))

Native (Cometrans — build-number ready, Sparkle pending):

  • build_dmg.sh already sets CFBundleVersion for Sparkle comparison
  • To complete: add Sparkle SPM dep, SUFeedURL in Info.plist, EdDSA signing key
  • CI must generate/sign appcast XML and publish alongside DMG on each release
  • See auto-updater.md

Step 6: CI Workflow for PRs

Goal: Catch build breaks before release.

Native: ci.yml on push/PR — swift build -c release && swift test on macos-26

Electron: Add ci.yml with pnpm typecheck && pnpm build (no signing needed for CI)

Step 7: Release & Verify

Goal: Ship and confirm auto-update works end-to-end.

Release checklist:

  • [ ] Bump version in source (version.txt or package.json)
  • [ ] Tag vX.Y.Z (Electron) or run workflow_dispatch (Cometrans)
  • [ ] CI completes signing + notarization
  • [ ] GitHub Release contains all required assets
  • [ ] Install previous version, confirm updater finds new release
  • [ ] spctl -a -vv -t install passes on downloaded artifact

Verify notarization locally:

xcrun stapler validate Cometrans-1.0.0.dmg
# or
spctl -a -vv -t install dist/cometode-1.0.0-arm64.dmg

Usage

Validate secrets are configured locally

bash /mnt/skills/user/apple-mac-cicd/scripts/validate-secrets.sh

Scaffold a release workflow

bash /mnt/skills/user/apple-mac-cicd/scripts/scaffold-release-workflow.sh \
  --type electron \
  --app-name MyApp \
  --output .github/workflows/release.yml

Arguments:

  • --typenative or electron (required)
  • --app-name — artifact stem, e.g. Cometrans (required)
  • --output — workflow file path (default: .github/workflows/release.yml)

Present Results to User

When helping set up macOS CI/CD, report:

  1. App type and chosen updater
  2. Secrets still missing (run validate script output)
  3. Files created/modified with paths
  4. Release steps — how to trigger first release
  5. Auto-update status — wired or remaining steps

Troubleshooting

"No signing certificate configured" in CI

  • Verify APPLE_DEVELOPER_ID_P12_BASE64 / CSC_LINK secret is set and decodes to valid P12

Notarization fails with invalid credentials

  • Regenerate app-specific password; confirm APPLE_TEAM_ID matches certificate

Gatekeeper blocks app despite CI success

  • Ensure --options runtime on codesign (native) or hardenedRuntime: true (Electron)
  • Confirm stapler ran: xcrun stapler validate <artifact>

electron-updater finds no updates

  • Release must include latest-mac.yml, .zip, .blockmap
  • publish.owner / publish.repo in electron-builder.yml must match GitHub repo
  • App must be built in production mode (not dev)

Sparkle shows wrong version order

  • Use numeric CFBundleVersion (Cometrans formula: major*10000 + minor*100 + patch)
  • Never use semver strings in CFBundleVersion