Files
Jungfraujoch/tools/notarize_macos.sh
T
Filip LeonarskiandClaude Fable 5.1 82e5de1261
Build Packages / Create release (push) Successful in 7s
Build Packages / build:portable:macos-arm64:nocuda (push) Failing after 3m56s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 9m51s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 14m6s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 17m41s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 20m52s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m19s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 21m26s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 12m53s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 24m2s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m48s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 14m55s
Build Packages / Generate python client (push) Successful in 28s
Build Packages / Build documentation (push) Successful in 1m4s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 26m8s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 22m46s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 29m3s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 27m12s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 25m36s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 28m42s
Build Packages / Unit tests (push) Failing after 1h23m15s
Build Packages / Validation Battery (push) Successful in 33m26s
macOS: sign jfjoch_viewer and rugnux with a Developer ID and notarize them
JFJOCH_MACOS_SIGNING_IDENTITY (the certificate's SHA-1) makes the install step sign the shipped
program with hardened runtime and secure timestamp: macdeployqt's -sign-for-notarization for the
viewer bundle, a codesign INSTALL(CODE) for rugnux. tools/notarize_macos.sh then submits the cpack
artefact to Apple, waits for the verdict and staples the ticket to the .dmg; the rugnux binary
inside the .tgz is submitted as a zip, as a bare executable cannot carry a ticket. Both macOS CI
jobs resolve the identity from the runner's keychain, check for the hardened runtime and notarize
on every push, so a rejection shows up with the change that caused it.

The identity is passed as the hash, not the name: Qt's generated deploy script writes
DEPLOY_TOOL_OPTIONS unquoted, so a name with spaces splits into several macdeployqt arguments. The
notarytool profile has to live in the login keychain file (store-credentials --keychain): the
default data-protection keychain becomes unreadable once the screen locks, which an unattended
runner's does.

Verified end to end on the runner: both artefacts accepted by Apple, the stapled image and a
quarantined copy of the app and of rugnux pass Gatekeeper as Notarized Developer ID, signing and
the credential lookup work from a launchd-started process with the console locked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-14 15:01:30 +02:00

61 lines
2.9 KiB
Bash
Executable File

#!/bin/bash
# Notarize the macOS release artefacts with Apple and staple the ticket where one can be stapled.
#
# tools/notarize_macos.sh <jfjoch-viewer-*.dmg | rugnux-*.tar.gz> ...
#
# The programs inside must already carry a Developer ID signature with hardened runtime and secure
# timestamp: configure with -DJFJOCH_MACOS_SIGNING_IDENTITY=<certificate SHA-1> and let cpack produce
# the artefact (see the top-level CMakeLists.txt). The same certificate signs the .dmg here: the
# one JFJOCH_MACOS_SIGNING_IDENTITY names, else the Developer ID Application in the keychain. Needs
# notarytool credentials stored once on the machine, under the profile named by JFJOCH_NOTARY_PROFILE
# (default jfjoch-notary). On an unattended machine store them in the login keychain file: without
# --keychain they go into the data-protection keychain, which is unreadable while the screen is
# locked, and the step then fails with "No Keychain password item found".
#
# xcrun notarytool store-credentials jfjoch-notary --apple-id <apple id> --team-id <team id> \
# --keychain ~/Library/Keychains/login.keychain-db
#
# .dmg signed with the same Developer ID, submitted, the ticket stapled to the image.
# .tar.gz the rugnux binary inside is zipped and submitted; Apple then knows its hash, which is
# all Gatekeeper needs (a bare executable has nowhere to staple a ticket). The archive is
# shipped unchanged.
set -euo pipefail
profile=${JFJOCH_NOTARY_PROFILE:-jfjoch-notary}
identity=${JFJOCH_MACOS_SIGNING_IDENTITY:-$(security find-identity -v -p codesigning | sed -n 's/^ *[0-9]*) \([0-9A-F]*\) "Developer ID Application: .*/\1/p' | head -1)}
if [ -z "$identity" ]; then echo "no Developer ID Application identity in the keychain"; exit 1; fi
submit() { # submit <file>: wait for Apple's verdict, print the log on rejection
local out id status
out=$(xcrun notarytool submit "$1" --keychain-profile "$profile" --wait --output-format plist)
id=$(echo "$out" | plutil -extract id raw -)
status=$(echo "$out" | plutil -extract status raw -)
echo "notarization of $(basename "$1"): $status (submission $id)"
if [ "$status" != "Accepted" ]; then
xcrun notarytool log "$id" --keychain-profile "$profile"
exit 1
fi
}
for file in "$@"; do
case "$file" in
*.dmg)
codesign --force --timestamp --sign "$identity" "$file"
submit "$file"
xcrun stapler staple "$file"
spctl -a -t open --context context:primary-signature -v "$file"
;;
*.tar.gz|*.tgz)
tmp=$(mktemp -d)
tar xf "$file" -C "$tmp"
bin=$(find "$tmp" -name rugnux -type f)
ditto -c -k "$bin" "$tmp/rugnux.zip"
submit "$tmp/rugnux.zip"
rm -rf "$tmp"
;;
*)
echo "don't know how to notarize $file"; exit 1
;;
esac
done