From 8aa96ee2647c37e6bc1079a6b607f1b025e075a1 Mon Sep 17 00:00:00 2001 From: Iliya Date: Fri, 16 Oct 2026 23:34:50 -0400 Subject: [PATCH] Retry stapling when Apple's ticket service drops the connection Two releases in a row (v1.25.3, v1.25.4) failed after notarization succeeded, because stapler lost its connection to Apple's CloudKit ticket service (-1005, error 68). Staple and validate now retry up to four times with a growing delay, and the release workflow no longer runs a second, redundant validate after build-dmg.sh has done it. --- .github/workflows/release.yml | 2 +- scripts/build-dmg.sh | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c39c9e4..3b06fff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -154,7 +154,7 @@ jobs: export VERSION="${{ steps.version.outputs.version }}" bash scripts/build-dmg.sh --notarize ls -la .build/MacSai-${VERSION}.dmg - xcrun stapler validate .build/MacSai-${VERSION}.dmg + # build-dmg.sh already staples and validates the DMG (with retries). - name: Clean up signing keychain if: always() diff --git a/scripts/build-dmg.sh b/scripts/build-dmg.sh index 2510773..1b2650f 100755 --- a/scripts/build-dmg.sh +++ b/scripts/build-dmg.sh @@ -50,6 +50,25 @@ if [[ "${1:-}" == "--notarize" ]]; then SIGNING_IDENTITY="$APPLE_DEVELOPER_ID" fi +# Stapling and validating fetch the ticket from Apple's CloudKit service, +# which sometimes drops the connection ("-1005 The network connection was +# lost", error 68) after notarization already succeeded. Retry instead of +# failing the whole release. +stapler_with_retry() { + local attempt + for attempt in 1 2 3 4; do + if xcrun stapler "$@"; then + return 0 + fi + if [[ $attempt -lt 4 ]]; then + echo " stapler $1 failed (attempt ${attempt}/4), retrying in $((attempt * 15))s..." + sleep $((attempt * 15)) + fi + done + echo "ERROR: stapler $1 failed after 4 attempts" + return 1 +} + echo "=== Building Mac Sai v${VERSION} ===" echo "Signing identity: $SIGNING_IDENTITY" echo "Notarize: $NOTARIZE" @@ -259,8 +278,8 @@ if [[ "$NOTARIZE" == "true" ]]; then --keychain-profile "${NOTARY_PROFILE}" \ --wait rm -f "${APP_ZIP}" - xcrun stapler staple "${APP_BUNDLE}" - xcrun stapler validate "${APP_BUNDLE}" + stapler_with_retry staple "${APP_BUNDLE}" + stapler_with_retry validate "${APP_BUNDLE}" echo " → App notarized and stapled (verifies offline)" fi @@ -288,8 +307,8 @@ if [[ "$NOTARIZE" == "true" ]]; then xcrun notarytool submit ".build/${DMG_NAME}" \ --keychain-profile "${NOTARY_PROFILE}" \ --wait - xcrun stapler staple ".build/${DMG_NAME}" - xcrun stapler validate ".build/${DMG_NAME}" + stapler_with_retry staple ".build/${DMG_NAME}" + stapler_with_retry validate ".build/${DMG_NAME}" echo " → Notarization complete (DMG stapled; app inside stapled too)" else echo "[7/7] Skipping notarization (no --notarize flag)"