name: Test macOS Signing on: push: branches: [ozgur/build] workflow_dispatch: # Manual trigger is also available jobs: test-signing: runs-on: macos steps: - name: Create Entitlements File run: | # Create entitlements file inline cat > LuckyRobots.entitlements << EOF com.apple.security.cs.allow-jit com.apple.security.cs.allow-unsigned-executable-memory com.apple.security.cs.disable-library-validation com.apple.security.cs.allow-dyld-environment-variables com.apple.security.device.audio-input com.apple.security.device.camera EOF echo "Created entitlements file:" cat LuckyRobots.entitlements shell: bash - name: Download and Extract Artifact id: extract-artifact run: | # Working with absolute paths to eliminate path inconsistencies WORKSPACE_DIR="$(pwd)" BUILDS_DIR="$WORKSPACE_DIR/Builds" EXTRACT_DIR="$WORKSPACE_DIR/temp_extract" # Create directories mkdir -p "$BUILDS_DIR/Mac" mkdir -p "$EXTRACT_DIR" # Download specific artifact echo "Downloading build artifact..." # Use fixed artifact URL ARTIFACT_URL="https://luckyrobots.com/LuckyRobots/LuckyWorld/actions/runs/84/artifacts/LuckyRobots-macOS" echo "Using artifact URL: $ARTIFACT_URL" BUILD_ZIP="$WORKSPACE_DIR/build.zip" # Download the artifact curl -L "$ARTIFACT_URL" -o "$BUILD_ZIP" # First unzip - Outer artifact zip file echo "Extracting outer zip file..." unzip -o "$BUILD_ZIP" -d "$EXTRACT_DIR" # List the contents of temp_extract echo "Contents of temp_extract:" ls -la "$EXTRACT_DIR" # Handle case where the artifact might have different structure # Try to find any zip files recursively echo "Searching for zip files in extract directory..." ZIP_FILES=$(find "$EXTRACT_DIR" -name "*.zip" -type f) echo "Found ZIP files: $ZIP_FILES" # Create target directory for Mac app TARGET_DIR="$BUILDS_DIR/Mac" mkdir -p "$TARGET_DIR" # Extract all found zip files for ZIP_FILE in $ZIP_FILES; do echo "Extracting: $ZIP_FILE to $TARGET_DIR" unzip -o "$ZIP_FILE" -d "$TARGET_DIR" done # Look for LuckyWorld-Mac-Shipping.app specifically if [ -d "$TARGET_DIR/LuckyWorld-Mac-Shipping.app" ]; then APP_PATH="$TARGET_DIR/LuckyWorld-Mac-Shipping.app" echo "Found specific app: $APP_PATH" else # Try to find any .app bundle recursively echo "Searching for .app bundles in all directories..." APP_PATH=$(find "$BUILDS_DIR" -name "*.app" -type d | head -1) if [ -z "$APP_PATH" ]; then echo "Could not find any .app bundle. Looking in other directories..." APP_PATH=$(find "$WORKSPACE_DIR" -name "*.app" -type d | head -1) fi fi if [ -z "$APP_PATH" ]; then echo "ERROR: Could not find any .app bundle" echo "Contents of Builds directory:" find "$BUILDS_DIR" -type d | sort echo "Contents of extracted files:" find "$EXTRACT_DIR" -type f | sort exit 1 fi echo "Found app bundle at: $APP_PATH" echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT shell: bash - name: Setup for Signing id: setup-signing env: APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} run: | # Decode the base64 certificate echo "$APPLE_CERTIFICATE_BASE64" | base64 --decode > certificate.p12 # Create keychain and import certificate KEYCHAIN_PATH="signing-keychain.keychain-db" KEYCHAIN_PASSWORD="temporary" # Create custom keychain security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Download Apple root certificates echo "Downloading Apple Developer certificates..." curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer # Import all certificates to our custom keychain security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" # Set keychain for signing security list-keychain -d user -s "$KEYCHAIN_PATH" security default-keychain -s "$KEYCHAIN_PATH" # Always trust our certificates security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Setup API key echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > api_key.p8 echo "keychain_path=$KEYCHAIN_PATH" >> $GITHUB_OUTPUT echo "keychain_password=$KEYCHAIN_PASSWORD" >> $GITHUB_OUTPUT echo "api_key_path=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT shell: bash - name: Sign macOS App id: sign-app env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | APP_PATH="${{ steps.extract-artifact.outputs.app_path }}" echo "Signing app bundle: $APP_PATH" # First, handle problematic libraries separately find "$APP_PATH" -name "*.dylib" | while read DYLIB; do echo "Signing library: $DYLIB" codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$DYLIB" done # Now sign the application itself echo "Signing main application bundle..." /usr/bin/codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements ./LuckyRobots.entitlements "$APP_PATH" # Verify signature echo "Verifying signature..." codesign --verify --verbose "$APP_PATH" echo "App signing completed successfully" echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT shell: bash - name: Notarize macOS App run: | # Create a temporary file for notarization APP_PATH="${{ steps.sign-app.outputs.app_path }}" NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" # Get API key path from previous step API_KEY_PATH="${{ steps.setup-signing.outputs.api_key_path }}" # Submit for notarization using API key echo "Submitting for notarization with API key..." xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_PATH" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait # Staple the ticket to the application xcrun stapler staple "$APP_PATH" # Clean up the API key file rm -f "$API_KEY_PATH" rm -f "$NOTARIZE_APP_PATH" shell: bash - name: Package macOS App run: | # Package the signed and notarized app APP_PATH="${{ steps.sign-app.outputs.app_path }}" APP_NAME=$(basename "$APP_PATH") WORKSPACE_DIR="$(pwd)" OUTPUT_DIR="$WORKSPACE_DIR/TestSignedApps" # Create test output directory mkdir -p "$OUTPUT_DIR" echo "Creating test package..." ditto -c -k --keepParent "$APP_PATH" "$OUTPUT_DIR/Test-$APP_NAME.zip" echo "Created test package: $OUTPUT_DIR/Test-$APP_NAME.zip" echo "Test packaged apps:" ls -la "$OUTPUT_DIR" shell: bash - name: Upload Test Signed App uses: actions/upload-artifact@v3 if: success() with: name: TestSigned-macOS-App path: TestSignedApps/Test-*.zip retention-days: 7 - name: Cleanup if: always() run: | # Clean up keychain KEYCHAIN_PATH="${{ steps.setup-signing.outputs.keychain_path }}" if [ -n "$KEYCHAIN_PATH" ]; then security delete-keychain "$KEYCHAIN_PATH" || true fi # Clean up temp files rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer || true shell: bash