From f63a4211cd2b92eb42f53c4415c6eeb8baa6301f Mon Sep 17 00:00:00 2001 From: elkaix Date: Tue, 25 Aug 2026 15:41:13 -0400 Subject: [PATCH] ci(desktop): notarize and staple the macOS DMG electron-builder notarizes and staples the .app but not the disk image around it. A quarantined, unnotarized DMG is what Gatekeeper reports as "Pythinker.app is damaged and can't be opened" for browser downloads. Submit the DMG to notarytool, staple it, and gate the release on "spctl --assess --type open" accepting the image itself. --- .github/workflows/desktop-release.yml | 32 ++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml index 9377d96c2..9441d82b7 100644 --- a/.github/workflows/desktop-release.yml +++ b/.github/workflows/desktop-release.yml @@ -236,6 +236,31 @@ jobs: working-directory: apps/desktop run: pnpm exec electron-builder --mac dmg zip --publish never + # electron-builder notarizes and staples the .app but never the disk + # image around it. A quarantined, unnotarized DMG is what Gatekeeper + # reports as "damaged" on some macOS builds, so give the image its own + # ticket and staple it. The API key is preferred; the Apple ID + + # app-specific password pair is the fallback, mirroring electron-builder. + - name: Notarize and staple macOS DMG + shell: bash + run: | + set -euo pipefail + dmg_path="$(find apps/desktop/dist -maxdepth 1 -type f -name '*.dmg' -print -quit)" + if [ -z "$dmg_path" ]; then + echo 'macOS DMG not found' >&2 + exit 1 + fi + if [ -n "${APPLE_API_KEY:-}" ]; then + auth=(--key "$APPLE_API_KEY" --key-id "$APPLE_API_KEY_ID" --issuer "$APPLE_API_ISSUER") + elif [ -n "${APPLE_ID:-}" ]; then + auth=(--apple-id "$APPLE_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD" --team-id "$APPLE_TEAM_ID") + else + echo 'No notarization credentials configured; the DMG cannot be notarized.' >&2 + exit 1 + fi + xcrun notarytool submit "$dmg_path" "${auth[@]}" --wait --timeout 30m + xcrun stapler staple "$dmg_path" + - name: Verify macOS update artifacts shell: bash env: @@ -293,12 +318,13 @@ jobs: exit 1 fi verify_app "$dmg_app" - # electron-builder notarizes and staples the .app, then packs the - # already-stapled bundle into the disk image; the image itself never - # receives a ticket. Validate the staple where it actually lives. xcrun stapler validate "$dmg_app" cleanup_mount trap - EXIT + # The image carries its own ticket (see the notarize step above); + # Gatekeeper must accept it exactly as a user's browser download. + xcrun stapler validate "$dmg_path" + spctl --assess --type open --context context:primary-signature --verbose=2 "$dmg_path" - name: Mint releases-repo token if: needs.prepare.outputs.publish == 'true'