From 567ef909f8eea4e55cd4f0949913e4170284e40b Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 16:04:47 +0200 Subject: [PATCH] fix(workflows): update macOS build workflow to enable push triggers and refine local signing process --- .gitea/workflows/test-local-signing.yml | 4 +- .gitea/workflows/test-macos-build.yml | 358 ++++++------------------ 2 files changed, 89 insertions(+), 273 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 4cf4cfbd..1459312a 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -2,8 +2,8 @@ name: Test Local Signing on: workflow_dispatch: # Manual trigger - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: test-local-signing: diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 48c376d7..75679e6c 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -2,8 +2,8 @@ name: Test macOS Build Action on: workflow_dispatch: # Manual trigger only for testing - # push: - # branches: [ozgur/build] + push: + branches: [ozgur/build] jobs: test-macos-build: @@ -14,301 +14,117 @@ jobs: with: lfs: true fetch-depth: 0 - - - name: Check entitlements file - run: | - # Check if entitlements files exist - if [ -f "LuckyWorld.entitlements" ]; then - echo "Using existing LuckyWorld.entitlements file" - ENTITLEMENTS_FILE="LuckyWorld.entitlements" - else - echo "Creating default entitlements file as LuckyWorld.entitlements" - # Create entitlements file line by line instead of heredoc - echo '' > LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.allow-jit' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.allow-unsigned-executable-memory' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.disable-library-validation' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.allow-dyld-environment-variables' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.device.audio-input' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.device.camera' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - ENTITLEMENTS_FILE="LuckyWorld.entitlements" - fi - - echo "Using entitlements file: $ENTITLEMENTS_FILE" - echo "ENTITLEMENTS_FILE=$ENTITLEMENTS_FILE" >> "$GITHUB_ENV" - shell: bash - - # Step 1: Setup environment + + # Setup environment for build - name: Setup environment run: | - # Use the correct path where Unreal Engine is installed - UE_PATH="/Users/Shared/Epic Games/UE_5.5" - - if [ ! -d "$UE_PATH" ]; then - echo "Warning: Unreal Engine is not installed in the expected location" - echo "This is expected in CI environment - continuing anyway" - fi - + # Get the working directory path for absolute paths + WORKSPACE_DIR="$(pwd)" + echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" + echo "ENTITLEMENTS_FILE=LuckyWorld.entitlements" >> "$GITHUB_ENV" + # Create directories for builds mkdir -p Builds/Mac mkdir -p PackagedReleases - echo "Using Unreal Engine 5.5" - - # Get the working directory path for absolute paths - WORKSPACE_DIR="$(pwd)" - echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" + echo "Environment setup complete" shell: bash - # Step 2: Build for macOS + # Build for macOS - use your own build script or create a test app if needed - name: Build for macOS run: | if [ -f "./scripts/mac_build.sh" ]; then chmod +x ./scripts/mac_build.sh ./scripts/mac_build.sh else - echo "Build script not found, skipping this step" + echo "ERROR: Build script not found at ./scripts/mac_build.sh" + exit 1 fi shell: bash - - - # Step 3: Enhanced Debug for Certificate Import - - name: Debug Certificate Import - env: - CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + + # Find the app bundle + - name: Find app bundle run: | - # Debug: Print working directory and available resources - echo "Current working directory: $(pwd)" - echo "Contents of Saved/StagedBuilds directory (if exists):" - find ./Saved -type d -name "*.app" 2>/dev/null || echo "No .app bundles found in Saved/" - - # Checking system keychains - echo "Examining system keychains and certificates..." - security list-keychains - security default-keychain - - # Decode certificate and examine format - DEBUG - echo "Decoding certificate to debug..." - CERT_DIR="$HOME/certificates" - mkdir -p "$CERT_DIR" - CERT_PATH="$CERT_DIR/developer_certificate.p12" - echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" - - # Check if certificate was properly decoded - if [ -f "$CERT_PATH" ]; then - echo "Certificate was decoded, size: $(wc -c < "$CERT_PATH") bytes" - echo "Certificate file type: $(file "$CERT_PATH")" + if [ -z "$APP_PATH" ]; then + # 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) + + # If not found, check Builds directory + if [ -z "$APP_PATHS" ]; then + echo "Checking Builds directory..." + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) + fi + + # If still not found, check the whole workspace + if [ -z "$APP_PATHS" ]; then + echo "Checking entire workspace..." + APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) + 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" + echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" else - echo "ERROR: Failed to decode certificate" + echo "App path already set: $APP_PATH" + fi + + # Make sure app exists + if [ ! -d "$APP_PATH" ]; then + echo "ERROR: App bundle not found at $APP_PATH!" exit 1 fi - - # Trying import with different methods - echo "ATTEMPT 1: Using login keychain" - KEYCHAIN_PASSWORD="$(security find-generic-password -a ${USER} -s login -w)" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" login.keychain - security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k login.keychain -T /usr/bin/codesign || echo "Import to login keychain failed" - - echo "ATTEMPT 2: Creating custom keychain" - CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" - CUSTOM_PASSWORD="temppassword123" - security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - security default-keychain -s "$CUSTOM_KEYCHAIN" - security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign || echo "Import to custom keychain failed" - - # Add to search list - security list-keychains -d user -s "$CUSTOM_KEYCHAIN" login.keychain - security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - - # Check available identities in both keychains - echo "Checking login keychain for identities:" - security find-identity -v -p codesigning login.keychain || echo "No identities in login keychain" - - echo "Checking custom keychain for identities:" - security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" || echo "No identities in custom keychain" - - # Fallback solution - use adhoc signing for testing - echo "FALLBACK: Setting up adhoc signing option" - echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" - echo "DIRECT_SIGNING_AVAILABLE=false" >> "$GITHUB_ENV" - - # For debugging only, use a specific team ID if needed - echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" shell: bash - # Step 4: Find and prep app for signing - - name: Find and prep app for signing - run: | - # 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) - - # If not found, check Builds directory - if [ -z "$APP_PATHS" ]; then - echo "Checking Builds directory..." - APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) - fi - - # If still not found, check the whole workspace - if [ -z "$APP_PATHS" ]; then - echo "Checking entire workspace..." - APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) - 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) - - # Get app name for later use - APP_NAME=$(basename "$MAIN_APP_PATH") - - echo "Using app bundle: $MAIN_APP_PATH" - echo "App name: $APP_NAME" - - echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" - echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" - shell: bash - - # Step 5: Sign application with alternative fallback - - name: Sign application - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - # Debug info - echo "Signing app bundle: $APP_PATH" - echo "Using entitlements file: $ENTITLEMENTS_FILE" - - # Sign the app with ad-hoc identity - echo "🔏 Signing app with ad-hoc identity..." - /usr/bin/codesign --force --sign - --timestamp --options runtime --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" - - # Verify signing - echo "🔍 Verifying signature..." - codesign -vvv --deep --strict "$APP_PATH" - - # Check entitlements - echo "🔍 Checking entitlements..." - codesign -d --entitlements - "$APP_PATH" - - echo "✅ Ad-hoc signing completed for testing purposes" - echo "NEEDS_REAL_CERT=true" >> "$GITHUB_ENV" - shell: bash - - # Step 6: Create Reference Script for Production Signing - - name: Create Production Signing Reference - run: | - echo "📝 Creating reference script for production code signing..." - - cat > sign_and_notarize_production.sh << 'EOF' - #!/bin/bash - # Sign and notarize macOS application - # This script is a reference for using a real Developer ID certificate - - # Configuration (replace with your values) - APP_PATH="LuckyWorld-Mac-Shipping.app" # Your app path - TEAM_ID="${APPLE_TEAM_ID}" # Your Apple Team ID - BUNDLE_ID="com.luckyworld.game" # Your app bundle ID - ENTITLEMENTS_PATH="LuckyWorld.entitlements" # Your entitlements file - APPLE_ID="${APPLE_NOTARY_USER}" # Your Apple ID - APP_PASSWORD="${APPLE_NOTARY_PASSWORD}" # Your app-specific password - - # Step 1: Check for Developer ID Application certificate - echo "Checking for Developer ID Application certificate..." - IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') - - if [ -z "$IDENTITY" ]; then - echo "Error: No Developer ID Application certificate found" - echo "Please create a Developer ID Application certificate in your Apple Developer account" - echo "and install it in your keychain" - exit 1 - fi - - echo "Using identity: $IDENTITY" - - # Step 2: Sign the app - echo "Signing app..." - codesign --force --options runtime --entitlements "$ENTITLEMENTS_PATH" \ - --sign "$IDENTITY" --timestamp "$APP_PATH" - - # Step 3: Verify signing - echo "Verifying signature..." - codesign -vvv --deep --strict "$APP_PATH" - - # Step 4: Create zip for notarization - echo "Creating zip for notarization..." - ZIP_PATH="${APP_PATH%.app}-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" - - # Step 5: Submit for notarization - echo "Submitting for notarization..." - xcrun notarytool submit "$ZIP_PATH" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$TEAM_ID" \ - --wait - - # Step 6: Staple the notarization ticket - echo "Stapling notarization ticket..." - xcrun stapler staple "$APP_PATH" - - # Step 7: Verify notarization - echo "Verifying notarization..." - spctl --assess --verbose --type exec "$APP_PATH" - - # Step 8: Create final distribution zip - echo "Creating final distribution zip..." - FINAL_ZIP="${APP_PATH%.app}-macOS-Signed.zip" - ditto -c -k --keepParent "$APP_PATH" "$FINAL_ZIP" - - echo "✅ App successfully signed and notarized!" - echo "Final package: $FINAL_ZIP" - EOF - - chmod +x sign_and_notarize_production.sh - echo "✅ Created reference script for production code signing" - shell: bash - - # Step 9: Upload test artifact - - name: Upload Test Build Artifact - uses: actions/upload-artifact@v3 - if: success() + # Use the macos-notarize action to sign and notarize the app + - name: Sign and Notarize macOS App + uses: ./.gitea/actions/macos-notarize + id: sign-and-notarize with: - name: LuckyWorld-macOS-UNSIGNED-TEST - path: PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip + app-path: ${{ env.APP_PATH }} + entitlements-file: ${{ env.ENTITLEMENTS_FILE }} + team-id: ${{ secrets.APPLE_TEAM_ID }} + certificate-base64: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + notarization-method: 'api-key' + notary-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} + notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + notary-api-key-path: ${{ secrets.NOTARY_API_KEY_CONTENT }} + bundle-id: 'com.luckyrobots.luckyworld' + fallback-to-adhoc: 'true' + + # Upload signed app if available + - name: Upload Signed App + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.signed != 'none' + with: + name: LuckyWorld-macOS-Signed + path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 7 - # Step 10: Cleanup - - name: Cleanup - if: always() + # Report results + - name: Report Results run: | - # Clean up keychain and certificates - rm -rf "$HOME/certificates" || true - security delete-keychain "$HOME/certificates/build.keychain" || true + echo "🔐 App signing: ${{ steps.sign-and-notarize.outputs.signed }}" + echo "🔏 App notarization: ${{ steps.sign-and-notarize.outputs.notarized }}" - echo "Cleanup complete" + if [ "${{ steps.sign-and-notarize.outputs.signed }}" != "none" ]; then + echo "✅ Packaging completed successfully!" + echo "Final package: ${{ steps.sign-and-notarize.outputs.package-path }}" + else + echo "⚠️ App was not signed - check the logs for details" + fi shell: bash \ No newline at end of file