From 7ef0376181f4f77421ac01252ee58b17c7ebe768 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 00:17:18 +0200 Subject: [PATCH] fix(actions): enhance macOS notarization workflow by adding security verifications and automation permissions --- .gitea/actions/macos-notarize/action.yml | 85 +++++++++++++++++++++++- .gitea/workflows/test-local-signing.yml | 4 ++ LuckyWorld.entitlements | 4 ++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 062da8cf..33cf0dce 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -1,6 +1,6 @@ name: "macOS Sign and Notarize" description: "Signs and notarizes macOS applications with Developer ID certificate" -author: moersoy" +author: moersoy inputs: app-path: @@ -674,6 +674,11 @@ runs: ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" echo "✅ Created ZIP package: $ZIP_FILE" + # Verify stapling on the app before packaging + echo "🔍 Verifying app notarization and stapling..." + xcrun stapler validate "${{ inputs.app-path }}" || echo "⚠️ App stapling verification failed" + spctl -a -vvv --type exec "${{ inputs.app-path }}" || echo "⚠️ App notarization verification failed" + # Check if we can create DMG (hdiutil is available) if command -v hdiutil &> /dev/null; then # Create DMG package (much better for distribution) @@ -687,8 +692,54 @@ runs: # Optional: Add README or instructions echo "# Installation Instructions\n\nDrag the application to your Applications folder to install." > "$DMG_TMP_DIR/README.txt" - # Create DMG file with the app - hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + # Create a helper script to remove quarantine attribute + echo "Creating helper script to remove quarantine attribute..." + mkdir -p "$DMG_TMP_DIR/scripts" + cat > "$DMG_TMP_DIR/scripts/remove_quarantine.sh" << 'EOF' +#!/bin/bash +APP_PATH="/Applications/$(basename "$0" | sed 's/remove_quarantine_//')" +if [ -d "$APP_PATH" ]; then + echo "Removing quarantine attribute from $APP_PATH" + xattr -dr com.apple.quarantine "$APP_PATH" + echo "✅ Quarantine attribute removed" + osascript -e "display notification \"Quarantine attribute removed from $APP_PATH\" with title \"Installation Complete\"" +else + echo "❌ Application not found at $APP_PATH" + osascript -e "display notification \"Application not found at $APP_PATH\" with title \"Installation Failed\"" +fi +EOF + + # Make the script executable and name it based on the app + chmod +x "$DMG_TMP_DIR/scripts/remove_quarantine.sh" + cp "$DMG_TMP_DIR/scripts/remove_quarantine.sh" "$DMG_TMP_DIR/scripts/remove_quarantine_$(basename "${{ inputs.app-path }}")" + + # Try to use create-dmg if available, otherwise fall back to hdiutil + if command -v create-dmg &> /dev/null; then + echo "Using create-dmg for better DMG creation..." + + # Decide which keychain to use for getting identity + if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then + echo "Using system keychain identity" + IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') + else + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') + fi + + create-dmg \ + --volname "${APP_NAME}" \ + --codesign-identity "$IDENTITY_HASH" \ + --app-drop-link 450 200 \ + --hide-extension "$(basename "${{ inputs.app-path }}")" \ + --add-file "README.txt" 200 200 \ + --add-file "scripts" 200 300 \ + --no-internet-enable \ + "$DMG_FILE" \ + "$DMG_TMP_DIR" + else + # Fall back to hdiutil + hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + fi if [ -f "$DMG_FILE" ]; then echo "✅ Created DMG package: $DMG_FILE" @@ -751,6 +802,10 @@ runs: echo "Verifying DMG stapling..." xcrun stapler validate "$DMG_FILE" + # Additional verification of DMG security + echo "Performing additional security verification of DMG..." + spctl --assess --verbose=4 --type open "$DMG_FILE" || echo "⚠️ DMG security verification warning" + echo "DMG is now fully signed, notarized, and stapled!" else echo "⚠️ DMG notarization may have failed or is still in progress." @@ -783,6 +838,10 @@ runs: echo "Verifying DMG stapling..." xcrun stapler validate "$DMG_FILE" + # Additional verification of DMG security + echo "Performing additional security verification of DMG..." + spctl --assess --verbose=4 --type open "$DMG_FILE" || echo "⚠️ DMG security verification warning" + echo "DMG is now fully signed, notarized, and stapled!" else echo "⚠️ DMG notarization may have failed or is still in progress." @@ -813,6 +872,26 @@ runs: echo "hdiutil not available, skipping DMG creation" echo "::set-output name=package-path::$ZIP_FILE" fi + + # Final verification of all artifacts + echo "🔍 Final verification of all distribution artifacts..." + + if [ -f "$ZIP_FILE" ]; then + echo "Verifying ZIP package integrity..." + ditto -v -x "$ZIP_FILE" /tmp/verify_app_extraction || echo "⚠️ ZIP extraction test failed" + rm -rf /tmp/verify_app_extraction + fi + + if [ -f "$DMG_FILE" ]; then + echo "Verifying DMG file signature..." + codesign -vvv "$DMG_FILE" || echo "⚠️ DMG signature verification failed" + + # Check if DMG was notarized successfully + if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then + echo "Verifying DMG stapling..." + xcrun stapler validate "$DMG_FILE" || echo "⚠️ DMG stapling verification failed" + fi + fi - name: Cleanup if: always() diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 1459312a..5f13a79e 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -32,6 +32,10 @@ jobs: com.apple.security.device.camera + com.apple.security.automation.apple-events + + com.apple.security.get-task-allow + EOF diff --git a/LuckyWorld.entitlements b/LuckyWorld.entitlements index 4dc9a495..d8b1cb47 100644 --- a/LuckyWorld.entitlements +++ b/LuckyWorld.entitlements @@ -22,5 +22,9 @@ com.apple.security.network.client + com.apple.security.automation.apple-events + + com.apple.security.get-task-allow + \ No newline at end of file