This is a web service that runs on macOS and offers a REST API to notarize signed application bundles or signed DMG. You can read more about notarization on the Apple developer website.
brew install temurin17
$ ./mvnw clean package
It produces the self-contained application in /target/quarkus-app
.
You can run the application using: java -jar target/quarkus-app/quarkus-run.jar
See below for advanced startup method.
To download a release and perform verification whether the downloaded artifact has been produced by the project,
you should use the download-github-release.sh
script (supported since v1.2.0
):
$ ./download-github-release.sh -v 1.3.0
This will download the 1.3.0
release together with the provenance and perform verification (requires that the slsa-verifier tool is installe):
$ ./download-github-release.sh -v 1.3.0
REPO = eclipse-cbi/macos-notarization-service
VERSION = 1.3.0
ARTIFACT = macos-notarization-service
Downloaded artifact 'macos-notarization-service-1.3.0.zip'
Downloaded provenance 'macos-notarization-service-1.3.0-attestation.intoto.build.slsa'
Verifying artifact 'macos-notarization-service-1.3.0.zip' using provenance 'macos-notarization-service-1.3.0-attestation.intoto.build.slsa':
Verified build using builder "https://github.com/jreleaser/release-action/.github/workflows/builder_slsa3.yml@refs/tags/v1.1.0-java" at commit 5325c11c611568f5e043d934185183783f228c0a
Verifying artifact macos-notarization-service-1.3.0.zip: PASSED
PASSED: Verified SLSA provenance
Configure NOTARIZATION_APPLEID_USERNAME
, NOTARIZATION_APPLEID_PASSWORD
and NOTARIZATION_APPLEID_TEAMID
with the proper values for your Apple developer ID account in file start.sh
. Then, just run
./start.sh
On production system, it is advised to run this service as a system daemon with launchd
. The service will then be started automatically at boot time or if the program crash. You can find a sample file to edit and put in /Library/LaunchDaemons
in src/main/launchd/org.eclipse.cbi.macos-notarization-service.plist. To load (or unload) the service, just do
sudo launchctl load -w /Library/LaunchDaemons/org.eclipse.cbi.macos-notarization-service.plist
or
sudo launchctl unload -w /Library/LaunchDaemons/org.eclipse.cbi.macos-notarization-service.plist
See Apple documentation about daemons and agents for more options.
The service is Quarkus application exposing a simple REST API with 3 endpoints. See Quarkus documentation for all of its configuration options.
The following script calls the 3 endpoints successively to notarize a signed DMG file. It assumes that jq
is installed on the system running the script. The notarization service is expected to run on IP 10.0.0.1
on port 8383
.
DMG="/path/to/myApp.dmg"
RESPONSE=\
$(curl -s -X POST \
-F file=@${DMG} \
-F 'options={"primaryBundleId": "my-primary-bundle-id", "staple": true};type=application/json' \
http://10.0.0.1:8383/macos-notarization-service/notarize)
UUID=$(echo ${RESPONSE} | jq -r '.uuid')
STATUS=$(echo ${RESPONSE} | jq -r '.notarizationStatus.status')
while [[ ${STATUS} == 'IN_PROGRESS' ]]; do
sleep 1m
RESPONSE=$(curl -s http://10.0.0.1:8383/macos-notarization-service/${UUID}/status)
STATUS=$(echo ${RESPONSE} | jq -r '.notarizationStatus.status')
done
if [[ ${STATUS} != 'COMPLETE' ]]; then
echo "Notarization failed: ${RESPONSE}"
exit 1
fi
mv "${DMG}" "unnotarized-${DMG}"
curl -JO http://10.0.0.1:8383/macos-notarization-service/${UUID}/download
We first upload our DMG to the service endpoint macos-notarization-service/notarize
in a form part named file
along with a set of options in JSON format in a form part named options
. Only two options are available for now:
- primaryBundleId (required): the primary bundle ID that will be sent to the notarization service by
xcrun altool
. The value you give doesn’t need to match the bundle identifier of the submitted app or have any particular value. It only needs to make sense to you. See Apple documentation for more information. - staple: a boolean to specify wether or not the notarization ticket should be stapled to the notarized binary at the end of the process. Default is false. We advise you always set it to
true
. This ensures that Gatekeeper can find the notarization ticket even when a network connection isn’t available.
Once the upload to the notarization is complete, you will receive (the $RESPONSE
variable in the script above) a JSON file with a content similar to
{
"uuid":"e68713e3-2ee7-4ebd-8672-20949a9ecdb9",
"notarizationStatus": {
"status":"IN_PROGRESS",
"message":"Uploading' file to Apple notarization 'service"
}
}
The uuid
field is very important as it will be the one that will let you poll the service to know the status of the notarization process for your file and to download the results in the end. The notarizationStatus
object contains the current status.
The $STATUS
will change from ÌN_PROGRESS
to either COMPLETE
or ERROR
depending on the outcome of the process. Here the script polls the service every minute to check if the process is done via the second endpoint macos-notarization-service/$UUID/status
.
Once the process is done, you can download the notarized DMG with the endpoint macos-notarization-service/${UUID}/download
. Note that this is unnecessary if you did not asked for the notarization ticket to be stapled to the binary to be notarized. Indeed, the notarization itself is side effect free for binaries if you don't staple the ticket.
- Eclipse® is a Trademark of the Eclipse Foundation, Inc.
- Eclipse Foundation is a Trademark of the Eclipse Foundation, Inc.
Copyright 2019 the Eclipse Foundation, Inc. and others. Code released under the Eclipse Public License Version 2.0 (EPL-2.0).
SPDX-License-Identifier: EPL-2.0