From 234a4226c5f23808f42b97049223768650b668e8 Mon Sep 17 00:00:00 2001 From: TZGyn Date: Wed, 12 Aug 2026 11:31:14 +0800 Subject: [PATCH] Add notarization to release pipeline; sign with hardened runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release.sh now submits the zip to Apple's notary via notarytool, staples the ticket, and repackages, so users no longer hit Gatekeeper warnings. build-app.sh signs Developer ID builds with the hardened runtime and unlocks the login keychain to avoid transient signing errors. The private API key (.p8) is gitignored. 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-flash-0731 --- .gitignore | 3 +++ build-app.sh | 8 +++--- release.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c2f0ace..1817c52 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ # App bundle (build artifact, regenerate with ./build-app.sh) Kapture.app/ +# Secrets +*.p8 + # macOS .DS_Store diff --git a/build-app.sh b/build-app.sh index 10f8150..60bb35f 100755 --- a/build-app.sh +++ b/build-app.sh @@ -23,8 +23,10 @@ SIGN_KEYCHAIN="" if [ -n "$DEV_IDENT" ]; then CERT="$DEV_IDENT" echo "Using Developer ID identity: $CERT" - # Sign from the login keychain where the Dev ID lives. - SIGN_KEYCHAIN="" + # Ensure the login keychain holding the Dev ID is unlocked & accessible. + security unlock-keychain "$HOME/Library/Keychains/login.keychain-db" 2>/dev/null || true + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" "$HOME/Library/Keychains/login.keychain-db" >/dev/null 2>&1 || true + SIGN_KEYCHAIN="$HOME/Library/Keychains/login.keychain-db" else CERT="kapture-dev" echo "Using self-signed identity 'kapture-dev'" @@ -123,7 +125,7 @@ chmod +x scripts/make-icon.sh ./scripts/make-icon.sh if [ -n "$SIGN_KEYCHAIN" ]; then - codesign --force --sign "$CERT" --keychain "$SIGN_KEYCHAIN" "$APP" + codesign --force --options runtime --sign "$CERT" --keychain "$SIGN_KEYCHAIN" "$APP" else codesign --force --sign "$CERT" "$APP" fi diff --git a/release.sh b/release.sh index 0f780bf..4f15ce0 100755 --- a/release.sh +++ b/release.sh @@ -8,14 +8,83 @@ if [ "$#" -ne 1 ]; then fi VERSION="$1" +# Notarization credentials. Configure once, e.g. in ~/.zshrc: +# export KAPTURE_NOTARY_ASC_PROVIDER="" +# export KAPTURE_NOTARY_API_KEY_PATH="$HOME/.config/kapture/AuthKey_XXXX.p8" +# export KAPTURE_NOTARY_API_KEY_ID="" +# export KAPTURE_NOTARY_API_ISSUER="" +# If these are unset (or KAPTURE_SKIP_NOTARY=1), release.sh builds, zips, and stops +# there — the zip is signed with the Developer ID identity but NOT notarized. + ./build-app.sh mkdir -p dist rm -f dist/Kapture.zip ditto -c -k --keepParent Kapture.app dist/Kapture.zip -shasum -a 256 dist/Kapture.zip +if [ -n "${KAPTURE_SKIP_NOTARY:-}" ]; then + echo + echo "Skipping notarization (KAPTURE_SKIP_NOTARY set)." + shasum -a 256 dist/Kapture.zip + echo + echo "Tag and release with:" + echo " git tag v$VERSION && git push origin v$VERSION" + echo "Attach dist/Kapture.zip to the GitHub release manually." + exit 0 +fi + +REQUIRED_VARS="KAPTURE_NOTARY_ASC_PROVIDER KAPTURE_NOTARY_API_KEY_PATH KAPTURE_NOTARY_API_KEY_ID KAPTURE_NOTARY_API_ISSUER" +MISSING="" +for v in $REQUIRED_VARS; do + if [ -z "${!v:-}" ]; then + MISSING="$MISSING $v" + fi +done +if [ -n "$MISSING" ]; then + echo "Notarization skipped — missing env var(s):$MISSING (see header comments)." >&2 + shasum -a 256 dist/Kapture.zip + echo + echo "The zip above is signed but NOT notarized; Gatekeeper will warn users until it is." + echo "Set the KAPTURE_NOTARY_* variables and re-run ./release.sh $VERSION." + exit 0 +fi + +if ! command -v xcrun >/dev/null 2>&1 || ! xcrun --find notarytool >/dev/null 2>&1; then + echo "Notarization skipped — xcrun notarytool not found (requires Xcode 13+)." >&2 + shasum -a 256 dist/Kapture.zip + exit 0 +fi + +echo "Submitting to Apple for notarization (first run can take minutes)..." +xcrun notarytool submit dist/Kapture.zip \ + --key "$KAPTURE_NOTARY_API_KEY_PATH" \ + --key-id "$KAPTURE_NOTARY_API_KEY_ID" \ + --issuer "$KAPTURE_NOTARY_API_ISSUER" \ + --wait \ + --output-format json > notary-result.json + +STATUS=$(jq -r '.status' notary-result.json 2>/dev/null || echo "unknown") +if [ "$STATUS" != "Accepted" ]; then + echo "Notarization failed with status: $STATUS" >&2 + if [ -f notary-result.json ]; then + cat notary-result.json >&2 + rm -f notary-result.json + fi + exit 1 +fi +rm -f notary-result.json + +echo "Notarization accepted — stapling ticket onto the app..." +xcrun stapler staple Kapture.app +xcrun stapler validate Kapture.app + +rm -f dist/Kapture.zip +ditto -c -k --keepParent Kapture.app dist/Kapture.zip + +echo +echo "Done — notarized." +shasum -a 256 dist/Kapture.zip echo echo "Tag and release with:" echo " git tag v$VERSION && git push origin v$VERSION" -echo "Attach dist/Kapture.zip to the GitHub release manually." +echo "Attach dist/Kapture.zip to the GitHub release manually; the Homebrew cask is ready."