@@ -312,6 +312,44 @@ jobs:
312312 codesign --force --deep --sign - --timestamp=none "$APP"
313313 codesign --verify --deep --verbose=2 "$APP" || (codesign --display --verbose=5 "$APP"; exit 1)
314314
315+ - name : Verify permissions and Info.plist
316+ run : |
317+ set -euxo pipefail
318+ APP="dist/SSH Studio.app"
319+ chmod +x "$APP/Contents/MacOS/ssh-studio"
320+ plutil -lint "$APP/Contents/Info.plist"
321+ # Show signature and linkage (non-fatal)
322+ codesign -dv --verbose=4 "$APP" || true
323+ otool -L "$APP/Contents/MacOS/ssh-studio" || true
324+
325+ - name : Gatekeeper assessment (non-fatal)
326+ run : |
327+ set -euxo pipefail
328+ APP="dist/SSH Studio.app"
329+ spctl --assess --type execute -v "$APP" || true
330+
331+ - name : Developer ID sign app (optional)
332+ env :
333+ APPLE_SIGNING_IDENTITY : ${{ secrets.APPLE_SIGNING_IDENTITY }}
334+ APPLE_DEVELOPER_CERT_BASE64 : ${{ secrets.APPLE_DEVELOPER_CERT_BASE64 }}
335+ APPLE_DEVELOPER_CERT_PASSWORD : ${{ secrets.APPLE_DEVELOPER_CERT_PASSWORD }}
336+ run : |
337+ set -euxo pipefail
338+ APP="dist/SSH Studio.app"
339+ if [ -z "${APPLE_SIGNING_IDENTITY:-}" ] || [ -z "${APPLE_DEVELOPER_CERT_BASE64:-}" ] || [ -z "${APPLE_DEVELOPER_CERT_PASSWORD:-}" ]; then
340+ echo "Signing secrets not provided; skipping Developer ID signing."; exit 0; fi
341+ KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
342+ KEYCHAIN_PWD="$(openssl rand -hex 12)"
343+ security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN_PATH"
344+ security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
345+ security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN_PATH"
346+ echo "$APPLE_DEVELOPER_CERT_BASE64" | base64 --decode > "$RUNNER_TEMP/dev_cert.p12"
347+ security import "$RUNNER_TEMP/dev_cert.p12" -k "$KEYCHAIN_PATH" -P "$APPLE_DEVELOPER_CERT_PASSWORD" -A
348+ security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain-db
349+ # Re-sign app with Developer ID (replaces ad-hoc)
350+ codesign --force --deep --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" "$APP"
351+ codesign --verify --deep --strict --verbose=2 "$APP"
352+
315353
316354 - name : Create DMG
317355 run : |
@@ -324,6 +362,76 @@ jobs:
324362 ln -s /Applications dmgroot/Applications
325363 hdiutil create -volname "SSH Studio" -srcfolder dmgroot -ov -fs HFS+ "ssh-studio-${VER}-${ARCH}.dmg"
326364
365+ - name : Developer ID sign DMG (optional)
366+ env :
367+ APPLE_SIGNING_IDENTITY : ${{ secrets.APPLE_SIGNING_IDENTITY }}
368+ APPLE_DEVELOPER_CERT_BASE64 : ${{ secrets.APPLE_DEVELOPER_CERT_BASE64 }}
369+ APPLE_DEVELOPER_CERT_PASSWORD : ${{ secrets.APPLE_DEVELOPER_CERT_PASSWORD }}
370+ run : |
371+ set -euxo pipefail
372+ if [ -z "${APPLE_SIGNING_IDENTITY:-}" ] || [ -z "${APPLE_DEVELOPER_CERT_BASE64:-}" ] || [ -z "${APPLE_DEVELOPER_CERT_PASSWORD:-}" ]; then
373+ echo "Signing secrets not provided; skipping DMG signing."; exit 0; fi
374+ VER=$(sed -n "s/.*version: '\([^']*\)'.*/\1/p" meson.build | head -n1)
375+ ARCH=$(uname -m)
376+ DMG="ssh-studio-${VER}-${ARCH}.dmg"
377+ KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
378+ if [ ! -f "$RUNNER_TEMP/dev_cert.p12" ]; then
379+ echo "$APPLE_DEVELOPER_CERT_BASE64" | base64 --decode > "$RUNNER_TEMP/dev_cert.p12"
380+ fi
381+ if [ ! -f "$KEYCHAIN_PATH" ]; then
382+ KEYCHAIN_PWD="$(openssl rand -hex 12)"
383+ security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN_PATH"
384+ security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
385+ security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN_PATH"
386+ security import "$RUNNER_TEMP/dev_cert.p12" -k "$KEYCHAIN_PATH" -P "$APPLE_DEVELOPER_CERT_PASSWORD" -A
387+ security list-keychain -d user -s "$KEYCHAIN_PATH" login.keychain-db
388+ fi
389+ codesign --force --timestamp --sign "$APPLE_SIGNING_IDENTITY" "$DMG"
390+ spctl --assess --type open -v "$DMG" || true
391+
392+ - name : Notarize DMG with notarytool (API key) (optional)
393+ env :
394+ NOTARYTOOL_KEY_ID : ${{ secrets.NOTARYTOOL_KEY_ID }}
395+ NOTARYTOOL_ISSUER_ID : ${{ secrets.NOTARYTOOL_ISSUER_ID }}
396+ NOTARYTOOL_PRIVATE_KEY : ${{ secrets.NOTARYTOOL_PRIVATE_KEY }}
397+ run : |
398+ set -euxo pipefail
399+ if [ -z "${NOTARYTOOL_KEY_ID:-}" ] || [ -z "${NOTARYTOOL_ISSUER_ID:-}" ] || [ -z "${NOTARYTOOL_PRIVATE_KEY:-}" ]; then
400+ echo "Notary API key secrets not provided; skipping API-key notarization."; exit 0; fi
401+ VER=$(sed -n "s/.*version: '\([^']*\)'.*/\1/p" meson.build | head -n1)
402+ ARCH=$(uname -m)
403+ DMG="ssh-studio-${VER}-${ARCH}.dmg"
404+ KEYFILE="$RUNNER_TEMP/AuthKey.p8"
405+ echo "$NOTARYTOOL_PRIVATE_KEY" > "$KEYFILE"
406+ xcrun notarytool submit "$DMG" \
407+ --key "$KEYFILE" \
408+ --key-id "$NOTARYTOOL_KEY_ID" \
409+ --issuer "$NOTARYTOOL_ISSUER_ID" \
410+ --wait
411+ xcrun stapler staple "$DMG"
412+
413+ - name : Notarize DMG with notarytool (Apple ID) (optional)
414+ env :
415+ APPLE_ID : ${{ secrets.APPLE_ID }}
416+ APPLE_TEAM_ID : ${{ secrets.APPLE_TEAM_ID }}
417+ APPLE_APP_SPECIFIC_PASSWORD : ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
418+ run : |
419+ set -euxo pipefail
420+ # Only run if API key secrets are missing but Apple ID-based secrets are present
421+ if [ -n "${NOTARYTOOL_KEY_ID:-}" ] && [ -n "${NOTARYTOOL_ISSUER_ID:-}" ] && [ -n "${NOTARYTOOL_PRIVATE_KEY:-}" ]; then
422+ echo "API key provided; skipping Apple ID notarization path."; exit 0; fi
423+ if [ -z "${APPLE_ID:-}" ] || [ -z "${APPLE_TEAM_ID:-}" ] || [ -z "${APPLE_APP_SPECIFIC_PASSWORD:-}" ]; then
424+ echo "Apple ID notarization secrets not provided; skipping."; exit 0; fi
425+ VER=$(sed -n "s/.*version: '\([^']*\)'.*/\1/p" meson.build | head -n1)
426+ ARCH=$(uname -m)
427+ DMG="ssh-studio-${VER}-${ARCH}.dmg"
428+ xcrun notarytool submit "$DMG" \
429+ --apple-id "$APPLE_ID" \
430+ --team-id "$APPLE_TEAM_ID" \
431+ --password "$APPLE_APP_SPECIFIC_PASSWORD" \
432+ --wait
433+ xcrun stapler staple "$DMG"
434+
327435
328436 - name : Upload artifact
329437 uses : actions/upload-artifact@v4
0 commit comments