Skip to content

Instantly share code, notes, and snippets.

@rdelrosario
Last active January 12, 2024 19:40
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rdelrosario/9e0f4e79a468082424b5bd4714c34fb0 to your computer and use it in GitHub Desktop.
Save rdelrosario/9e0f4e79a468082424b5bd4714c34fb0 to your computer and use it in GitHub Desktop.
macOS Application Notarization Script
#!/bin/bash
usage()
{
# Display Help
echo "*********************************************************************************************************************************************************"
echo " MacOS Application Notarization Script"
echo "*********************************************************************************************************************************************************"
echo
echo " Requirements"
echo " - XCode Installed"
echo " - Apple Id Account app-specific Password (https://support.apple.com/en-us/HT204397)"
echo " - Apple Developer ID Application Certificate created and installed in keychain (https://developer.apple.com/support/developer-id/)"
echo
echo " Instructions"
echo " 1. Run notarize option to code sign application and create notarization request"
echo " 2. Run check option with the request UUID of the previous step to check the notarization status"
echo " 3. Run staple option only if the notarization status was successful and package was approved"
echo " 4. You are now ready to distribute, if you want to create an installer you can use this option https://github.com/sindresorhus/create-dmg."
echo " Note that if you distribute your app in a .dmg, follow these steps:"
echo
echo " - Add your notarized and stapled app to the DMG."
echo " - Notarize your .dmg file."
echo " Example: sh $0 --notarize -a MyApp.dmg -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF)"
echo " - Staple the notarization to the .dmg file: xcrun stapler staple MyApp.dmg."
echo " Example: sh $0 --staple --file MyApp.dmg"
echo "________________________________________________________________________________________________________________________________________________________"
echo
echo " Usage"
echo " $0 [-n|s|c] [ -a APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ] [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ] [ -k UUID ]"
echo
echo "________________________________________________________________________________________________________________________________________________________"
echo
echo " Options:"
echo
notarizeHelp
checkHelp
stapleHelp
return
}
notarizeHelp()
{
echo " ======================================================================="
echo " -n | --notarize Notarize file"
echo " ======================================================================="
echo " Syntax:"
echo " [ -n | --notarize ] [ -a | --file APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ] [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ]"
echo " Parameters:"
echo " [ -a | --file ] - File name"
echo " [ -i ] - Apple Signing identity"
echo " [ -e ] - Application entitlements file"
echo " [ -b ] - Application Bundle identifier"
echo " [ -u ] - Apple Developer ID Username"
echo " [ -p ] - Application Specific password"
echo " [ -v ] - Access Provider"
echo " Example:"
echo " .app sh $0 --notarize -a MyApp.app -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF -e App.entitlements -i \"Developer ID Application: COMPANY\""
echo " .zip sh $0 --notarize -a MyApp.app.zip -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
echo " .dmg sh $0 --notarize -a MyApp.dmg -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
echo
}
checkHelp()
{
echo " ======================================================================="
echo " -c | --check Check notarization status"
echo " ======================================================================="
echo " Syntax:"
echo " [ -c | --check ] [ -u USERNAME ] [ -p PASSWORD ] [ -k UUID ]"
echo " Parameters:"
echo " [ -u ] - Apple Developer ID Username"
echo " [ -p ] - Application Specific password"
echo " [ -k ] - Notarization Request UUID"
echo " Example:"
echo " sh $0 --check -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -k ffff-ffffff-ffffff-ffffffffff"
echo
}
stapleHelp()
{
echo " ======================================================================="
echo " -s | --staple Staple file"
echo " ======================================================================="
echo " Syntax:"
echo " [ -s | --staple ] [ -a | --file APP_NAME ]"
echo " Parameters:"
echo " [ -a | --file ] - File name"
echo " Example:"
echo " sh $0 --staple --file MyApp.app"
echo
}
#Help Dictionary
helpFunction()
{
echo ""
usage
exit 1
}
# Transform long options to short ones
for arg in "$@"; do
shift
case "$arg" in
"--notarize") set -- "$@" "-n" ;;
"--staple") set -- "$@" "-s" ;;
"--check") set -- "$@" "-c" ;;
"--file") set -- "$@" "-a" ;;
*) set -- "$@" "$arg"
esac
done
while getopts "nsca:i:e:b:v:u:k:p:" option
do
case "${option}"
in
n) ACTION=NOTARIZE;;
s) ACTION=STAPLE;;
c) ACTION=CHECK;;
a) APP_NAME=${OPTARG};;
i) SIGNING_IDENTITY=${OPTARG};;
e) ENTITLEMENTS=${OPTARG};;
b) BUNDLE_ID=${OPTARG};;
p) PASSWORD=${OPTARG};;
v) PROVIDER=${OPTARG};;
u) USERNAME=${OPTARG};;
k) UUID=${OPTARG};;
?) helpFunction ;;
esac
done
do_check()
{
echo "$UUID"
if [ -z "${UUID}" ]; then
echo "[Error] Didn't specify notarization request UUID";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${UUID}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then
echo
checkHelp
exit 1
fi
echo "[INFO] Checking Notarization status for $UUID"
xcrun altool --notarization-info "$UUID" -u "$USERNAME" -p "$PASSWORD" --output-format xml
exit 1
}
sign()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
fi
if [ -z "${SIGNING_IDENTITY}" ]; then
echo "[Error] Didn't specify signing identity";
fi
if [ -z "${ENTITLEMENTS}" ]; then
echo "[Error] Didn't specify entitlements file";
fi
if [ -z "${BUNDLE_ID}" ]; then
echo "[Error] Didn't specify bundle identifier";
fi
if [ -z "${PROVIDER}" ]; then
echo "[Error] Didn't specify access provider";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ] || [ -z "${ENTITLEMENTS}" ] || [ -z "${SIGNING_IDENTITY}" ]; then
echo
notarizeHelp
exit 1
fi
echo "[INFO] Signing app contents"
find "$APP_NAME/Contents"|while read fname; do
if [[ -f $fname ]]; then
echo "[INFO] Signing $fname"
codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" $fname
fi
done
echo "[INFO] Signing app file"
codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$APP_NAME"
echo "[INFO] Verifying Code Sign"
codesign --verify --verbose "$APP_NAME"
echo "[INFO] Zipping $APP_NAME to ${APP_NAME}.zip"
ditto -c -k --rsrc --keepParent "$APP_NAME" "${APP_NAME}.zip"
#echo "[INFO] Uploading $APP_NAME for notarization"
#xcrun altool --notarize-app -t osx -f "${APP_NAME}.zip" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER" --output-format xml
notarizationUpload "${APP_NAME}.zip"
}
notarize()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
fi
if [ -z "${BUNDLE_ID}" ]; then
echo "[Error] Didn't specify bundle identifier";
fi
if [ -z "${PROVIDER}" ]; then
echo "[Error] Didn't specify access provider";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${BUNDLE_ID}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ]; then
echo
notarizeHelp
exit 1
fi
case "$APP_NAME" in
*.app) sign;;
*.zip) notarizationUpload "$APP_NAME";;
*.dmg) notarizationUpload "$APP_NAME";;
esac
}
notarizationUpload()
{
echo "[INFO] Uploading $APP_NAME for notarization"
xcrun altool --notarize-app -t osx -f "$1" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER" --output-format xml
}
do_staple()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
echo
stapleHelp
exit 1
fi
echo "[INFO] Stapling $APP_NAME"
xcrun stapler staple "$APP_NAME"
echo "[INFO] Validating Staple for $APP_NAME"
xcrun stapler validate "$APP_NAME"
}
#Excute Action base on the option -s -n -c
case $ACTION in
STAPLE) do_staple;;
CHECK) do_check;;
NOTARIZE) notarize;;
*) helpFunction;
esac
unset APP_NAME ACTION SIGNING_IDENTITY BUNDLE_ID ENTITLEMENTS USERNAME PASSWORD PROVIDER UUID
@theRealGupta
Copy link

How to use this with pkg?

@fsol11
Copy link

fsol11 commented Oct 8, 2020

How to use this with pkg?

Look at this page:

https://www.xamboy.com/2020/05/28/net-core-application-macos-packaging-and-notarization/

search for app_notarizer.sh

@JRC-BitBull
Copy link

Sorry for being thick, but what is 'Access Provider' as referenced above? Is it the code referred to as 'Organizational Unit' on the signing cert? When I run the script it seems to go through every stage with no errors but nothing happens.

@vHanda
Copy link

vHanda commented Aug 25, 2021

Sorry for being thick, but what is 'Access Provider' as referenced above? Is it the code referred to as 'Organizational Unit' on the signing cert? When I run the script it seems to go through every stage with no errors but nothing happens.

The access provider can be fetched via this command - xcrun altool --list-providers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment