Files
horizon-airdef/packaging/macos/package.sh
T
Ludovic Marie 3ffbb1cb9f Sign and notarize the macOS builds with Developer ID
With the repository variable MACOS_SIGN_IDENTITY set, the launcher's Horizon.app and .dmg and the
game's three programs are signed with the hardened runtime and a timestamp, notarized and (app,
dmg) stapled, from a keychain of the Mac mini's own that keychain.sh unlocks with its password from
1Password. Unset, everything is signed ad hoc as before. The launcher checks an updated bundle's
signature before and after swapping it in, and puts the old one back when it doesn't hold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 12:20:34 +02:00

78 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Packages the macOS launcher: Horizon.app (the binary, Info.plist, the icon), signed, then the
# two release assets, horizon-launcher-macos-arm64.zip (what the launcher updates itself from;
# older launchers find the binary inside it) and horizon-launcher-macos-arm64.dmg (the installer:
# the app and an Applications link over a background, to drag one onto the other).
#
# packaging/macos/package.sh BINARY VERSION OUTDIR
#
# Needs macOS (ditto, codesign, hdiutil) and dmgbuild (pip install dmgbuild==1.6.5; $DMGBUILD
# names it if it isn't on PATH). Signing: ad hoc by default, which needs no Apple account. With
# MACOS_SIGN_IDENTITY set to a "Developer ID Application: …" identity (in $MACOS_SIGN_KEYCHAIN
# when set), the app and the .dmg are signed with the hardened runtime and a timestamp, and with
# MACOS_NOTARY_PROFILE too, both are notarized and stapled (keychain.sh unlock sets the two;
# see packaging/macos/README.md).
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
binary=$1
version=$2
out=$(mkdir -p "$3" && cd "$3" && pwd)
app=$out/Horizon.app
rm -rf "$app"
mkdir -p "$app/Contents/MacOS" "$app/Contents/Resources"
cp "$binary" "$app/Contents/MacOS/horizon-launcher"
chmod 755 "$app/Contents/MacOS/horizon-launcher"
cp "$here/../icons/horizon.icns" "$app/Contents/Resources/horizon.icns"
sed "s/@VERSION@/$version/g" "$here/Info.plist" > "$app/Contents/Info.plist"
printf 'APPL????' > "$app/Contents/PkgInfo"
plutil -lint "$app/Contents/Info.plist"
identity=${MACOS_SIGN_IDENTITY:--}
keychain=()
[[ -n "${MACOS_SIGN_KEYCHAIN:-}" ]] && keychain=(--keychain "$MACOS_SIGN_KEYCHAIN")
if [[ "$identity" == "-" ]]; then
codesign --force --sign - "$app"
else
codesign --force --options runtime --timestamp ${keychain[@]+"${keychain[@]}"} --sign "$identity" "$app"
fi
codesign --verify --strict --verbose=2 "$app"
# Still starts under the hardened runtime.
"$app/Contents/MacOS/horizon-launcher" --version
notarize=$([[ "$identity" != "-" && -n "${MACOS_NOTARY_PROFILE:-}" ]] && echo yes || true)
# The app first, so the zip and the .dmg both carry it stapled.
[[ -z "$notarize" ]] || "$here/notarize.sh" "$app"
rm -f "$out/horizon-launcher-macos-arm64.zip" "$out/horizon-launcher-macos-arm64.dmg"
# No resource forks or extended attributes: they would land as ._ files inside the bundle.
(cd "$out" && ditto -c -k --norsrc --noextattr --noqtn --keepParent Horizon.app horizon-launcher-macos-arm64.zip)
cat > "$out/dmg.json" <<JSON
{
"title": "Horizon",
"icon-size": 128,
"background": "$here/background.png",
"window": { "position": { "x": 200, "y": 160 }, "size": { "width": 660, "height": 420 } },
"format": "UDZO",
"contents": [
{ "x": 180, "y": 200, "type": "file", "path": "$app" },
{ "x": 480, "y": 200, "type": "link", "path": "/Applications" }
]
}
JSON
"${DMGBUILD:-dmgbuild}" -s "$out/dmg.json" Horizon "$out/horizon-launcher-macos-arm64.dmg"
rm "$out/dmg.json"
dmg=$out/horizon-launcher-macos-arm64.dmg
if [[ "$identity" != "-" ]]; then
codesign --force --timestamp ${keychain[@]+"${keychain[@]}"} --sign "$identity" "$dmg"
codesign --verify --strict --verbose=2 "$dmg"
fi
hdiutil verify "$dmg" >/dev/null
if [[ -n "$notarize" ]]; then
"$here/notarize.sh" "$dmg"
# What Gatekeeper says of a download: both must be "source=Notarized Developer ID".
spctl --assess --verbose=2 "$app"
spctl --assess --type open --context context:primary-signature --verbose=2 "$dmg"
fi
echo "Packaged $out/horizon-launcher-macos-arm64.zip and .dmg"