Notarizing Automator applications
Apple recently updated their notarization documentation to include this note:
Beginning in macOS 10.14.5, all new or updated kernel extensions and all software from developers new to distributing with Developer ID must be notarized in order to run. In a future version of macOS, notarization will be required by default for all software.
The part about “notarization will be required by default for all software” made me think, because there are a few apps that I’ve written over the years that are still useful (at least to me). All of them were built using Automator, which meant that the usual Xcode-based ways of notarizing applications wasn’t going to work for me.
With assistance by folks in the MacAdmins Slack though, I was able to develop a process that allowed me to do the following:
- Codesign an Automator application
- Upload the application to Apple for notarization
- Attach the notarization to the application
- Verify that the notarization was attached and valid.
The documentation linked below was also very helpful in figuring out how to notarize using command line tools:
- https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution/customizing_the_notarization_workflow
- https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution
For more details, please see below the jump.
Pre-requisites
For notarization, you need the following things:
- Xcode 10 or later installed on your Mac.
- An Apple Developer Connection account
- A one-time password for your ADC account’s Apple ID
As an example to use for the process, I’m using an existing Automator application that I wrote a while back:
Notarization requires that the application in question be code signed and I had not yet done so for this application, so I needed to code sign my application first.
To do this, first clear the application of extended attributes by running a command like the one below:
sudo xattr -rc "/path/to/Application Name Here.app"
In my case, the command looked like this:
sudo xattr -rc "/Users/username/Desktop/Payload-Free Package Creator.app"
Once the application is ready for signing, run a command like the one below was run to code sign the application:
codesign --force --options runtime --deep --sign "Developer ID Application: Name Here (YG45FDT45F)" "/path/to/Application Name Here.app"
In my case, the command looked like this:
codesign --force --options runtime --deep --sign "Developer ID Application: Rich Trouton (XF95CST45F)" "/Users/username/Desktop/Payload-Free Package Creator.app"
Once signed, verify the signature using a command like the one below:
codesign -dv --verbose=4 "/path/to/Application Name Here.app"
In my case, the command looked like this:
codesign -dv --verbose=4 "/Users/username/Desktop/Payload-Free Package Creator.app"
Once finished, the output of the code signing looked like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computername:~ username$ sudo xattr -rc "/Users/username/Desktop/Payload-Free Package Creator.app" | |
Password: | |
computername:~ username$ codesign –force –options runtime –deep –sign "Developer ID Application: Rich Trouton (XF95CST45F)" "/Users/username/Desktop/Payload-Free Package Creator.app" | |
computername:~ username$ codesign -dv –verbose=4 "/Users/username/Desktop/Payload-Free Package Creator.app" | |
Executable=/Users/username/Desktop/Payload-Free Package Creator.app/Contents/MacOS/Application Stub | |
Identifier=com.apple.automator.Payload-FreePackageCreator | |
Format=app bundle with Mach-O thin (x86_64) | |
CodeDirectory v=20500 size=378 flags=0x10000(runtime) hashes=4+3 location=embedded | |
VersionPlatform=1 | |
VersionMin=657920 | |
VersionSDK=657920 | |
Hash type=sha256 size=32 | |
CandidateCDHash sha1=e8e508b4a9f6afe4ca74aa1e721978d43e812a06 | |
CandidateCDHash sha256=a410264a896780b689a326d73968eb361892702c | |
Hash choices=sha1,sha256 | |
Page size=4096 | |
CDHash=a410264a896780b689a326d73968eb361892702c | |
Signature size=9054 | |
Authority=Developer ID Application: Rich Trouton (XF95CST45F) | |
Authority=Developer ID Certification Authority | |
Authority=Apple Root CA | |
Timestamp=Apr 10, 2019 at 2:23:36 PM | |
Info.plist entries=31 | |
TeamIdentifier=XF95CST45F | |
Runtime Version=10.10.0 | |
Sealed Resources version=2 rules=13 files=36 | |
Internal requirements count=1 size=208 | |
computername:~ username$ |
The next thing needed is to get the app ready for upload to Apple for notarization. For this, you’ll need to do two things:
- Have your one-time password for your ADC account ready.
- Compress your application inside of a .zip file
Once your application has been compressed, run a command similar to the one below to upload it to Apple for notarization:
xcrun altool --notarize-app --primary-bundle-id "com.example.application.name" --username "adc_appleid_here" --password "adc_appleid_one_time_password_here" --file "/path/to/Application Name Here.zip"
In my case, the command looked like this:
xcrun altool --notarize-app --primary-bundle-id "com.apple.automator.Payload-FreePackageCreator" --username "adc_appleid_here" --password "one-time-password-goes-here" --file "/Users/username/Desktop/Payload-Free Package Creator.zip"
Once finished, the output of the notarization upload looked like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computername:~ username$ xcrun altool –notarize-app –primary-bundle-id "com.apple.automator.Payload-FreePackageCreator" –username "adc_appleid_here" –password "one-time-password-goes-here" –file "/Users/username/Desktop/Payload-Free Package Creator.zip" | |
2019-04-10 14:26:08.435 altool[39198:348433] No errors uploading '/Users/username/Desktop/Payload-Free Package Creator.zip'. | |
RequestUUID = be136ed3-3888-44e1-87ed-0e5c8c13cdb5 | |
computername:~ username$ |
To validate that the notarization is successful, run a command similar to the one below:
xcrun altool --notarization-info uuid-goes-here --username "adc_appleid_here" --password "one-time-password-goes-here"
In my case, the command looked like this:
xcrun altool --notarization-info be136ed3-3888-44e1-87ed-0e5c8c13cdb5 --username "adc_appleid_here" --password "one-time-password-goes-here"
Once finished, the output of the notarization validation looked like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computername:~ username$ xcrun altool –notarization-info be136ed3-3888-44e1-87ed-0e5c8c13cdb5 –username "adc_appleid_here" –password "one-time-password-goes-here" | |
2019-04-10 14:29:20.894 altool[39296:353688] No errors getting notarization info. | |
RequestUUID: be136ed3-3888-44e1-87ed-0e5c8c13cdb5 | |
Date: 2019-04-10 18:26:09 +0000 | |
Status: success | |
LogFileURL: https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma123/v4/a8/6f/a7/a86fa770-d553-1597-3e1d-48bb9c4f5f2e/developer_log.json?accessKey=1555115360_2635583872253219967_IJVPxumx10OG%2Bvds%2Biwi%2FcbwW1Yy4qvaLM7BGo4gxyiVHlt35YPsgh09cgGH%2F7UA9vF6duU7reRWq4TcoqxgBYS2Uwbock7TVnaD1%2BnR3LUxo1E5aQcQfhIW4bxt6S4aSEj22PbuucT0oTyGPLKiuV%2FoYO%2FT1TlHtETnCaJk9nc%3D | |
Status Code: 0 | |
Status Message: Package Approved | |
computername:~ username$ |
As part of the validation, a link to a log file is included. In my case, the log looks like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"logFormatVersion": 1, | |
"jobId": "be136ed3-3888-44e1-87ed-0e5c8c13cdb5", | |
"status": "Accepted", | |
"statusSummary": "Ready for distribution", | |
"statusCode": 0, | |
"archiveFilename": "Payload-Free_Package_Creator.zip", | |
"uploadDate": "2019-04-10T18:26:09Z", | |
"sha256": "bc3ac8c1cf7e70de274025f92078159392d654f030bb32375b3fed83b9af8e3e", | |
"ticketContents": [ | |
{ | |
"path": "Payload-Free_Package_Creator.zip/Payload-Free Package Creator.app/Contents/document.wflow", | |
"digestAlgorithm": "SHA-256", | |
"cdhash": "4634e03994cd0851f26a6f8cd6470a95b9696fe5", | |
"arch": "i386" | |
}, | |
{ | |
"path": "Payload-Free_Package_Creator.zip/Payload-Free Package Creator.app/Contents/document.wflow", | |
"digestAlgorithm": "SHA-256", | |
"cdhash": "4634e03994cd0851f26a6f8cd6470a95b9696fe5", | |
"arch": "x86_64" | |
}, | |
{ | |
"path": "Payload-Free_Package_Creator.zip/Payload-Free Package Creator.app/Contents/document.wflow", | |
"digestAlgorithm": "SHA-256", | |
"cdhash": "4634e03994cd0851f26a6f8cd6470a95b9696fe5", | |
"arch": "x86_64h" | |
}, | |
{ | |
"path": "Payload-Free_Package_Creator.zip/Payload-Free Package Creator.app", | |
"digestAlgorithm": "SHA-256", | |
"cdhash": "a410264a896780b689a326d73968eb361892702c", | |
"arch": "x86_64" | |
}, | |
{ | |
"path": "Payload-Free_Package_Creator.zip/Payload-Free Package Creator.app/Contents/MacOS/Application Stub", | |
"digestAlgorithm": "SHA-256", | |
"cdhash": "a410264a896780b689a326d73968eb361892702c", | |
"arch": "x86_64" | |
} | |
], | |
"issues": null | |
} |
Once the notarization has been generated for the app, the next step is to attach, or staple, the notarization to the app. To do this, run a command similar to the one below on your codesigned app:
xcrun stapler staple "/path/to/Application Name Here.app"
In my case, the command looked like this:
xcrun stapler staple "/Users/username/Desktop/Payload-Free Package Creator.app"
Once finished, the output of the stapling process looked like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computername:~ username$ xcrun stapler staple "/Users/username/Desktop/Payload-Free Package Creator.app" | |
Processing: /Users/username/Desktop/Payload-Free Package Creator.app | |
Processing: /Users/username/Desktop/Payload-Free Package Creator.app | |
The staple and validate action worked! | |
computername:~ username$ |
The final step is to validate that the stapling was successful. To do this, run a command similar to the one below:
stapler validate -v "/path/to/Application Name Here.app"
In my case, the command looked like this:
stapler validate -v "/Users/username/Desktop/Payload-Free Package Creator.app"
Once finished, the output of the stapling validation looked like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
computername:~ username$ stapler validate -v "/Users/username/Desktop/Payload-Free Package Creator.app" | |
Processing: /Users/username/Desktop/Payload-Free Package Creator.app | |
Properties are { | |
NSURLIsDirectoryKey = 1; | |
NSURLIsPackageKey = 1; | |
NSURLIsSymbolicLinkKey = 0; | |
NSURLLocalizedTypeDescriptionKey = Application; | |
NSURLTypeIdentifierKey = "com.apple.application-bundle"; | |
"_NSURLIsApplicationKey" = 1; | |
} | |
Props are { | |
cdhash = <a410264a 896780b6 89a326d7 3968eb36 1892702c>; | |
digestAlgorithm = 2; | |
flags = 65536; | |
secureTimestamp = "2019-04-10 18:23:36 +0000"; | |
signingId = "com.apple.automator.Payload-FreePackageCreator"; | |
teamId = XF95CST45F; | |
} | |
JSON Data is { | |
records = ( | |
{ | |
recordName = "2/2/a410264a896780b689a326d73968eb361892702c"; | |
} | |
); | |
} | |
Headers: { | |
"Content-Type" = "application/json"; | |
} | |
Domain is api.apple-cloudkit.com | |
Response is <NSHTTPURLResponse: 0x7fbe9de29840> { URL: https://api.apple-cloudkit.com/database/1/com.apple.gk.ticket-delivery/production/public/records/lookup } { Status Code: 200, Headers { | |
"Apple-Originating-System" = ( | |
UnknownOriginatingSystem | |
); | |
Connection = ( | |
"keep-alive" | |
); | |
"Content-Encoding" = ( | |
gzip | |
); | |
"Content-Type" = ( | |
"application/json; charset=UTF-8" | |
); | |
Date = ( | |
"Wed, 10 Apr 2019 18:33:04 GMT" | |
); | |
Server = ( | |
"AppleHttpServer/70a91026" | |
); | |
"Strict-Transport-Security" = ( | |
"max-age=31536000; includeSubDomains;" | |
); | |
"Transfer-Encoding" = ( | |
Identity | |
); | |
Via = ( | |
"xrail:st11p00ic-qugw02260301.me.com:8301:18H140:grp60", | |
"icloudedge:fr02p01ic-ztde010902:7401:19RC85:Frankfurt" | |
); | |
"X-Apple-CloudKit-Version" = ( | |
"1.0" | |
); | |
"X-Apple-Request-UUID" = ( | |
"79e314c2-7be3-4715-b880-73e4a5e9b5a4" | |
); | |
"X-Responding-Instance" = ( | |
"ckdatabasews:16303401:st42p63ic-ztfb17170801:8201:1905B392:a7f3f78fb52" | |
); | |
"access-control-expose-headers" = ( | |
"X-Apple-Request-UUID, X-Responding-Instance", | |
Via | |
); | |
"apple-seq" = ( | |
0 | |
); | |
"apple-tk" = ( | |
false | |
); | |
} } | |
Size of data is 2845 | |
JSON Response is: { | |
records = ( | |
{ | |
created = { | |
deviceID = 2; | |
timestamp = 1554920826358; | |
userRecordName = "_d28c74d190a3782e89496b0a13437fef"; | |
}; | |
deleted = 0; | |
fields = { | |
signedTicket = { | |
type = BYTES; | |
value = "czhjaAEAAADwBQAAQgAAADCCBewwggL+MIICpKADAgECAggcrXLgBzKYBDAKBggqhkjOPQQDAjByMSYwJAYDVQQDDB1BcHBsZSBTeXN0ZW0gSW50ZWdyYXRpb24gQ0EgNDEmMCQGA1UECwwdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMB4XDTE4MDUwMzA1MjI1N1oXDTE5MDYwMjA1MjI1N1owRDEgMB4GA1UEAwwXU29mdHdhcmUgVGlja2V0IFNpZ25pbmcxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJbqyhMrgDDTnHBoZheGp0mypFXTwAUJKmXKQamgz95BKOEzvSlkeBxp1oI7mMSewrQLbOjztegUxnaB4RAtOAqOCAVAwggFMMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUeke6OIoVJEgiRs2+jxokezQDKmkwQQYIKwYBBQUHAQEENTAzMDEGCCsGAQUFBzABhiVodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLWFzaWNhNDAyMIGWBgNVHSAEgY4wgYswgYgGCSqGSIb3Y2QFATB7MHkGCCsGAQUFBwICMG0Ma1RoaXMgY2VydGlmaWNhdGUgaXMgdG8gYmUgdXNlZCBleGNsdXNpdmVseSBmb3IgZnVuY3Rpb25zIGludGVybmFsIHRvIEFwcGxlIFByb2R1Y3RzIGFuZC9vciBBcHBsZSBwcm9jZXNzZXMuMB0GA1UdDgQWBBSvkaFMaSOwRfsIVbF12z5+m2d5XjAOBgNVHQ8BAf8EBAMCB4AwEAYKKoZIhvdjZAYBHgQCBQAwCgYIKoZIzj0EAwIDSAAwRQIgWUBuPT4qbzW2paWYyyLINmhuQphzZj8ZXnNuflZB5kECIQCZBAp3F09H5C4WdMQdX3RUPL1a6udCdIi7QWtRMsiuOjCCAuYwggJtoAMCAQICCDMN7vi/TGguMAoGCCqGSM49BAMDMGcxGzAZBgNVBAMMEkFwcGxlIFJvb3QgQ0EgLSBHMzEmMCQGA1UECwwdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMB4XDTE3MDIyMjIyMjMyMloXDTMyMDIxODAwMDAwMFowcjEmMCQGA1UEAwwdQXBwbGUgU3lzdGVtIEludGVncmF0aW9uIENBIDQxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAZrpFZvfZ8n0c42jpIbVs1UNmRKyZRomfrJIH7i9VgP3OJq6xlHLy7vO6QBtAETRHxaJq2gnCkliuXmBm9PfFqjgfcwgfQwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS7sN6hWDOImqSKmd6+veuv2sskqzBGBggrBgEFBQcBAQQ6MDgwNgYIKwYBBQUHMAGGKmh0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtYXBwbGVyb290Y2FnMzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmFwcGxlLmNvbS9hcHBsZXJvb3RjYWczLmNybDAdBgNVHQ4EFgQUeke6OIoVJEgiRs2+jxokezQDKmkwDgYDVR0PAQH/BAQDAgEGMBAGCiqGSIb3Y2QGAhEEAgUAMAoGCCqGSM49BAMDA2cAMGQCMBUMqY7Gr5Zpa6ef3VzUA1lsrlLUYMaLduC3xaLxCXzgmuNrseN8McQneqeOif2rdwIwYTMg8Sn/+YcyrinIZD12e1Gk0gIvdr5gIpHx1Tp13LTixiqW/sYJ3EpP1STw/MqyZzh0awIAFAACAAAAAAAAAHo1rlwAAAAAAqQQJkqJZ4C2iaMm1zlo6zYYknAsAkY04DmUzQhR8mpvjNZHCpW5aW/lMEUCIFHz9qrAYpGzyJpxp1VP9PjaVbdyeO4rfWRLOi/6qRVDAiEAiS1WtdN4wNAtcdZXadXtOttKgafNKpKQgQCXIuxGrSQA"; | |
}; | |
}; | |
modified = { | |
deviceID = 2; | |
timestamp = 1554920826358; | |
userRecordName = "_d28c74d190a3782e89496b0a13437fef"; | |
}; | |
pluginFields = { | |
}; | |
recordChangeTag = jubjpo8f; | |
recordName = "2/2/a410264a896780b689a326d73968eb361892702c"; | |
recordType = DeveloperIDTicket; | |
} | |
); | |
} | |
Downloaded ticket has been stored at file:///var/folders/74/mp0fvtls5kn9b8yzzwr98y400000gn/T/79e314c2-7be3-4715-b880-73e4a5e9b5a4.ticket. | |
The validate action worked! | |
computername:~ username$ |
Following notarization, Apple should send you a notification similar to the one shown below that your app has been notarized.
Great Instructions Rich!
When I try to notarize an AppleScript app the code signing and the notarization succeed as you say but when I get to the stapling step the response I get to:
xcrun stapler staple “/Volumes/HardDrive/MyApp.app”
is:
CloudKit query for MyApp.app (2/936578f9cf6dff6314bdebeba427cac9dab3f7e8) failed due to “record not found”.
Could not find base64 encoded ticket in response for 2/936578f9cf6dff6314bdebeba427cac9dab3f7e8
The staple and validate action failed! Error 65.
You might check out this thread: . It involves an extra step of creating an entitlements file. In the example case, it’s just entitlements to send Apple events and load external frameworks.
“You might check out this thread” I guess the link disappeared? What extra step is it?
It looks like the link has been eaten — it’s a thread on Apple’s Developer Forums. Things have moved on a bit, and now the easiest way is to use SD Notary from the makers of Script Debugger. (Disclaimer: I’m one of the authors.)
Instead of creating a .zip, I created a .dmg and then signed it (without hardening)
I used the signed .dmg to upload for notarization and was then able to staple the successful notarization to the .dmg.
So maybe that is the way to deal with AppleScript apps.
macOS is slowly becoming iOS! Sad days ahead!
Hello, I want to ask, what is the difference between ADC and normal Developer ID? Thanks
do you have an automated terminal script for this process?
thank you so much for putting this together and documenting it so well.
Amazing. Thank you so much for this guide! Very helpful.
Keep in mind that you can’t create “App-specific passwords” using a “Managed” Apple ID. This only works with “unmanaged” Apple IDs.
Very clear, thank you so much. In my case, since my Apple ID is associated with multiple teams, in the notarization step I had to add the flag –asc-provider to specify the *shortname* for the team. This shortname can be found with xcrun altool –list-providers and the username and one-time password mentioned in the instructions.