#!/bin/bash # Builds, signs, notarizes, staples, and zips Konverter for release. # # ./release.sh 0.1.0 # # Notarization is required. If it fails, this script fails: do not publish the # tag, release, or cask from an unnotarized build. set -euo pipefail cd "$(dirname "$0")" if [ "$#" -ne 1 ]; then echo "usage: $0 e.g. ./release.sh 0.1.0" >&2 exit 1 fi VERSION="$1" APP="Konverter.app" ZIP="dist/Konverter.zip" IDENT=$(security find-identity -v -p codesigning 2>/dev/null \ | awk '/Developer ID Application:/ { print $2; exit }') if [ -z "$IDENT" ]; then echo "release.sh: no Developer ID Application identity in the keychain." >&2 echo "An ad-hoc signed build cannot be notarized; install the certificate first." >&2 exit 1 fi KEY_PATH="${KONVERTER_NOTARY_API_KEY_PATH:-$HOME/.config/kapture/AuthKey_K5KXMMSB28.p8}" KEY_ID="${KONVERTER_NOTARY_API_KEY_ID:-K5KXMMSB28}" ISSUER="${KONVERTER_NOTARY_API_ISSUER:-3e25e5dc-8b75-453f-a71c-c7f3feaac628}" if [ ! -f "$KEY_PATH" ]; then echo "release.sh: notary API key not found at $KEY_PATH" >&2 exit 1 fi if ! xcrun --find notarytool >/dev/null 2>&1; then echo "release.sh: xcrun notarytool not found (requires Xcode 13+)." >&2 exit 1 fi ./build-app.sh "$VERSION" # The zip submitted to Apple must contain the signed bundle only. mkdir -p dist rm -f "$ZIP" ditto -c -k --keepParent "$APP" "$ZIP" echo "Submitting to Apple for notarization (first run can take minutes)..." RESULT=$(mktemp) trap 'rm -f "$RESULT"' EXIT xcrun notarytool submit "$ZIP" \ --key "$KEY_PATH" \ --key-id "$KEY_ID" \ --issuer "$ISSUER" \ --wait \ --output-format json > "$RESULT" STATUS=$(/usr/bin/python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("status","unknown"))' "$RESULT" 2>/dev/null || echo unknown) if [ "$STATUS" != "Accepted" ]; then echo "release.sh: notarization returned '$STATUS' — release aborted." >&2 cat "$RESULT" >&2 SUBMIT_ID=$(/usr/bin/python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("id",""))' "$RESULT" 2>/dev/null || true) if [ -n "$SUBMIT_ID" ]; then echo "Detail:" >&2 xcrun notarytool log "$SUBMIT_ID" --key "$KEY_PATH" --key-id "$KEY_ID" --issuer "$ISSUER" >&2 || true fi exit 1 fi echo "Notarization accepted — stapling ticket onto the app..." xcrun stapler staple "$APP" xcrun stapler validate "$APP" # Re-zip so the distributed archive carries the stapled ticket. rm -f "$ZIP" ditto -c -k --keepParent "$APP" "$ZIP" echo "Verifying Gatekeeper assessment..." if ! spctl -a -vv "$APP" 2>&1 | grep -q 'source=Notarized Developer ID'; then echo "release.sh: spctl does not report 'source=Notarized Developer ID' — release aborted." >&2 spctl -a -vv "$APP" >&2 || true exit 1 fi spctl -a -vv "$APP" 2>&1 | sed 's/^/ /' echo echo "Done — notarized and stapled." shasum -a 256 "$ZIP" echo echo "Publish with:" echo " git tag v$VERSION && git push origin v$VERSION" echo " tea releases create --tag v$VERSION --title \"Konverter $VERSION\" \\" echo " --note \"\" --asset $ZIP \\" echo " --repo TZGyn/konverter --login gitea.tzgyn.dev"