LuckyWorld/.gitea/workflows/macos-build.yml
Ozgur Ersoy c1f7010a92
All checks were successful
macOS Build, Sign and Notarize / build-sign-notarize (push) Successful in 45m49s
fix(actions): enhance macOS notarization workflow by adding detailed status reporting and quarantine checks for improved application security
2025-04-17 18:48:19 +02:00

671 lines
29 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: macOS Build, Sign and Notarize
on:
workflow_dispatch: # Manuel tetikleme
push:
branches: [ozgur/build]
jobs:
build-sign-notarize:
runs-on: macos
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
lfs: true
fetch-depth: 0
- name: Setup environment
run: |
# Çalışma dizini yolunu al
WORKSPACE_DIR="$(pwd)"
echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV"
echo "ENTITLEMENTS_FILE=LuckyWorld.entitlements" >> "$GITHUB_ENV"
# CI ortam değişkenini true olarak ayarla
echo "CI=true" >> "$GITHUB_ENV"
# Build için gerekli dizinleri oluştur
mkdir -p Builds/Mac
mkdir -p PackagedReleases
mkdir -p ArchivedApps
echo "Environment setup complete"
shell: bash
- name: Setup Certificate and Keychain
id: setup-cert
shell: bash
env:
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
echo "🔐 Setting up certificate..."
# Create a temporary directory for certificates
CERT_DIR="$HOME/certificates"
mkdir -p "$CERT_DIR"
# Decode the certificate to a p12 file
echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12"
# Create keychain
KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db"
KEYCHAIN_PASSWORD="temppassword123"
# Delete existing keychain if it exists
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
# Create new keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Add to search list and make default
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"')
security default-keychain -s "$KEYCHAIN_PATH"
# Import certificate
echo "🔑 Importing developer certificate..."
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
# Try with additional parameters if needed
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 || true
# Set partition list for codesign to access keychain
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Verify certificate
echo "🔍 Verifying code signing identities..."
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
# Try to use the System keychain as a fallback
echo "🔍 Checking system keychain for code signing identities..."
SYSTEM_IDENTITIES=$(security find-identity -v -p codesigning)
echo "$SYSTEM_IDENTITIES"
if echo "$SYSTEM_IDENTITIES" | grep -q "Developer ID Application"; then
echo "✅ Found Developer ID Application certificate in system keychain"
echo "::set-output name=use_system_cert::true"
else
echo "::set-output name=use_system_cert::false"
fi
# Store keychain variables for later steps
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> $GITHUB_ENV
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV
echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> $GITHUB_ENV
# Clean up
rm -f "$CERT_DIR/certificate.p12"
- name: Build for macOS
id: build
run: |
if [ -f "./scripts/mac_build.sh" ]; then
chmod +x ./scripts/mac_build.sh
# Set CI environment variable explicitly before running
export CI=true
./scripts/mac_build.sh
# Check if the build succeeded by looking for the app
APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null || echo "")
if [ -z "$APP_PATHS" ]; then
APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null || echo "")
fi
if [ -z "$APP_PATHS" ]; then
echo "❌ ERROR: Build command appeared to succeed but no app bundle was found!"
echo "This usually means the build failed but didn't properly return an error code."
exit 1
fi
else
echo "ERROR: Build script not found at ./scripts/mac_build.sh"
exit 1
fi
shell: bash
- name: Find app bundle
id: find-app
run: |
# Add error handling
set +e # Don't exit immediately on error for this block
echo "Build status check..."
if [ ! -d "./Builds" ] && [ ! -d "./Saved/StagedBuilds" ]; then
echo "❌ ERROR: Build directories do not exist. Build likely failed."
exit 1
fi
# First check Saved/StagedBuilds directory - where Unreal often places built apps
echo "Checking Saved/StagedBuilds directory..."
APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null || echo "")
# If not found, check Builds directory
if [ -z "$APP_PATHS" ]; then
echo "No app found in Saved/StagedBuilds, checking Builds directory..."
APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null || echo "")
fi
# If still not found, check the whole workspace
if [ -z "$APP_PATHS" ]; then
echo "No app found in Builds, checking entire workspace..."
APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null || echo "")
fi
if [ -z "$APP_PATHS" ]; then
echo "❌ ERROR: Could not find any app bundles!"
echo "Listing all directories to help debug:"
find . -type d -maxdepth 3 | sort
exit 1
fi
echo "Found potential app bundles:"
echo "$APP_PATHS"
# Use the first app path found (preferably the main app, not a child app)
MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1)
echo "Using app bundle: $MAIN_APP_PATH"
# Make sure app exists - using local variable
if [ ! -d "$MAIN_APP_PATH" ]; then
echo "❌ ERROR: App bundle not found at $MAIN_APP_PATH!"
exit 1
fi
# Export APP_PATH for next steps to use
echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV"
# Get bundle ID from Info.plist for reference (not modifying)
if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then
BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")
echo "Detected bundle ID: $BUNDLE_ID"
echo "BUNDLE_ID=$BUNDLE_ID" >> "$GITHUB_ENV"
fi
shell: bash
- name: Sign App
id: sign
shell: bash
run: |
echo "🔏 Signing app with Developer ID certificate..."
# Check if app path exists
if [ ! -d "${{ env.APP_PATH }}" ]; then
echo "❌ App bundle not found at ${{ env.APP_PATH }}"
echo "::set-output name=signed::none"
exit 1
fi
# Check if entitlements file exists
if [ ! -f "${{ env.ENTITLEMENTS_FILE }}" ]; then
echo "❌ Entitlements file not found at ${{ env.ENTITLEMENTS_FILE }}"
echo "::set-output name=signed::none"
exit 1
fi
# 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 [ -z "$IDENTITY_HASH" ]; then
echo "❌ No valid Developer ID Application certificate found"
echo "Falling back to ad-hoc signing for testing..."
# Use ad-hoc identity as fallback
codesign --force --deep --verbose --options runtime --entitlements "${{ env.ENTITLEMENTS_FILE }}" --sign - --timestamp "${{ env.APP_PATH }}"
echo "::set-output name=signed::adhoc"
else
echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH"
# Enhanced deep recursive signing for all binaries
echo "🔍 Performing deep recursive signing of all components..."
# First, find all .dylib files and sign them individually
echo "Signing all dynamic libraries (.dylib files)..."
find "${{ env.APP_PATH }}" -name "*.dylib" | while read -r dylib; do
echo "Signing: $dylib"
codesign --force --verbose --options runtime --entitlements "${{ env.ENTITLEMENTS_FILE }}" --sign "$IDENTITY_HASH" --timestamp "$dylib" || echo "⚠️ Failed to sign: $dylib"
done
# Sign all .so files
echo "Signing all shared objects (.so files)..."
find "${{ env.APP_PATH }}" -name "*.so" | while read -r so; do
echo "Signing: $so"
codesign --force --verbose --options runtime --entitlements "${{ env.ENTITLEMENTS_FILE }}" --sign "$IDENTITY_HASH" --timestamp "$so" || echo "⚠️ Failed to sign: $so"
done
# Sign all executable files (files with execute permission)
echo "Signing all executable files..."
find "${{ env.APP_PATH }}" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read -r exe; do
echo "Signing executable: $exe"
codesign --force --verbose --options runtime --entitlements "${{ env.ENTITLEMENTS_FILE }}" --sign "$IDENTITY_HASH" --timestamp "$exe" || echo "⚠️ Failed to sign: $exe"
done
# Sign all frameworks
echo "Signing frameworks..."
find "${{ env.APP_PATH }}" -path "*.framework" -type d | while read -r framework; do
echo "Signing framework: $framework"
codesign --force --verbose --options runtime --entitlements "${{ env.ENTITLEMENTS_FILE }}" --sign "$IDENTITY_HASH" --timestamp "$framework" || echo "⚠️ Failed to sign: $framework"
done
# Final signing of the main bundle
echo "🔐 Performing final signing of the main app bundle..."
codesign --force --deep --verbose --options runtime --entitlements "${{ env.ENTITLEMENTS_FILE }}" --sign "$IDENTITY_HASH" --timestamp "${{ env.APP_PATH }}"
echo "::set-output name=signed::identity"
fi
# Verify signing
echo "🔍 Verifying signature..."
codesign -vvv --deep --strict "${{ env.APP_PATH }}"
# Check entitlements
echo "🔍 Checking entitlements..."
codesign -d --entitlements - "${{ env.APP_PATH }}"
- name: Notarize App
id: notarize
if: steps.sign.outputs.signed != 'none'
shell: bash
env:
API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }}
API_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }}
API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }}
run: |
echo "📤 Notarizing app..."
# Set default output
echo "::set-output name=notarized::false"
# Get app name for zip file naming
APP_NAME=$(basename "${{ env.APP_PATH }}" .app)
BUNDLE_ID="${{ env.BUNDLE_ID }}"
# If bundle ID is not provided, try to extract from Info.plist
if [ -z "$BUNDLE_ID" ]; then
if [ -f "${{ env.APP_PATH }}/Contents/Info.plist" ]; then
BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ env.APP_PATH }}/Contents/Info.plist")
echo "Extracted bundle ID: $BUNDLE_ID"
else
BUNDLE_ID="com.luckyrobots.app"
echo "Using default bundle ID: $BUNDLE_ID"
fi
fi
# Check if we're using API key notarization method
if [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then
echo "Using App Store Connect API key for notarization..."
# Create directory for API key if API_KEY_PATH contains content
mkdir -p ~/private_keys
# Check if API_KEY_PATH is a path or content
if [[ "$API_KEY_PATH" == /* ]] && [ -f "$API_KEY_PATH" ]; then
# It's a path to a file
echo "Using API key from path: $API_KEY_PATH"
cp "$API_KEY_PATH" ~/private_keys/AuthKey_${API_KEY_ID}.p8
else
# It contains the key content
echo "Using API key from content"
echo "$API_KEY_PATH" > ~/private_keys/AuthKey_${API_KEY_ID}.p8
fi
# Create zip for notarization
ZIP_PATH="${APP_NAME}-notarize.zip"
ditto -c -k --keepParent "${{ env.APP_PATH }}" "$ZIP_PATH"
echo "Submitting for notarization with API key..."
# First, submit without waiting for completion
SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
--key-id "$API_KEY_ID" \
--issuer "$API_ISSUER_ID" 2>&1)
SUBMIT_STATUS=$?
# Display output for debugging
echo "Notarization submission output:"
echo "$SUBMIT_OUTPUT"
echo "Submission exit status: $SUBMIT_STATUS"
# Check if submission was successful
if [ $SUBMIT_STATUS -ne 0 ]; then
echo "❌ Failed to submit for notarization. Exit code: $SUBMIT_STATUS"
exit 1
fi
# Extract submission ID for log retrieval
SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2)
if [ -z "$SUBMISSION_ID" ]; then
echo "❌ Could not extract submission ID from output. Notarization failed."
exit 1
fi
echo "Submission ID: $SUBMISSION_ID"
echo "Waiting for notarization to complete..."
# Now wait for the processing to complete
COMPLETE=false
MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max)
ATTEMPT=1
while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..."
INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
--key-id "$API_KEY_ID" \
--issuer "$API_ISSUER_ID" 2>&1)
INFO_STATUS=$?
echo "Status check output:"
echo "$INFO_OUTPUT"
# Check if the notarization is complete
if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then
echo "✅ Notarization completed successfully!"
COMPLETE=true
FINAL_STATUS="Accepted"
elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then
echo "❌ Notarization failed with status: Invalid"
COMPLETE=true
FINAL_STATUS="Invalid"
elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then
echo "❌ Notarization failed with status: Rejected"
COMPLETE=true
FINAL_STATUS="Rejected"
else
echo "Notarization still in progress. Waiting 30 seconds before checking again..."
sleep 30
ATTEMPT=$((ATTEMPT + 1))
fi
done
# Handle timeout
if [ "$COMPLETE" = "false" ]; then
echo "❌ Notarization timed out after $MAX_ATTEMPTS attempts."
exit 1
fi
# Handle completed notarization
if [ "$FINAL_STATUS" = "Accepted" ]; then
# Get logs for information (even though successful)
echo "📋 Getting notarization logs for information..."
LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
--key-id "$API_KEY_ID" \
--issuer "$API_ISSUER_ID" 2>&1)
echo "==== NOTARIZATION LOG SUMMARY ===="
echo "$LOGS_OUTPUT" | head -20
echo "=================================="
# Staple the notarization ticket
echo "Stapling notarization ticket..."
xcrun stapler staple -v "${{ env.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 "${{ env.APP_PATH }}"
echo "NOTARIZATION_STATUS=success" >> $GITHUB_ENV
echo "::set-output name=notarized::true"
else
echo "⚠️ Stapling completed with status $STAPLE_STATUS (may still be valid)"
echo "NOTARIZATION_STATUS=partial" >> $GITHUB_ENV
fi
else
# Get detailed logs for failed notarization
echo "📋 Fetching detailed logs for submission ID: $SUBMISSION_ID"
LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
--key-id "$API_KEY_ID" \
--issuer "$API_ISSUER_ID" 2>&1)
echo "==== DETAILED NOTARIZATION LOGS ===="
echo "$LOGS_OUTPUT"
echo "=================================="
echo "NOTARIZATION_STATUS=failed" >> $GITHUB_ENV
echo "❌ Notarization failed with status: $FINAL_STATUS"
exit 1
fi
# Clean up
rm -rf ~/private_keys
else
echo "⚠️ Missing notarization credentials. Skipping notarization."
echo "Set these secrets for notarization:"
echo " - NOTARY_API_KEY_ID: Your API key ID"
echo " - NOTARY_API_KEY_ISSUER_ID: Your API issuer ID"
echo " - NOTARY_API_KEY_PATH: Your p8 file content"
echo "NOTARIZATION_STATUS=skipped" >> $GITHUB_ENV
fi
- name: Create DMG Package
id: package
if: steps.notarize.outputs.notarized == 'true'
shell: bash
run: |
echo "📦 Creating DMG package..."
# Get app name for DMG file naming
APP_NAME=$(basename "${{ env.APP_PATH }}" .app)
# Create a DMG package
DMG_FILE="./PackagedReleases/${APP_NAME}-Signed-Notarized.dmg"
rm -f "$DMG_FILE" 2>/dev/null || true
# Create temporary folder for DMG contents
DMG_TMP_DIR=$(mktemp -d)
cp -R "${{ env.APP_PATH }}" "$DMG_TMP_DIR/"
# 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"
echo "Size: $(du -h "$DMG_FILE" | cut -f1)"
echo "DMG_PATH=$DMG_FILE" >> $GITHUB_ENV
echo "DMG_STATUS=success" >> $GITHUB_ENV
echo "DMG_SIZE=$(du -h "$DMG_FILE" | cut -f1)" >> $GITHUB_ENV
echo "::set-output name=dmg_created::true"
echo "::set-output name=dmg_path::$DMG_FILE"
else
echo "❌ Failed to create DMG package"
echo "DMG_STATUS=failed" >> $GITHUB_ENV
echo "::set-output name=dmg_created::false"
exit 1
fi
# Clean up temporary directory
rm -rf "$DMG_TMP_DIR"
- name: Upload DMG Package
uses: actions/upload-artifact@v3
if: env.DMG_PATH != ''
with:
name: LuckyWorld-macOS-Signed-Notarized
path: ${{ env.DMG_PATH }}
retention-days: 30
- name: Check Quarantine Attributes
id: quarantine
if: steps.notarize.outputs.notarized == 'true'
shell: bash
run: |
echo "🔍 Checking quarantine attributes..."
# Check quarantine attributes on the app
if command -v xattr &> /dev/null; then
QUARANTINE=$(xattr -l "${{ env.APP_PATH }}" | grep -i "quarantine" || echo "None")
if [ "$QUARANTINE" == "None" ]; then
echo "✅ No quarantine attributes found (good)"
echo "QUARANTINE_STATUS=clean" >> $GITHUB_ENV
else
echo "⚠️ Warning: Quarantine attributes found on the app:"
echo "$QUARANTINE"
echo "QUARANTINE_STATUS=present" >> $GITHUB_ENV
fi
# Check for provenance attribute (indicates successful notarization)
PROVENANCE=$(xattr -l "${{ env.APP_PATH }}" | grep -i "com.apple.provenance" || echo "None")
if [ "$PROVENANCE" != "None" ]; then
echo "✅ Provenance attribute found (indicates successful notarization)"
echo "PROVENANCE_STATUS=present" >> $GITHUB_ENV
else
echo "⚠️ Warning: No provenance attribute found - notarization may not be properly attached"
echo "PROVENANCE_STATUS=missing" >> $GITHUB_ENV
fi
else
echo "⚠️ xattr command not available, can't check quarantine status"
echo "QUARANTINE_STATUS=unknown" >> $GITHUB_ENV
echo "PROVENANCE_STATUS=unknown" >> $GITHUB_ENV
fi
# If DMG exists, check it too
if [ -n "$DMG_PATH" ] && [ -f "$DMG_PATH" ]; then
if command -v xattr &> /dev/null; then
DMG_QUARANTINE=$(xattr -l "$DMG_PATH" | grep -i "quarantine" || echo "None")
if [ "$DMG_QUARANTINE" == "None" ]; then
echo "✅ No quarantine attributes found on DMG (good)"
echo "DMG_QUARANTINE_STATUS=clean" >> $GITHUB_ENV
else
echo "⚠️ Warning: Quarantine attributes found on the DMG:"
echo "$DMG_QUARANTINE"
echo "DMG_QUARANTINE_STATUS=present" >> $GITHUB_ENV
fi
fi
fi
- name: Status Report
if: always()
shell: bash
run: |
echo "📋 ========== macOS Build Status Report =========="
echo ""
# App Info
if [ -n "${{ env.APP_PATH }}" ]; then
echo "🔍 Application Info:"
echo " Path: ${{ env.APP_PATH }}"
echo " Bundle ID: ${{ env.BUNDLE_ID || 'Unknown' }}"
if [ -f "${{ env.APP_PATH }}/Contents/Info.plist" ]; then
VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${{ env.APP_PATH }}/Contents/Info.plist" 2>/dev/null || echo "Unknown")
BUILD=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "${{ env.APP_PATH }}/Contents/Info.plist" 2>/dev/null || echo "Unknown")
echo " Version: $VERSION (Build $BUILD)"
fi
else
echo "❌ No application found"
fi
echo ""
# Code Signing Status
echo "🔏 Code Signing Status:"
if [ "${{ steps.sign.outputs.signed }}" == "identity" ]; then
echo " ✅ Successfully signed with Developer ID"
elif [ "${{ steps.sign.outputs.signed }}" == "adhoc" ]; then
echo " ⚠️ Signed ad-hoc (not suitable for distribution)"
else
echo " ❌ Not signed or signing failed"
fi
echo ""
# Notarization Status
echo "🔐 Notarization Status:"
if [ "${{ steps.notarize.outputs.notarized }}" == "true" ]; then
echo " ✅ Successfully notarized and stapled"
elif [ "${{ env.NOTARIZATION_STATUS }}" == "partial" ]; then
echo " ⚠️ Notarized but stapling may have issues"
elif [ "${{ env.NOTARIZATION_STATUS }}" == "skipped" ]; then
echo " ⚠️ Notarization was skipped (missing credentials)"
elif [ "${{ env.NOTARIZATION_STATUS }}" == "failed" ]; then
echo " ❌ Notarization failed"
else
echo " ❓ Notarization status unknown"
fi
# Quarantine Status
if [ -n "${{ env.QUARANTINE_STATUS }}" ]; then
echo ""
echo "🛡️ Quarantine & Security Status:"
if [ "${{ env.QUARANTINE_STATUS }}" == "clean" ]; then
echo " ✅ No quarantine attributes (good)"
elif [ "${{ env.QUARANTINE_STATUS }}" == "present" ]; then
echo " ⚠️ Quarantine attributes present"
else
echo " ❓ Quarantine status unknown"
fi
if [ "${{ env.PROVENANCE_STATUS }}" == "present" ]; then
echo " ✅ Provenance attribute present (indicates successful notarization)"
elif [ "${{ env.PROVENANCE_STATUS }}" == "missing" ]; then
echo " ⚠️ No provenance attribute (might indicate notarization issues)"
fi
fi
# DMG Package Status
echo ""
echo "📦 DMG Package Status:"
if [ "${{ env.DMG_STATUS }}" == "success" ]; then
echo " ✅ DMG created successfully"
echo " 📍 Path: ${{ env.DMG_PATH }}"
echo " 📏 Size: ${{ env.DMG_SIZE || 'Unknown' }}"
if [ "${{ env.DMG_QUARANTINE_STATUS }}" == "clean" ]; then
echo " ✅ DMG has no quarantine attributes (good)"
elif [ "${{ env.DMG_QUARANTINE_STATUS }}" == "present" ]; then
echo " ⚠️ DMG has quarantine attributes"
fi
elif [ "${{ env.DMG_STATUS }}" == "failed" ]; then
echo " ❌ DMG creation failed"
elif [ "${{ steps.package.outputs.dmg_created }}" == "true" ]; then
echo " ✅ DMG created successfully"
echo " 📍 Path: ${{ steps.package.outputs.dmg_path }}"
else
echo " ❓ DMG was not created"
fi
# Artifact Upload Status
echo ""
echo "🚀 Artifact Upload Status:"
if [ -n "${{ env.DMG_PATH }}" ] && [ -f "${{ env.DMG_PATH }}" ]; then
echo " ✅ DMG artifact should be uploaded"
else
echo " ❌ DMG artifact not available for upload"
fi
echo ""
echo "=================================================="
- name: Cleanup
if: always()
shell: bash
run: |
echo "🧹 Cleaning up..."
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
rm -f *-notarize.zip || true
echo "✅ Cleanup complete"