macos-notarization-workflow
SkillDev toolsAutomate Apple notarization with xcrun notarytool for macOS application distribution
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the macos-notarization-workflow skill
What this skill tells your AI
The instructions your AI receives, as published by a5c-ai/babysitter in library/specializations/desktop-development/skills/macos-notarization-workflow/SKILL.md and read by ahel’s review.
Automate Apple notarization workflow using xcrun notarytool for macOS applications. This skill handles the complete notarization process including submission, status checking, and stapling.
Capabilities
- Submit apps for notarization via notarytool
- Monitor notarization status
- Staple notarization ticket to app
- Handle notarization errors
- Generate CI/CD notarization scripts
- Configure App Store Connect API keys
- Validate apps before submission
- Generate notarization reports
Input Schema
{
"type": "object",
"properties": {
"projectPath": {
"type": "string",
"description": "Path to the project"
},
"appPath": {
"type": "string",
"description": "Path to the signed app bundle or DMG"
},
"authMethod": {
"enum": ["app-store-connect-api", "apple-id", "keychain"],
"default": "app-store-connect-api"
},
"credentials": {
"type": "object",
"properties": {
"keyId": { "type": "string" },
"issuerId": { "type": "string" },
"keyPath": { "type": "string" },
"appleId": { "type": "string" },
"teamId": { "type": "string" }
}
},
"waitForCompletion": {
"type": "boolean",
"default": true
},
"staple": {
"type": "boolean",
"default": true
}
},
"required": ["projectPath", "appPath"]
}
Output Schema
{
"type": "object",
"properties": {
"success": { "type": "boolean" },
"submissionId": { "type": "string" },
"status": { "enum": ["Accepted", "Invalid", "In Progress", "Rejected"] },
"logUrl": { "type": "string" },
"errors": { "type": "array" },
"stapled": { "type": "boolean" }
},
"required": ["success"]
}
Notarization Workflow
1. Prerequisites
# Ensure Xcode command line tools are installed
xcode-select --install
# Verify code signing
codesign --verify --deep --strict MyApp.app
codesign -vvv --deep --strict MyApp.app
# Check hardened runtime
codesign -dvvv MyApp.app | grep runtime
# Should show: flags=0x10000(runtime)
2. Store Credentials (Recommended)
# Store App Store Connect API key in keychain
xcrun notarytool store-credentials "MyProfile" \
--key ~/private_keys/AuthKey_XXXXXXXXXX.p8 \
--key-id XXXXXXXXXX \
--issuer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Or store Apple ID credentials
xcrun notarytool store-credentials "MyAppleIDProfile" \
--apple-id your.email@example.com \
--team-id XXXXXXXXXX \
--password @keychain:AC_PASSWORD
3. Submit for Notarization
# Using stored credentials
xcrun notarytool submit MyApp.app \
--keychain-profile "MyProfile" \
--wait
# Using API key directly
xcrun notarytool submit MyApp.app \
--key ~/private_keys/AuthKey_XXXXXXXXXX.p8 \
--key-id XXXXXXXXXX \
--issuer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--wait
# Using Apple ID
xcrun notarytool submit MyApp.app \
--apple-id your.email@example.com \
--team-id XXXXXXXXXX \
--password @keychain:AC_PASSWORD \
--wait
4. Check Status
# Check specific submission
xcrun notarytool info <submission-id> \
--keychain-profile "MyProfile"
# Get submission log
xcrun notarytool log <submission-id> \
--keychain-profile "MyProfile" \
developer_log.json
# List recent submissions
xcrun notarytool history \
--keychain-profile "MyProfile"
5. Staple Ticket
# Staple to app bundle
xcrun stapler staple MyApp.app
# Staple to DMG
xcrun stapler staple MyApp.dmg
# Staple to pkg
xcrun stapler staple MyApp.pkg
# Validate stapling
xcrun stapler validate MyApp.app
Complete Script
#!/bin/bash
# notarize.sh
set -e
APP_PATH="${1}"
KEYCHAIN_PROFILE="${2:-MyProfile}"
echo "=== Validating app bundle ==="
codesign --verify --deep --strict "$APP_PATH"
echo "=== Submitting for notarization ==="
SUBMISSION_OUTPUT=$(xcrun notarytool submit "$APP_PATH" \
--keychain-profile "$KEYCHAIN_PROFILE" \
--wait \
--output-format json)
SUBMISSION_ID=$(echo "$SUBMISSION_OUTPUT" | jq -r '.id')
STATUS=$(echo "$SUBMISSION_OUTPUT" | jq -r '.status')
echo "Submission ID: $SUBMISSION_ID"
echo "Status: $STATUS"
if [ "$STATUS" != "Accepted" ]; then
echo "=== Notarization failed, fetching log ==="
xcrun notarytool log "$SUBMISSION_ID" \
--keychain-profile "$KEYCHAIN_PROFILE" \
notarization_log.json
cat notarization_log.json
exit 1
fi
echo "=== Stapling ticket ==="
xcrun stapler staple "$APP_PATH"
echo "=== Validating staple ==="
xcrun stapler validate "$APP_PATH"
echo "=== Notarization complete ==="
GitHub Actions Integration
name: Build and Notarize
on:
push:
tags: ['v*']
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Import signing certificate
env:
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
run: |
CERTIFICATE_PATH=$RUNNER_TEMP/certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
echo -n "$CERTIFICATE_BASE64" | base64 --decode > $CERTIFICATE_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Build app
run: |
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
-configuration Release \
-archivePath build/MyApp.xcarchive \
archive
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/
- name: Store notarization credentials
env:
API_KEY: ${{ secrets.NOTARIZATION_API_KEY }}
API_KEY_ID: ${{ secrets.NOTARIZATION_API_KEY_ID }}
API_ISSUER: ${{ secrets.NOTARIZATION_API_ISSUER }}
run: |
mkdir -p ~/private_keys
echo -n "$API_KEY" > ~/private_keys/AuthKey.p8
xcrun notarytool store-credentials "CI_PROFILE" \
--key ~/private_keys/AuthKey.p8 \
--key-id "$API_KEY_ID" \
--issuer "$API_ISSUER"
- name: Notarize app
run: |
xcrun notarytool submit build/MyApp.app \
--keychain-profile "CI_PROFILE" \
--wait
xcrun stapler staple build/MyApp.app
- name: Create DMG
run: |
create-dmg build/MyApp.app build/
xcrun notarytool submit build/*.dmg \
--keychain-profile "CI_PROFILE" \
--wait
xcrun stapler staple build/*.dmg
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: MyApp
path: build/*.dmg
Common Issues
Issue: Hardened runtime not enabled
Error: The signature does not include a secure timestamp.
Fix: Sign with hardened runtime and timestamp:
codesign --force --options runtime --timestamp --sign "Developer ID" MyApp.app
Issue: Missing entitlements
Error: The executable does not have the hardened runtime enabled.
Fix: Include entitlements in signing:
codesign --force --options runtime --timestamp \
--entitlements MyApp.entitlements \
--sign "Developer ID Application: Company" MyApp.app
Issue: Unsigned nested code
Error: The signature of the binary is invalid.
Fix: Sign all nested components:
find MyApp.app -name "*.dylib" -o -name "*.framework" | \
xargs -I {} codesign --force --options runtime --timestamp --sign "Developer ID" {}
Best Practices
- Use App Store Connect API: More reliable than Apple ID
- Store credentials securely: Use keychain profiles
- Validate before submitting: codesign --verify
- Always staple: Makes offline verification possible
- Archive submission logs: For debugging
- Test on fresh Mac: Verify Gatekeeper acceptance
Related Skills
macos-entitlements-generator- Entitlements configurationmacos-codesign-workflow- Code signingcode-signing-setupprocess - Full signing workflow
Related Agents
swiftui-macos-expert- macOS developmentcode-signing-specialist- Signing expertise
Signals
- GitHub stars
- 2k
- Forks
- 112
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
macos-notarization-workflow- Source
- github.com/a5c-ai/babysitter
Related picks
Skill · tddworks
The pick for GitHub Actionsgithub-actions-docs
Skill · devantler-tech
The pick for GitHub Actionsteach
Skill · mattpocock
More in Dev toolsimplement
Skill · mattpocock
More in Dev toolsponytail
Skill · dietrichgebert
More in Dev toolscaveman
Skill · juliusbrussee
More in Dev tools