diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 1f9c1973..7c3a47be 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -396,11 +396,29 @@ runs: # Staple the notarization ticket echo "Stapling notarization ticket..." - xcrun stapler staple "${{ inputs.app-path }}" + xcrun stapler staple -v "${{ inputs.app-path }}" STAPLE_STATUS=$? if [ $STAPLE_STATUS -eq 0 ]; then echo "✅ Stapling completed successfully!" + + # Verify the stapling worked properly + echo "Verifying stapled ticket is properly attached..." + xcrun stapler validate -v "${{ inputs.app-path }}" + + # Check if stapling metadata is correctly stored in xattr + echo "Checking app extended attributes..." + if command -v xattr &> /dev/null; then + xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "⚠️ Warning: com.apple.provenance attribute not found" + fi + + # Add special instructions for distribution + echo "📋 IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings." + echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files." + echo "For proper distribution, consider the following options:" + echo "1. Use a DMG installer with a signed, notarized app inside" + echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)" + echo "3. If distributing directly, use a distribution platform that preserves notarization tickets" else echo "⚠️ Stapling completed with status $STAPLE_STATUS (may still be valid)" fi @@ -556,11 +574,29 @@ runs: # Staple the notarization ticket echo "Stapling notarization ticket..." - xcrun stapler staple "${{ inputs.app-path }}" + xcrun stapler staple -v "${{ inputs.app-path }}" STAPLE_STATUS=$? if [ $STAPLE_STATUS -eq 0 ]; then echo "✅ Stapling completed successfully!" + + # Verify the stapling worked properly + echo "Verifying stapled ticket is properly attached..." + xcrun stapler validate -v "${{ inputs.app-path }}" + + # Check if stapling metadata is correctly stored in xattr + echo "Checking app extended attributes..." + if command -v xattr &> /dev/null; then + xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "⚠️ Warning: com.apple.provenance attribute not found" + fi + + # Add special instructions for distribution + echo "📋 IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings." + echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files." + echo "For proper distribution, consider the following options:" + echo "1. Use a DMG installer with a signed, notarized app inside" + echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)" + echo "3. If distributing directly, use a distribution platform that preserves notarization tickets" else echo "⚠️ Stapling completed with status $STAPLE_STATUS (may still be valid)" fi @@ -626,18 +662,50 @@ runs: APP_NAME=$(basename "${{ inputs.app-path }}" .app) if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then - ZIP_FILE="${APP_NAME}-Signed-Notarized.zip" + PACKAGE_SUFFIX="Signed-Notarized" echo "Creating distribution package with notarized app..." else - ZIP_FILE="${APP_NAME}-Signed.zip" + PACKAGE_SUFFIX="Signed" echo "Creating distribution package with signed app..." fi # Create zip package + ZIP_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.zip" ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" + echo "✅ Created ZIP package: $ZIP_FILE" - echo "✅ Created package: $ZIP_FILE" - echo "::set-output name=package-path::$ZIP_FILE" + # Check if we can create DMG (hdiutil is available) + if command -v hdiutil &> /dev/null; then + # Create DMG package (much better for distribution) + DMG_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.dmg" + echo "Creating DMG distribution package..." + + # Create temporary folder for DMG contents + DMG_TMP_DIR=$(mktemp -d) + cp -R "${{ inputs.app-path }}" "$DMG_TMP_DIR/" + + # 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" + + if [ -f "$DMG_FILE" ]; then + echo "✅ Created DMG package: $DMG_FILE" + # Use DMG as the primary package if available + echo "::set-output name=package-path::$DMG_FILE" + echo "::set-output name=zip-package-path::$ZIP_FILE" + else + echo "⚠️ Failed to create DMG, falling back to ZIP package" + echo "::set-output name=package-path::$ZIP_FILE" + fi + + # Clean up temp directory + rm -rf "$DMG_TMP_DIR" + else + echo "hdiutil not available, skipping DMG creation" + echo "::set-output name=package-path::$ZIP_FILE" + fi - name: Cleanup if: always() diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 30803244..dbd4b8ad 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -201,6 +201,15 @@ jobs: name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized' || 'LuckyWorld-macOS-Signed' }} path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 30 + + # Upload ZIP package if DMG was created (as a backup) + - name: Upload ZIP Package + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' + with: + name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized-ZIP' || 'LuckyWorld-macOS-Signed-ZIP' }} + path: ${{ steps.sign-and-notarize.outputs.zip-package-path }} + retention-days: 30 # Report results - name: Report Results