fix(actions): streamline macOS build workflow by integrating DMG signing and notarization directly into the macos-notarize action

This commit is contained in:
Ozgur 2025-04-15 20:31:04 +02:00
parent 71e5075d42
commit 659b5de3ea
No known key found for this signature in database
GPG Key ID: 66CDF27505A35546
2 changed files with 130 additions and 93 deletions

View File

@ -692,6 +692,113 @@ runs:
if [ -f "$DMG_FILE" ]; then
echo "✅ Created DMG package: $DMG_FILE"
# Sign the DMG with the same certificate used for the app
echo "Signing DMG file..."
# Decide which keychain to use
if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then
echo "Using system keychain identity"
# Get certificate hash instead of name to avoid ambiguity
IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}')
echo "Using certificate hash: $IDENTITY_HASH"
else
# Make sure keychain is unlocked
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
echo "Using custom keychain identity"
# Get certificate hash instead of name to avoid ambiguity
IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}')
echo "Using certificate hash: $IDENTITY_HASH"
fi
if [ -n "$IDENTITY_HASH" ]; then
# Sign the DMG
codesign --force --sign "$IDENTITY_HASH" --options runtime --timestamp "$DMG_FILE"
# Verify DMG signature
echo "Verifying DMG signature..."
codesign -vvv "$DMG_FILE"
# Only notarize DMG if the app was successfully notarized
if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then
echo "Notarizing DMG file..."
# Check if we're using API key notarization method
if [ "${{ inputs.notarization-method }}" = "api-key" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then
# Use the same API key setup from the notarize step
echo "Using App Store Connect API key for DMG notarization..."
echo "Submitting DMG for notarization..."
DMG_SUBMIT_OUTPUT=$(xcrun notarytool submit "$DMG_FILE" \
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
--key-id "$API_KEY_ID" \
--issuer "$API_ISSUER_ID" --wait 2>&1)
echo "DMG notarization submission output:"
echo "$DMG_SUBMIT_OUTPUT"
# Extract DMG submission ID
DMG_SUBMISSION_ID=$(echo "$DMG_SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2)
if [ -n "$DMG_SUBMISSION_ID" ] && echo "$DMG_SUBMIT_OUTPUT" | grep -q "status: Accepted"; then
echo "✅ DMG notarization completed successfully!"
# Staple the DMG
echo "Stapling notarization ticket to DMG..."
xcrun stapler staple "$DMG_FILE"
# Verify DMG stapling
echo "Verifying DMG stapling..."
xcrun stapler validate "$DMG_FILE"
echo "DMG is now fully signed, notarized, and stapled!"
else
echo "⚠️ DMG notarization may have failed or is still in progress."
echo "The app itself is still properly notarized, but the DMG may need manual verification."
fi
elif [ "${{ inputs.notarization-method }}" = "app-password" ] && [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then
# Use App-specific password for DMG notarization
echo "Using App-specific password for DMG notarization..."
echo "Submitting DMG for notarization..."
DMG_SUBMIT_OUTPUT=$(xcrun notarytool submit "$DMG_FILE" \
--apple-id "$APPLE_ID" \
--password "$APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID" --wait 2>&1)
echo "DMG notarization submission output:"
echo "$DMG_SUBMIT_OUTPUT"
# Extract DMG submission ID
DMG_SUBMISSION_ID=$(echo "$DMG_SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2)
if [ -n "$DMG_SUBMISSION_ID" ] && echo "$DMG_SUBMIT_OUTPUT" | grep -q "status: Accepted"; then
echo "✅ DMG notarization completed successfully!"
# Staple the DMG
echo "Stapling notarization ticket to DMG..."
xcrun stapler staple "$DMG_FILE"
# Verify DMG stapling
echo "Verifying DMG stapling..."
xcrun stapler validate "$DMG_FILE"
echo "DMG is now fully signed, notarized, and stapled!"
else
echo "⚠️ DMG notarization may have failed or is still in progress."
echo "The app itself is still properly notarized, but the DMG may need manual verification."
fi
else
echo "⚠️ DMG not notarized due to missing credentials."
echo "The app itself is properly notarized, but the DMG is only signed."
fi
else
echo "App was not notarized, skipping DMG notarization."
fi
else
echo "⚠️ No valid identity found for DMG signing. DMG will be created but not signed."
fi
# 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"

View File

@ -314,26 +314,6 @@ jobs:
echo "STAPLED_APP_PATH=$APP_PATH" >> "$GITHUB_ENV"
shell: bash
# Create a properly archived ZIP of the stapled app (preserves stapling)
- name: Create Stapled App Archive (ZIP)
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none'
run: |
STAPLED_APP_PATH="${{ env.STAPLED_APP_PATH }}"
APP_NAME=$(basename "$STAPLED_APP_PATH" .app)
ARCHIVE_DIR="./ArchivedApps"
mkdir -p "$ARCHIVE_DIR"
# Create the ZIP archive (preserving all metadata)
echo "Creating ZIP archive of stapled app..."
cd "$(dirname "$STAPLED_APP_PATH")"
# Use ditto to preserve all metadata and permissions
ditto -c -k --keepParent "$(basename "$STAPLED_APP_PATH")" "$GITHUB_WORKSPACE/$ARCHIVE_DIR/$APP_NAME.zip"
cd "$GITHUB_WORKSPACE"
echo "ZIP archive created at: $ARCHIVE_DIR/$APP_NAME.zip"
echo "STAPLED_APP_ZIP=$ARCHIVE_DIR/$APP_NAME.zip" >> "$GITHUB_ENV"
shell: bash
# Create a DMG file (macOS disk image) for easy distribution
- name: Create DMG for Distribution
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none'
@ -343,77 +323,17 @@ jobs:
ARCHIVE_DIR="./ArchivedApps"
DMG_FILE="$ARCHIVE_DIR/$APP_NAME.dmg"
# Create a DMG file
echo "Creating DMG file..."
hdiutil create -volname "$APP_NAME" -srcfolder "$STAPLED_APP_PATH" -ov -format UDZO "$DMG_FILE"
# Note: The actual DMG creation, signing, notarization and stapling
# are now handled by the macos-notarize action
# Sign the DMG with the same certificate
echo "Signing DMG file..."
# Extract certificate info from the previously signed app
CERT_IDENTITY=$(codesign -dvv "$STAPLED_APP_PATH" 2>&1 | grep "Authority" | head -1 | sed -e 's/.*Authority=//g')
echo "Using certificate identity: $CERT_IDENTITY"
# Sign the DMG
codesign --sign "$CERT_IDENTITY" --options runtime --timestamp "$DMG_FILE"
# Verify DMG signature
echo "Verifying DMG signature..."
codesign -vvv "$DMG_FILE"
# Notarize the DMG
echo "Notarizing DMG file..."
# Select which authentication method to use for notarization
if [ -n "${{ secrets.NOTARY_API_KEY_ID }}" ] && [ -n "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" ]; then
# Use API Key authentication (preferred)
echo "Using Notary API Key authentication..."
UUID=$(xcrun notarytool submit "$DMG_FILE" \
--key "${{ secrets.NOTARY_API_KEY_PATH }}" \
--key-id "${{ secrets.NOTARY_API_KEY_ID }}" \
--issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" \
--wait | grep "id:" | awk '{print $2}')
elif [ -n "${{ secrets.APPLE_ID }}" ] && [ -n "${{ secrets.APPLE_TEAM_ID }}" ]; then
# Use Apple ID authentication
echo "Using Apple ID authentication..."
UUID=$(xcrun notarytool submit "$DMG_FILE" \
--apple-id "${{ secrets.APPLE_ID }}" \
--password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \
--team-id "${{ secrets.APPLE_TEAM_ID }}" \
--wait | grep "id:" | awk '{print $2}')
# Just ensure we have the correct path for outputs
if [ -f "${{ steps.sign-and-notarize.outputs.package-path }}" ]; then
echo "Using DMG created by the macos-notarize action"
echo "DMG file location: ${{ steps.sign-and-notarize.outputs.package-path }}"
echo "STAPLED_APP_DMG=${{ steps.sign-and-notarize.outputs.package-path }}" >> "$GITHUB_ENV"
else
echo "⚠️ No notarization credentials available. DMG will not be notarized."
UUID=""
echo "⚠️ DMG not found from the macos-notarize action output"
fi
echo "Notarization UUID: $UUID"
# Check notarization status
if [ -n "$UUID" ]; then
# Use the same authentication method for UUID info
if [ -n "${{ secrets.NOTARY_API_KEY_ID }}" ] && [ -n "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" ]; then
xcrun notarytool info "$UUID" \
--key "${{ secrets.NOTARY_API_KEY_PATH }}" \
--key-id "${{ secrets.NOTARY_API_KEY_ID }}" \
--issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}"
elif [ -n "${{ secrets.APPLE_ID }}" ] && [ -n "${{ secrets.APPLE_TEAM_ID }}" ]; then
xcrun notarytool info "$UUID" \
--apple-id "${{ secrets.APPLE_ID }}" \
--password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \
--team-id "${{ secrets.APPLE_TEAM_ID }}"
fi
# Staple the DMG
echo "Stapling notarization ticket to DMG..."
xcrun stapler staple "$DMG_FILE"
# Verify stapling
echo "Verifying DMG stapling..."
xcrun stapler validate "$DMG_FILE"
else
echo "⚠️ Notarization UUID not found. DMG may not be properly notarized."
fi
echo "DMG file created at: $DMG_FILE"
echo "STAPLED_APP_DMG=$DMG_FILE" >> "$GITHUB_ENV"
shell: bash
# Upload stapled app directly (this is the most reliable approach)
@ -425,22 +345,32 @@ jobs:
path: ${{ env.STAPLED_APP_PATH }}
retention-days: 30
# Upload the ZIP archive (proper archiving that preserves stapling)
# Create a properly archived ZIP of the stapled app (preserves stapling)
- name: Create Stapled App Archive (ZIP)
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != ''
run: |
# The ZIP is now created by the macos-notarize action
echo "Using ZIP created by the macos-notarize action"
echo "ZIP file location: ${{ steps.sign-and-notarize.outputs.zip-package-path }}"
echo "STAPLED_APP_ZIP=${{ steps.sign-and-notarize.outputs.zip-package-path }}" >> "$GITHUB_ENV"
shell: bash
# Upload the ZIP archive from the macos-notarize action
- name: Upload Stapled App ZIP Archive
uses: actions/upload-artifact@v3
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none'
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != ''
with:
name: LuckyWorld-macOS-Stapled-ZIP
path: ${{ env.STAPLED_APP_ZIP }}
path: ${{ steps.sign-and-notarize.outputs.zip-package-path }}
retention-days: 30
# Upload the DMG file
# Upload the DMG file from the macos-notarize action
- name: Upload Stapled App DMG
uses: actions/upload-artifact@v3
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none'
with:
name: LuckyWorld-macOS-Stapled-DMG
path: ${{ env.STAPLED_APP_DMG }}
path: ${{ steps.sign-and-notarize.outputs.package-path }}
retention-days: 30
# Upload signed app (might be DMG or other package format)