Notarizing and Stapling with rcodesign

Submit Notarizations with notary-submit

You can notarize a signed asset via rcodesign notary-submit.

Notarization requires an App Store Connect API Key. See Obtaining an App Store Connect API Key for instructions on how to obtain one.

Assuming you used rcodesign encode-app-store-connect-api-key to produce a JSON file with all the API Key information, simply specify --api-key-file to define the path to this JSON file.

To notarize an already signed asset:

rcodesign notary-submit \
  --api-key-file ~/.appstoreconnect/key.json \
  path/to/file/to/notarize

By default notarize-submit just uploads the asset to Apple. To wait on its notarization result, add --wait:

rcodesign notary-submit \
  --api-key-file ~/.appstoreconnect/key.json \
  --wait \
  path/to/file/to/notarize

Or to wait and automatically staple the file if notarization was successful:

rcodesign notary-submit \
  --api-key-file ~/.appstoreconnect/key.json \
  --staple \
  path/to/file/to/notarize

Stapling With staple

If an asset was already notarized, you can attempt to staple (read: attach) the notarization ticket to that entity via the staple command:

rcodesign staple path/to/file/to/staple

Tip

It is possible to staple any asset, not just those notarized by you.

Checking on Submitted Notarizations

Notarization is an asynchronous process: you first submit an asset to Apple then you wait for an indefinite amount of time (often a few dozen seconds) for Apple’s servers to scan the asset and issue a notarization ticket.

If a notarization operation is interrupted or if you want to check on its status, there are a few support commands to query Apple’s servers.

notary-list will list the most recent submitted notarization requests. This command will print a list of submission IDs, dates, and a brief status of each one.:

rcodesign notary-list --api-key-file ~/.appstoreconnect/key.json

notary-wait can be used to wait on a previously submitted notarization request to finish:

rcodesign notary-wait \
  --api-key-file ~/.appstoreconnect/key.json \
  <submission ID>

Here, <submission ID> is an identifier issued by Apple and printed when running rcodesign notary-list or rcodesign notary-submit.

notary-log can be used to retrieve the notarization log for a submission identifier:

rcodesign notary-log \
  --api-key-file ~/.appstoreconnect/key.json \
  <submission ID>

Common Notarization Problems

Notarization can fail for a myriad of reasons. On software that hasn’t been successfully notarized before and on untested release pipeline, notarization failures before success are somewhat expected.

Apple’s requirements for notarization are enumerated at Notarizing macOS software before distribution.

The sections below document common notarization failures and how to mitigate them. They somewhat mirror Apple’s official guidance at Resolving common notarization issues, which we highly recommend you read before this documentation.

Using sign –for-notarization

The rcodesign sign command has a --for-notarization argument that attempts to engage Apple notarization compatibility mode.

When this flag is used:

  • The signing configuration is validated for notarization compatibility.

  • Signing settings are automatically changed to help ensure notarization compatibility.

This flag is best effort. If you encounter notarization failures when using this flag that you think could be automatically detected or prevented, please consider filing a bug report.

Usage example:

rcodesign sign \
  --for-notarization \
  --pem-source developer-id-application.pem \
  MyApp.app

Notarize with Apple Tooling First

For applications that haven’t been notarized before or when debugging issues with notarization, we highly recommend using Apple’s official tooling and workflows for notarizing from a macOS machine before attempting to debug notarization with rcodesign.

This is because notarization and its errors can be challenging to work through. Having an existence proof that a piece of software can be notarized with Apple’s tooling proves that software is capable of passing notarization. It means that failures in rcodesign notarization are due to invoking rcodesign incorrectly or due to a bug in rcodesign.

We highly recommend reading Apple’s notarization documentation (linked above) when debugging notarization failures.

Hardened Runtime Not Enabled

The hardened runtime needs to be enabled to pass notarization. If you don’t have the hardened runtime enabled, notarization has been known to fail with the error: The executable does not have the hardened runtime enabled.

To enable the hardened runtime with rcodesign sign, the runtime code signature flag must be enabled via the --code-signature-flags argument. e.g.:

rcodesign sign \
   --code-signature-flags runtime \
   MyApp.app

--code-signature-flags only applies to the _main_ entity being signed by default. If you are signing an application bundle with multiple binaries, for example, you will need to use the _scoped_ syntax to --code-signature-flags to specify code signature flags for each additional path being signed. e.g.:

rcodesign sign \
  --code-signature-flags runtime \
  --code-signature-flags Contents/MacOS/additional-binary:runtime \
  MyApp.app

For complex bundles consisting of several binaries or nested bundles, this can grow quite cumbersome and it is easy to forget to annotate a binary, especially if new files appear in the bundles. For complex signing scenarios, we recommend using configuration files to define the signing settings.

Incorrect Signing Certificate

Another common notarization problem is not signing with an Apple issued signing certificate or not using the appropriate certificate for signing a particular entity.

See Apple’s Use a valid Developer ID certificate for more.