diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index f6fa982a..2c22adc6 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -22,6 +22,9 @@ jobs: WORKSPACE_DIR="$(pwd)" echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" echo "ENTITLEMENTS_FILE=LuckyWorld.entitlements" >> "$GITHUB_ENV" + + # Set CI environment variable to true for build script + echo "CI=true" >> "$GITHUB_ENV" # Create directories for builds mkdir -p Builds/Mac @@ -58,6 +61,8 @@ jobs: 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 else echo "ERROR: Build script not found at ./scripts/mac_build.sh" diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index d8b46c43..9f500dc8 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -13,20 +13,34 @@ PROJECT_ROOT="$(pwd)" PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject" ARCHIVE_DIR="$PROJECT_ROOT/Builds" +# Check if running in CI environment +if [ -n "$GITHUB_ACTIONS" ] || [ -n "$CI" ]; then + # Skip certificate check in CI environment + echo "🔄 Running in CI environment, skipping certificate checks" + RUNNING_IN_CI=true +else + RUNNING_IN_CI=false +fi + # 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 [ "$RUNNING_IN_CI" = "false" ]; then + # Only check for certificate in non-CI environments 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" + # 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 + echo "Continuing build without signing..." + else + echo "🔑 Found Developer ID certificate: $CERTIFICATE_NAME" + fi fi +else + echo "🔄 Skipping local certificate check - signing will be handled in CI pipeline" fi # Check for entitlements file @@ -44,7 +58,11 @@ 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" +if [ "$RUNNING_IN_CI" = "false" ] && [ -n "$CERTIFICATE_NAME" ]; then + echo "Signing with certificate: $CERTIFICATE_NAME" +else + echo "Not signing locally - will be handled in CI" +fi # Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved @@ -146,116 +164,118 @@ if [ -n "$APP_PATH" ]; then fi fi -# 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 - - # First calculate total file count - # Find all binary files (executables, dylibs, .so files, frameworks) - echo "Scanning for binary files..." - - # Executable binary files (libraries, executables) - binaries=$(find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm +111 \) | sort) - total=$(echo "$binaries" | wc -l) - - echo "Found $total binary files to sign" - - # 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)) +# Only perform signing if not in CI and certificate is available +if [ "$RUNNING_IN_CI" = "false" ] && [ -n "$CERTIFICATE_NAME" ] && [ -n "$ENTITLEMENTS_FILE" ]; then + # 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 - # Show progress every 20 files - if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then - echo "Progress: $counter/$total - Signing: $binary" + # First calculate total file count + # Find all binary files (executables, dylibs, .so files, frameworks) + echo "Scanning for binary files..." + + # Executable binary files (libraries, executables) + binaries=$(find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm +111 \) | sort) + total=$(echo "$binaries" | wc -l) + + echo "Found $total binary files to sign" + + # 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)) + + # Show progress every 20 files + if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then + echo "Progress: $counter/$total - Signing: $binary" + fi + + # Skip if not a regular file (symbolic links etc) + if [ ! -f "$binary" ]; then + continue + fi + + # Check file type + file_info=$(file "$binary") + + # Only sign Mach-O files + if ! echo "$file_info" | grep -q "Mach-O"; then + continue + fi + + if [[ "$binary" == *CrashReportClient* ]]; then + echo "🛠️ Special handling for CrashReportClient: $binary" + fi + + # 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 + + # Show ENTITLEMENTS content for reference + echo "Using entitlements file for signatures:" + cat "$entitlements_file" + + # Find all nested apps and sign them + nested_apps=$(find "$app_path" -name "*.app" -type d) + + if [ -n "$nested_apps" ]; then + echo "Signing nested applications..." + echo "$nested_apps" | while read -r nested_app; do + if [ "$nested_app" != "$app_path" ]; then + echo "Signing nested app: $nested_app" + + # 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 "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { + echo "⚠️ Failed to sign nested app: $nested_app" + failed=$((failed + 1)) + } + fi + done fi - # Skip if not a regular file (symbolic links etc) - if [ ! -f "$binary" ]; then - continue - fi - - # Check file type - file_info=$(file "$binary") - - # Only sign Mach-O files - if ! echo "$file_info" | grep -q "Mach-O"; then - continue - fi - - if [[ "$binary" == *CrashReportClient* ]]; then - echo "🛠️ Special handling for CrashReportClient: $binary" - fi - - # 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" + # Sign the main application + echo "Signing main application: $app_path" + 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)) } - done - - # Show ENTITLEMENTS content for reference - echo "Using entitlements file for signatures:" - cat "$entitlements_file" - - # Find all nested apps and sign them - nested_apps=$(find "$app_path" -name "*.app" -type d) - - if [ -n "$nested_apps" ]; then - echo "Signing nested applications..." - echo "$nested_apps" | while read -r nested_app; do - if [ "$nested_app" != "$app_path" ]; then - echo "Signing nested app: $nested_app" - - # 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 "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { - echo "⚠️ Failed to sign nested app: $nested_app" - failed=$((failed + 1)) - } - fi - done - fi - - # Sign the main application - echo "Signing main application: $app_path" - 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" + + # Check signing status + echo "Verifying signatures..." + codesign -vvv --deep --strict "$app_path" + + # Check Hardened Runtime and other security settings + echo "Checking security settings (Hardened Runtime, etc.):" + codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" + + # 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:" + codesign -d --entitlements - "$crash_reporter" | grep -i "runtime\|hardened\|security" + fi } - - echo "✅ Signing completed: $counter files processed, $failed failures" - - # Check signing status - echo "Verifying signatures..." - codesign -vvv --deep --strict "$app_path" - - # Check Hardened Runtime and other security settings - echo "Checking security settings (Hardened Runtime, etc.):" - codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" - - # 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:" - codesign -d --entitlements - "$crash_reporter" | grep -i "runtime\|hardened\|security" - fi -} -# 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 + # Check libraries and perform post-processing if needed + echo "" + echo "🔍 Performing comprehensive signing and hardening of all binaries..." + # Sign all binary files recursively sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" "$CERTIFICATE_NAME" @@ -280,9 +300,15 @@ if [ -n "$APP_PATH" ] && [ -n "$ENTITLEMENTS_FILE" ]; then 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" - echo "Entitlements file: $ENTITLEMENTS_FILE" + # Skip signing locally - CI will handle it + if [ "$RUNNING_IN_CI" = "true" ]; then + echo "Skipping local signing - CI pipeline will handle signing and notarization" + else + echo "❌ Local signing skipped - certificate or entitlements file not available" + echo "App path: $APP_PATH" + echo "Entitlements file: $ENTITLEMENTS_FILE" + echo "Certificate: $CERTIFICATE_NAME" + fi fi echo ""