-
Notifications
You must be signed in to change notification settings - Fork 6
Signing and Notarizing
This page covers everything you need to do to produce a signed, notarized, and Gatekeeper-accepted release build of AxM Jamf Sync.
- An active Apple Developer Program membership (individual or organisation)
- Xcode 15 or later
- A Developer ID Application certificate in your keychain
- Download from developer.apple.com/account → Certificates if you don't have one
-
xcrun notarytoolcredentials (App Store Connect API key or Apple ID + app-specific password)
- Open
AxMJamfSync.xcodeproj - Select the AxMJamfSync target → Signing & Capabilities
- Set Team to your Apple Developer team
- Set Bundle Identifier — keep
com.karthikmac.axmjamfsyncor change it to match your Developer ID - Set Signing Certificate to Developer ID Application (not Development or Distribution)
- Confirm the entitlements file path is set:
AxMJamfSync/AxMJamfSync.entitlements
xcodebuild archive \
-project AxMJamfSync.xcodeproj \
-scheme AxMJamfSync \
-configuration Release \
-archivePath build/AxMJamfSync.xcarchive \
CODE_SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)"Or use Product → Archive in Xcode.
In the Organizer (Xcode → Window → Organizer), select your archive and click Distribute App:
- Choose Developer ID
- Choose Export
- Set signing to Developer ID Application
- Enable Hardened Runtime ✓ (required for notarization)
- Export to a folder — you'll get an
.appbundle
Or from the command line:
xcodebuild -exportArchive \
-archivePath build/AxMJamfSync.xcarchive \
-exportPath build/export \
-exportOptionsPlist ExportOptions.plistWhere ExportOptions.plist contains:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>manual</string>
<key>signingCertificate</key>
<string>Developer ID Application</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
</dict>
</plist>codesign --verify --deep --strict --verbose=2 build/export/AxMJamfSync.app
# Should print: AxMJamfSync.app: valid on disk
# AxMJamfSync.app: satisfies its Designated RequirementAlso check the entitlements were embedded:
codesign --display --entitlements - build/export/AxMJamfSync.appYou should see com.apple.security.app-sandbox, com.apple.security.network.client, and com.apple.security.files.user-selected.read-write.
xcrun notarytool submit build/export/AxMJamfSync.app \
--key /path/to/AuthKey_XXXXXXXXXX.p8 \
--key-id XXXXXXXXXX \
--issuer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--wait \
--output-format plistxcrun notarytool submit build/export/AxMJamfSync.app \
--apple-id your@email.com \
--password xxxx-xxxx-xxxx-xxxx \
--team-id YOUR_TEAM_ID \
--waitThe --wait flag blocks until notarization completes (usually 1–5 minutes). Remove it and use --no-wait + xcrun notarytool log <submission-id> to poll manually.
xcrun stapler staple build/export/AxMJamfSync.appStapling embeds the notarization ticket into the app bundle so Gatekeeper can verify it even without an internet connection.
Verify:
xcrun stapler validate build/export/AxMJamfSync.app
# Should print: The validate action worked!# Create a writable DMG
hdiutil create -size 50m -volname "AxM Jamf Sync" -srcfolder build/export/AxMJamfSync.app \
-ov -format UDZO build/AxMJamfSync.dmgSign the DMG too:
codesign --sign "Developer ID Application: Your Name (TEAMID)" build/AxMJamfSync.dmgNotarize the DMG (Gatekeeper checks the DMG itself before mounting):
xcrun notarytool submit build/AxMJamfSync.dmg \
--key /path/to/AuthKey_XXXXXXXXXX.p8 \
--key-id XXXXXXXXXX \
--issuer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--wait
xcrun stapler staple build/AxMJamfSync.dmgOn another Mac that has never seen this app:
spctl --assess --type exec --verbose build/export/AxMJamfSync.app
# Should print: AxMJamfSync.app: accepted
# source=Notarized Developer IDThe app's AxMJamfSync.entitlements contains exactly:
| Entitlement | Purpose |
|---|---|
com.apple.security.app-sandbox |
Required for Mac App Store and Gatekeeper trust |
com.apple.security.network.client |
Outbound connections to Apple APIs and Jamf Pro |
com.apple.security.files.user-selected.read-write |
Private key file picker + CSV export save dialog |
keychain-access-groups |
Read/write credentials in the app's Keychain group |
The app does not require any Hardened Runtime exceptions — no JIT, no unsigned memory execution, no resource access beyond what's in the entitlements. This makes notarization straightforward.
PrivacyInfo.xcprivacy is included in the bundle (already in project.pbxproj). It declares:
NSPrivacyTracking = false-
NSPrivacyCollectedDataTypes = [](no data collected) - Required Reasons APIs:
UserDefaults(CA92.1) andFileTimestamp(C617.1)
Apple's notarization pipeline scans for this file starting with Xcode 15. Without it, submission may be rejected with a privacy manifest warning.