From f28c4a21b5319b46d58035411027e6b65f0f44dc Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 21:20:13 +0200 Subject: [PATCH] fix(actions): enhance notarization script with comprehensive signing and bundle ID updates --- .gitea/actions/macos-notarize/action.yml | 66 +++++++++++++++++- .gitea/workflows/test-macos-build.yml | 88 +++++++++++++++++++++-- LuckyWorld.entitlements | 8 +++ scripts/mac_build.sh | 89 ++++++++++++++++-------- 4 files changed, 215 insertions(+), 36 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 9b06d0e0..1f9c1973 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -177,7 +177,61 @@ runs: else echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH" - # Sign the app bundle using the 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 "${{ inputs.app-path }}" -name "*.dylib" | while read -r dylib; do + echo "Signing: $dylib" + codesign --force --verbose --options runtime --entitlements "${{ inputs.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 "${{ inputs.app-path }}" -name "*.so" | while read -r so; do + echo "Signing: $so" + codesign --force --verbose --options runtime --entitlements "${{ inputs.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 "${{ inputs.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 "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$exe" || echo "⚠️ Failed to sign: $exe" + done + + # Sign all frameworks + echo "Signing frameworks..." + find "${{ inputs.app-path }}" -path "*.framework" -type d | while read -r framework; do + echo "Signing framework: $framework" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$framework" || echo "⚠️ Failed to sign: $framework" + done + + # Special handling for CrashReportClient.app + CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1) + if [ -n "$CRASH_REPORTER" ]; then + echo "🔍 Special handling for CrashReportClient.app: $CRASH_REPORTER" + # Sign CrashReportClient.app specifically with focus on hardened runtime + find "$CRASH_REPORTER" -type f -perm +111 | while read -r crash_bin; do + echo "Signing CrashReportClient binary: $crash_bin" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$crash_bin" || echo "⚠️ Failed to sign: $crash_bin" + done + + echo "Signing the CrashReportClient.app bundle itself..." + codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$CRASH_REPORTER" || echo "⚠️ Failed to sign CrashReportClient.app" + fi + + # Sign any other nested app bundles + find "${{ inputs.app-path }}" -path "*.app" -type d | grep -v CrashReportClient | while read -r nested_app; do + if [ "$nested_app" != "${{ inputs.app-path }}" ]; then + echo "Signing nested app: $nested_app" + codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$nested_app" || echo "⚠️ Failed to sign: $nested_app" + fi + done + + # Final signing of the main bundle + echo "🔐 Performing final signing of the main app bundle..." codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "${{ inputs.app-path }}" echo "::set-output name=signed::identity" fi @@ -189,6 +243,16 @@ runs: # Check entitlements echo "🔍 Checking entitlements..." codesign -d --entitlements - "${{ inputs.app-path }}" + + # Verify CrashReportClient + CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1) + if [ -n "$CRASH_REPORTER" ]; then + echo "🔍 Verifying CrashReportClient signature..." + codesign -vvv --deep --strict "$CRASH_REPORTER" || echo "⚠️ CrashReportClient may have verification issues" + + echo "CrashReportClient entitlements:" + codesign -d --entitlements - "$CRASH_REPORTER" || echo "⚠️ Could not display CrashReportClient entitlements" + fi - name: Notarize App id: notarize diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 887c9046..f6fa982a 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -30,6 +30,29 @@ jobs: echo "Environment setup complete" shell: bash + # Set correct bundle identifier before build + - name: Set bundle identifier + run: | + # Set the correct bundle identifier in DefaultGame.ini if it exists + CONFIG_FILE="Config/DefaultGame.ini" + if [ -f "$CONFIG_FILE" ]; then + # Check if section exists or add it + if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then + # Section exists, update the setting + sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" + else + # Section doesn't exist, add it + echo "" >> "$CONFIG_FILE" + echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" + echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" + fi + echo "Updated bundle ID in project config" + fi + + # Set the constant bundle ID for the workflow + echo "BUNDLE_ID=com.luckyrobots.luckyworld" >> "$GITHUB_ENV" + shell: bash + # Build for macOS - use your own build script or create a test app if needed - name: Build for macOS run: | @@ -86,14 +109,65 @@ jobs: # Export APP_PATH for next steps to use echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" - # Extract bundle ID from Info.plist + # Fix bundle ID in Info.plist before signing 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 from app: $BUNDLE_ID" - echo "BUNDLE_ID=$BUNDLE_ID" >> "$GITHUB_ENV" + echo "Setting bundle identifier to $BUNDLE_ID" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist" + echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")" else - echo "WARNING: Could not find Info.plist in app bundle. Using default bundle ID." - echo "BUNDLE_ID=com.YourCompany.LuckyWorld" >> "$GITHUB_ENV" + echo "WARNING: Could not find Info.plist in app bundle." + fi + + # Find and repair nested app bundles as well (like CrashReportClient.app) + NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d) + if [ -n "$NESTED_APPS" ]; then + echo "Found nested app bundles, fixing their bundle IDs:" + echo "$NESTED_APPS" | while read -r NESTED_APP; do + if [ -f "$NESTED_APP/Contents/Info.plist" ]; then + NESTED_NAME=$(basename "$NESTED_APP" .app) + NESTED_BUNDLE_ID="$BUNDLE_ID.$NESTED_NAME" + echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" + fi + done + fi + shell: bash + + # Fix common issues that may cause notarization failure + - name: Fix common issues for notarization + run: | + echo "🛠️ Fixing common issues that may cause notarization failure..." + + APP_PATH="${{ env.APP_PATH }}" + + # Remove get-task-allow entitlement from Info.plist files + echo "Checking for get-task-allow entitlement..." + find "$APP_PATH" -name "*.plist" -exec plutil -convert xml1 {} \; -exec grep -l "get-task-allow" {} \; | while read -r plist_file; do + echo "Removing get-task-allow from $plist_file" + /usr/libexec/PlistBuddy -c "Delete :com.apple.security.get-task-allow" "$plist_file" 2>/dev/null || true + done + + # Check for problematic libraries that cause issues + echo "Looking for problematic files..." + PROBLEM_FILES=$(find "$APP_PATH" -type f -name "*.dylib" | grep -i "boost\|tbb\|ogg\|vorbis\|onnx") + if [ -n "$PROBLEM_FILES" ]; then + echo "Found potentially problematic libraries. These will be carefully handled during signing:" + echo "$PROBLEM_FILES" | head -10 + if [ $(echo "$PROBLEM_FILES" | wc -l) -gt 10 ]; then + echo "... and $(echo "$PROBLEM_FILES" | wc -l) more" + fi + fi + + # Verify CrashReportClient specifically + CRASH_REPORTER=$(find "$APP_PATH" -path "*CrashReportClient.app*" -type d | head -1) + if [ -n "$CRASH_REPORTER" ]; then + echo "Found CrashReportClient at $CRASH_REPORTER" + if [ -f "$CRASH_REPORTER/Contents/Info.plist" ]; then + # Ensure it has the correct bundle ID format + CRASH_BUNDLE_ID="$BUNDLE_ID.CrashReportClient" + echo "Setting CrashReportClient bundle ID to $CRASH_BUNDLE_ID" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $CRASH_BUNDLE_ID" "$CRASH_REPORTER/Contents/Info.plist" + fi fi shell: bash @@ -112,7 +186,7 @@ jobs: notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} notary-api-key-path: ${{ secrets.NOTARY_API_KEY_PATH }} bundle-id: ${{ env.BUNDLE_ID }} - fallback-to-adhoc: 'true' + fallback-to-adhoc: 'false' # Upload signed app if available - name: Upload Signed App diff --git a/LuckyWorld.entitlements b/LuckyWorld.entitlements index ee35bd86..4dc9a495 100644 --- a/LuckyWorld.entitlements +++ b/LuckyWorld.entitlements @@ -14,5 +14,13 @@ com.apple.security.device.camera + com.apple.security.automation.apple-events + + com.apple.security.cs.debugger + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + \ No newline at end of file diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 7f243488..d8b46c43 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -13,6 +13,22 @@ PROJECT_ROOT="$(pwd)" PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject" ARCHIVE_DIR="$PROJECT_ROOT/Builds" +# Check for Developer ID certificate +CERTIFICATE_NAME="" +if [ -z "$CERTIFICATE_NAME" ]; then + # Try to find a Developer ID Application certificate + CERTIFICATE_NAME=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application.*)"$/\1/') + + if [ -z "$CERTIFICATE_NAME" ]; then + echo "⚠️ No Developer ID Application certificate found. Please specify a valid certificate name." + echo "Available certificates:" + security find-identity -v -p codesigning + exit 1 + else + echo "🔑 Found Developer ID certificate: $CERTIFICATE_NAME" + fi +fi + # Check for entitlements file if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyWorld.entitlements" @@ -28,6 +44,7 @@ echo "Project root: $PROJECT_ROOT" echo "Project file: $PROJECT_FILE" echo "Archive directory: $ARCHIVE_DIR" echo "Entitlements file: $ENTITLEMENTS_FILE" +echo "Signing with certificate: $CERTIFICATE_NAME" # Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved @@ -97,17 +114,17 @@ if [ -n "$APP_PATH" ]; then find "$APP_PATH" -name "*PhysX*" -o -name "*APEX*" fi -# Bundle ID'yi proje ayarlarında güncelle +# Update bundle ID in project settings echo "" echo "🔧 Updating bundle ID in UE config..." CONFIG_FILE="$PROJECT_ROOT/Config/DefaultGame.ini" if [ -f "$CONFIG_FILE" ]; then - # Mevcut bölümü kontrol et veya ekle + # Check if section exists or add it if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then - # Bölüm var, ayarı güncelleyebiliriz + # Section exists, update the setting sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" else - # Bölüm yok, eklememiz gerekiyor + # Section doesn't exist, add it echo "" >> "$CONFIG_FILE" echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" @@ -115,7 +132,7 @@ if [ -f "$CONFIG_FILE" ]; then echo "Updated bundle ID in project config" fi -# Build sonrası işlemler - bundle ID ayarlama +# Post-build process - set bundle ID echo "" echo "🔧 Performing post-build fix for bundle ID..." if [ -n "$APP_PATH" ]; then @@ -129,16 +146,17 @@ if [ -n "$APP_PATH" ]; then fi fi -# Recursive imzalama fonksiyonu - tüm binary dosyaları imzalar +# Recursive signing function - signs all binary files function sign_recursively() { local app_path="$1" local entitlements_file="$2" + local certificate="$3" local counter=0 local total=0 local failed=0 - # Önce toplam dosya sayısını hesapla - # Tüm binary dosyaları bul (executable, dylib, so, çerçeveler) + # First calculate total file count + # Find all binary files (executables, dylibs, .so files, frameworks) echo "Scanning for binary files..." # Executable binary files (libraries, executables) @@ -147,12 +165,12 @@ function sign_recursively() { echo "Found $total binary files to sign" - # Helper binary dosyaları imzala (tercih sırasına göre) + # Sign helper binary files (in order of preference) echo "Signing all binary files (libraries and executables)..." echo "$binaries" | while read -r binary; do counter=$((counter + 1)) - # Her 20 dosyada bir ilerleme göster + # Show progress every 20 files if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then echo "Progress: $counter/$total - Signing: $binary" fi @@ -162,10 +180,10 @@ function sign_recursively() { continue fi - # Dosya türünü kontrol et + # Check file type file_info=$(file "$binary") - # Sadece Mach-O dosyalarını imzala + # Only sign Mach-O files if ! echo "$file_info" | grep -q "Mach-O"; then continue fi @@ -174,18 +192,18 @@ function sign_recursively() { echo "🛠️ Special handling for CrashReportClient: $binary" fi - # Timestamp ve runtime options ile imzala - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { + # Sign with timestamp and runtime options + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { echo "⚠️ Failed to sign: $binary" failed=$((failed + 1)) } done - # Başvuru için ENTITLEMENTS içeriğini göster + # Show ENTITLEMENTS content for reference echo "Using entitlements file for signatures:" cat "$entitlements_file" - # Tüm nested app'leri bul ve imzala + # Find all nested apps and sign them nested_apps=$(find "$app_path" -name "*.app" -type d) if [ -n "$nested_apps" ]; then @@ -194,14 +212,14 @@ function sign_recursively() { if [ "$nested_app" != "$app_path" ]; then echo "Signing nested app: $nested_app" - # İmzalamadan önce Info.plist varsa Bundle ID ayarla + # Set Bundle ID in Info.plist if it exists before signing nested_info="$nested_app/Contents/Info.plist" if [ -f "$nested_info" ]; then echo "Setting bundle identifier for nested app" /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld.nested" "$nested_info" 2>/dev/null || true fi - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { echo "⚠️ Failed to sign nested app: $nested_app" failed=$((failed + 1)) } @@ -209,24 +227,24 @@ function sign_recursively() { done fi - # Asıl uygulamayı imzala + # Sign the main application echo "Signing main application: $app_path" - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { echo "⚠️ Failed to sign main app: $app_path" failed=$((failed + 1)) } echo "✅ Signing completed: $counter files processed, $failed failures" - # İmzalama durumunu kontrol et + # Check signing status echo "Verifying signatures..." codesign -vvv --deep --strict "$app_path" - # Hardened Runtime ve diğer güvenlik ayarları kontrol et + # Check Hardened Runtime and other security settings echo "Checking security settings (Hardened Runtime, etc.):" codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" - # Spesifik olarak CrashReportClient'i kontrol et (sorunlu dosya) + # Check CrashReportClient specifically (problematic file) crash_reporter=$(find "$app_path" -path "*CrashReportClient.app/Contents/MacOS/CrashReportClient" -type f | head -1) if [ -n "$crash_reporter" ]; then echo "Checking CrashReportClient specifically:" @@ -234,18 +252,33 @@ function sign_recursively() { fi } -# Kütüphaneleri kontrol et ve gerekirse post-processing yap +# Check libraries and perform post-processing if needed echo "" echo "🔍 Performing comprehensive signing and hardening of all binaries..." if [ -n "$APP_PATH" ] && [ -n "$ENTITLEMENTS_FILE" ]; then - # Recursive olarak tüm binary dosyaları imzala - sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" + # Sign all binary files recursively + sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" "$CERTIFICATE_NAME" - # Son olarak ana uygulamayı tekrar imzala + # Final signing of the main app bundle echo "Final signing of main app bundle" - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$APP_PATH" + codesign --force --options runtime --deep --sign "$CERTIFICATE_NAME" --timestamp --entitlements "$ENTITLEMENTS_FILE" "$APP_PATH" echo "✅ All binaries signed successfully with Hardened Runtime enabled" + + # Prepare app for notarization + echo "" + echo "🔐 Preparing for notarization..." + + # Create a ZIP archive for notarization + ZIP_PATH="$ARCHIVE_DIR/LuckyWorld.zip" + echo "Creating ZIP archive for notarization: $ZIP_PATH" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + + echo "✅ ZIP archive created for notarization at: $ZIP_PATH" + echo "" + echo "To notarize the app, run the following command:" + echo "xcrun notarytool submit \"$ZIP_PATH\" --apple-id \"YOUR_APPLE_ID\" --password \"APP_SPECIFIC_PASSWORD\" --team-id \"YOUR_TEAM_ID\" --wait" + echo "" else echo "❌ App path or entitlements file not found, cannot perform comprehensive signing" echo "App path: $APP_PATH"