fix(actions): enhance macOS notarization workflow by simplifying action structure, removing unnecessary debug logging steps, and implementing custom DMG creation with installer script
All checks were successful
Test macOS Build Action / test-macos-build (push) Successful in 49m52s
All checks were successful
Test macOS Build Action / test-macos-build (push) Successful in 49m52s
This commit is contained in:
parent
4b7123d9e1
commit
f1c3e9da5a
@ -1,6 +1,6 @@
|
||||
name: "macOS Sign and Notarize"
|
||||
description: "Signs and notarizes macOS applications with Developer ID certificate"
|
||||
author: moersoy"
|
||||
author: moersoy
|
||||
|
||||
inputs:
|
||||
app-path:
|
||||
@ -822,4 +822,3 @@ runs:
|
||||
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
|
||||
rm -f *-notarize.zip || true
|
||||
echo "✅ Cleanup complete"
|
||||
|
@ -15,13 +15,6 @@ jobs:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
# Enable debug logging
|
||||
- name: Enable Debug Logging
|
||||
run: |
|
||||
echo "ACTIONS_RUNNER_DEBUG=true" >> $GITHUB_ENV
|
||||
echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
# Setup environment for build
|
||||
- name: Setup environment
|
||||
run: |
|
||||
@ -152,588 +145,50 @@ jobs:
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
# Create a debug log file for notarize action
|
||||
- name: Create debug log directory
|
||||
run: |
|
||||
mkdir -p debug_logs
|
||||
echo "DEBUG_LOG_PATH=$(pwd)/debug_logs/notarize_log.txt" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
# Beginning of macos-notarize steps
|
||||
- name: Setup debug environment
|
||||
id: setup-debug-env
|
||||
run: |
|
||||
# Create debug directory if env variable is set
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
mkdir -p "$(dirname "$DEBUG_LOG_PATH")"
|
||||
touch "$DEBUG_LOG_PATH"
|
||||
echo "Debug logging enabled to: $DEBUG_LOG_PATH" | tee -a "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
|
||||
# Define debug log helper function
|
||||
echo '
|
||||
# Helper function for debug logging
|
||||
function debug_log() {
|
||||
echo "DEBUG: $1"
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
' > /tmp/debug_helpers.sh
|
||||
chmod +x /tmp/debug_helpers.sh
|
||||
|
||||
# Log debug message directly
|
||||
echo "DEBUG: Starting macOS notarize action"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - Starting macOS notarize action" >> "$DEBUG_LOG_PATH"
|
||||
echo "DEBUG: App path: ${{ env.APP_PATH }}"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - App path: ${{ env.APP_PATH }}" >> "$DEBUG_LOG_PATH"
|
||||
echo "DEBUG: Team ID: ${{ secrets.APPLE_TEAM_ID }}"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - Team ID: ${{ secrets.APPLE_TEAM_ID }}" >> "$DEBUG_LOG_PATH"
|
||||
echo "DEBUG: Notarization method: api-key"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - Notarization method: api-key" >> "$DEBUG_LOG_PATH"
|
||||
echo "DEBUG: Bundle ID: ${{ env.BUNDLE_ID }}"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - Bundle ID: ${{ env.BUNDLE_ID }}" >> "$DEBUG_LOG_PATH"
|
||||
shell: bash
|
||||
|
||||
- name: Set up variables
|
||||
id: setup
|
||||
run: |
|
||||
# Debug log helper
|
||||
function debug_log() {
|
||||
echo "DEBUG: $1"
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
# Debugging info
|
||||
debug_log "Setting up variables"
|
||||
|
||||
# Generate unique name for keychain
|
||||
KEYCHAIN_NAME="build-keychain-$(uuidgen)"
|
||||
KEYCHAIN_PASSWORD="$(uuidgen)"
|
||||
echo "KEYCHAIN_NAME=$KEYCHAIN_NAME" >> $GITHUB_ENV
|
||||
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV
|
||||
|
||||
# Set paths
|
||||
echo "APP_PATH=${{ env.APP_PATH }}" >> $GITHUB_ENV
|
||||
|
||||
# Generate working directory for temp files
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
echo "WORK_DIR=$WORK_DIR" >> $GITHUB_ENV
|
||||
|
||||
# Set bundle id (from input or extract from app)
|
||||
if [[ -n "${{ env.BUNDLE_ID }}" ]]; then
|
||||
BUNDLE_ID="${{ env.BUNDLE_ID }}"
|
||||
else
|
||||
BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ env.APP_PATH }}/Contents/Info.plist")
|
||||
fi
|
||||
echo "BUNDLE_ID=$BUNDLE_ID" >> $GITHUB_ENV
|
||||
|
||||
# Get app name from bundle path
|
||||
APP_NAME=$(basename "${{ env.APP_PATH }}" .app)
|
||||
echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV
|
||||
|
||||
# Set output directory
|
||||
OUTPUT_DIR="$(pwd)/PackagedReleases"
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
echo "OUTPUT_DIR=$OUTPUT_DIR" >> $GITHUB_ENV
|
||||
|
||||
# Set package paths
|
||||
ZIP_PATH="$OUTPUT_DIR/${APP_NAME}.zip"
|
||||
DMG_PATH="$OUTPUT_DIR/${APP_NAME}.dmg"
|
||||
echo "ZIP_PATH=$ZIP_PATH" >> $GITHUB_ENV
|
||||
echo "DMG_PATH=$DMG_PATH" >> $GITHUB_ENV
|
||||
|
||||
# Set notarization variables based on method
|
||||
debug_log "Using API key method for notarization"
|
||||
|
||||
# Create API key file - properly decode from base64
|
||||
API_KEY_FILE="$WORK_DIR/api_key.p8"
|
||||
debug_log "Creating API key file at: $API_KEY_FILE"
|
||||
|
||||
# Check if NOTARY_API_KEY_PATH is provided
|
||||
if [[ -z "${{ secrets.NOTARY_API_KEY_PATH }}" ]]; then
|
||||
debug_log "ERROR: NOTARY_API_KEY_PATH secret is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# First try using the secret directly (assuming it's a PEM key directly)
|
||||
echo "${{ secrets.NOTARY_API_KEY_PATH }}" > "$API_KEY_FILE"
|
||||
|
||||
# Check if it's already in PEM format
|
||||
if grep -q "BEGIN PRIVATE KEY" "$API_KEY_FILE"; then
|
||||
debug_log "Secret is already in PEM format, using directly"
|
||||
else
|
||||
debug_log "Secret is not in PEM format, trying to decode as base64"
|
||||
# Try base64 decoding
|
||||
echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 -D > "$API_KEY_FILE.decoded" 2>/dev/null || true
|
||||
|
||||
# Check if decoded content is PEM
|
||||
if [[ -s "$API_KEY_FILE.decoded" ]] && grep -q "BEGIN PRIVATE KEY" "$API_KEY_FILE.decoded"; then
|
||||
debug_log "Successfully decoded secret from base64 to PEM"
|
||||
mv "$API_KEY_FILE.decoded" "$API_KEY_FILE"
|
||||
else
|
||||
debug_log "ERROR: Secret is neither PEM nor valid base64-encoded PEM"
|
||||
debug_log "Secret starts with: $(head -c 20 "$API_KEY_FILE" | xxd -p)"
|
||||
if [[ -f "$API_KEY_FILE.decoded" ]]; then
|
||||
debug_log "Decoded content starts with: $(head -c 20 "$API_KEY_FILE.decoded" | xxd -p)"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Verify API key file exists and has content
|
||||
if [[ ! -f "$API_KEY_FILE" ]]; then
|
||||
debug_log "ERROR: API key file could not be created"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -s "$API_KEY_FILE" ]]; then
|
||||
debug_log "ERROR: API key file is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get file permissions and size for debugging
|
||||
FILE_PERMS=$(ls -la "$API_KEY_FILE")
|
||||
FILE_SIZE=$(wc -c < "$API_KEY_FILE")
|
||||
debug_log "API key file ($FILE_SIZE bytes): $FILE_PERMS"
|
||||
|
||||
# Set proper permissions
|
||||
chmod 600 "$API_KEY_FILE"
|
||||
|
||||
echo "API_KEY_FILE=$API_KEY_FILE" >> $GITHUB_ENV
|
||||
|
||||
debug_log "API key file created at: $API_KEY_FILE"
|
||||
debug_log "API key ID: ${{ secrets.NOTARY_API_KEY_ID }}"
|
||||
debug_log "API key issuer ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }}"
|
||||
shell: bash
|
||||
|
||||
- name: Setup keychain
|
||||
id: setup-keychain
|
||||
run: |
|
||||
# Debug log helper
|
||||
function debug_log() {
|
||||
echo "DEBUG: $1"
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
debug_log "Setting up keychain"
|
||||
|
||||
# Create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
||||
security default-keychain -s "$KEYCHAIN_NAME"
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
||||
security set-keychain-settings -t 3600 -u "$KEYCHAIN_NAME"
|
||||
|
||||
# Create certificate file
|
||||
CERTIFICATE_PATH="$WORK_DIR/certificate.p12"
|
||||
echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > "$CERTIFICATE_PATH"
|
||||
|
||||
# Add to keychain
|
||||
debug_log "Importing certificate into keychain"
|
||||
security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_NAME" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign
|
||||
|
||||
# Add to search list and set as default
|
||||
security list-keychains -d user -s "$KEYCHAIN_NAME" login.keychain
|
||||
security default-keychain -s "$KEYCHAIN_NAME"
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
||||
|
||||
# Allow codesign to access keychain items without prompting
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
||||
|
||||
# List all identities to find the exact name
|
||||
debug_log "Listing all identities in the keychain:"
|
||||
IDENTITY_INFO=$(security find-identity -v "$KEYCHAIN_NAME")
|
||||
debug_log "$IDENTITY_INFO"
|
||||
|
||||
# Parse the exact identity name from the output
|
||||
EXACT_IDENTITY=$(echo "$IDENTITY_INFO" | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application: .*)"/\1/')
|
||||
|
||||
if [[ -n "$EXACT_IDENTITY" ]]; then
|
||||
debug_log "Found exact identity: $EXACT_IDENTITY"
|
||||
SIGNING_IDENTITY="$EXACT_IDENTITY"
|
||||
echo "SIGNING_IDENTITY=$SIGNING_IDENTITY" >> $GITHUB_ENV
|
||||
echo "CERTIFICATE_AVAILABLE=true" >> $GITHUB_ENV
|
||||
else
|
||||
debug_log "WARNING: No Developer ID Application certificate found"
|
||||
if [[ "false" == "true" ]]; then
|
||||
debug_log "Falling back to ad-hoc signing"
|
||||
echo "CERTIFICATE_AVAILABLE=adhoc" >> $GITHUB_ENV
|
||||
else
|
||||
debug_log "Not falling back to ad-hoc signing as specified"
|
||||
echo "CERTIFICATE_AVAILABLE=false" >> $GITHUB_ENV
|
||||
fi
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Sign application
|
||||
id: sign-app
|
||||
run: |
|
||||
# Debug log helper
|
||||
function debug_log() {
|
||||
echo "DEBUG: $1"
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
debug_log "Starting application signing process"
|
||||
|
||||
# Make sure keychain is unlocked and available
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
||||
security list-keychains
|
||||
security default-keychain
|
||||
|
||||
# Verify certificate exists
|
||||
IDENTITY_INFO=$(security find-identity -v "$KEYCHAIN_NAME")
|
||||
debug_log "$IDENTITY_INFO"
|
||||
|
||||
# Directly extract hash to avoid ambiguity
|
||||
if [[ "$IDENTITY_INFO" =~ ([0-9A-F]{40}) ]]; then
|
||||
HASH_ID="${BASH_REMATCH[1]}"
|
||||
debug_log "Using certificate hash: $HASH_ID"
|
||||
SIGNING_IDENTITY="$HASH_ID" # Use hash directly
|
||||
else
|
||||
# Try to extract certificate name if hash not found
|
||||
EXACT_IDENTITY=$(echo "$IDENTITY_INFO" | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application: .*)"/\1/')
|
||||
if [[ -z "$EXACT_IDENTITY" ]]; then
|
||||
debug_log "ERROR: No Developer ID Application certificate found in keychain"
|
||||
debug_log "$IDENTITY_INFO"
|
||||
echo "SIGNING_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
debug_log "Using certificate identity: $EXACT_IDENTITY"
|
||||
SIGNING_IDENTITY="$EXACT_IDENTITY"
|
||||
fi
|
||||
|
||||
# Check entitlements file and validate it
|
||||
ENTITLEMENTS_PATH="${{ env.ENTITLEMENTS_FILE }}"
|
||||
USE_ENTITLEMENTS=false
|
||||
|
||||
if [[ -f "$ENTITLEMENTS_PATH" ]]; then
|
||||
debug_log "Found entitlements file: $ENTITLEMENTS_PATH - validating..."
|
||||
|
||||
# Try to validate the entitlements file
|
||||
plutil -lint "$ENTITLEMENTS_PATH" > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
debug_log "Entitlements file is valid, will use for signing"
|
||||
USE_ENTITLEMENTS=true
|
||||
else
|
||||
debug_log "WARNING: Entitlements file is invalid, will sign without entitlements"
|
||||
# Print the entitlements file content for debugging
|
||||
debug_log "Entitlements file content:"
|
||||
cat "$ENTITLEMENTS_PATH" | tee -a "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
else
|
||||
debug_log "No entitlements file found at $ENTITLEMENTS_PATH, will sign without entitlements"
|
||||
fi
|
||||
|
||||
# Prepare script and crash entitlements paths
|
||||
SCRIPT_PATH="./scripts/sign_all.sh"
|
||||
CRASH_ENTITLEMENTS_PATH="./scripts/crash_entitlements.plist"
|
||||
|
||||
# Ensure script is executable
|
||||
chmod +x "$SCRIPT_PATH"
|
||||
|
||||
# Log paths
|
||||
debug_log "Sign script path: $SCRIPT_PATH"
|
||||
debug_log "Crash entitlements path: $CRASH_ENTITLEMENTS_PATH"
|
||||
|
||||
# Verify files exist
|
||||
if [[ ! -f "$SCRIPT_PATH" ]]; then
|
||||
debug_log "ERROR: Sign script not found at $SCRIPT_PATH"
|
||||
ls -la "$(dirname "$SCRIPT_PATH")" | tee -a "$DEBUG_LOG_PATH"
|
||||
echo "SIGNING_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CRASH_ENTITLEMENTS_PATH" ]]; then
|
||||
debug_log "ERROR: Crash entitlements not found at $CRASH_ENTITLEMENTS_PATH"
|
||||
ls -la "$(dirname "$CRASH_ENTITLEMENTS_PATH")" | tee -a "$DEBUG_LOG_PATH"
|
||||
echo "SIGNING_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run comprehensive signing script
|
||||
debug_log "Running comprehensive signing script..."
|
||||
"$SCRIPT_PATH" "$SIGNING_IDENTITY" "$APP_PATH" "$ENTITLEMENTS_PATH" "$CRASH_ENTITLEMENTS_PATH" 2>&1 | tee -a "$DEBUG_LOG_PATH"
|
||||
SIGN_RESULT=${PIPESTATUS[0]}
|
||||
|
||||
if [ $SIGN_RESULT -eq 0 ]; then
|
||||
debug_log "App signed successfully"
|
||||
echo "SIGNING_RESULT=true" >> $GITHUB_ENV
|
||||
else
|
||||
debug_log "ERROR: App signing failed with exit code: $SIGN_RESULT"
|
||||
echo "SIGNING_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Notarize application
|
||||
id: notarize-app
|
||||
if: env.SIGNING_RESULT == 'true'
|
||||
run: |
|
||||
# Debug log helper
|
||||
function debug_log() {
|
||||
echo "DEBUG: $1"
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
debug_log "Starting notarization process"
|
||||
|
||||
# Create ZIP for notarization
|
||||
debug_log "Creating ZIP archive for notarization"
|
||||
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
debug_log "Error creating ZIP archive"
|
||||
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
debug_log "ZIP archive created successfully at: $ZIP_PATH"
|
||||
ZIP_SIZE=$(du -h "$ZIP_PATH" | cut -f1)
|
||||
debug_log "ZIP archive size: $ZIP_SIZE"
|
||||
|
||||
# Save UUID to a file to ensure it persists across steps
|
||||
UUID_FILE="$WORK_DIR/notarization_uuid.txt"
|
||||
|
||||
# Submit for notarization - use separate submission and polling
|
||||
debug_log "Submitting app for notarization..."
|
||||
|
||||
# Submit with error capture
|
||||
SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" 2>&1)
|
||||
SUBMIT_STATUS=$?
|
||||
|
||||
# Save output for detailed analysis
|
||||
echo "$SUBMIT_OUTPUT" > "$WORK_DIR/submit_output.txt"
|
||||
cat "$WORK_DIR/submit_output.txt" | tee -a "$DEBUG_LOG_PATH"
|
||||
|
||||
if [ $SUBMIT_STATUS -ne 0 ]; then
|
||||
debug_log "ERROR: Failed to submit for notarization, exit code: $SUBMIT_STATUS"
|
||||
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the request UUID - ensuring we get just one match
|
||||
REQUEST_UUID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-z0-9-]*" | head -1 | cut -d' ' -f2)
|
||||
|
||||
if [ -z "$REQUEST_UUID" ]; then
|
||||
# Alternative grep pattern
|
||||
REQUEST_UUID=$(echo "$SUBMIT_OUTPUT" | grep -o "[a-f0-9]\{8\}-[a-f0-9]\{4\}-[a-f0-9]\{4\}-[a-f0-9]\{4\}-[a-f0-9]\{12\}" | head -1)
|
||||
fi
|
||||
|
||||
if [ -z "$REQUEST_UUID" ]; then
|
||||
debug_log "ERROR: Failed to extract UUID from notarization submission"
|
||||
debug_log "Full submission output:"
|
||||
cat "$WORK_DIR/submit_output.txt"
|
||||
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
debug_log "Notarization submission UUID: $REQUEST_UUID"
|
||||
echo "NOTARIZATION_UUID=$REQUEST_UUID" >> $GITHUB_ENV
|
||||
|
||||
# Also save UUID to file so it's available in cleanup step
|
||||
echo "$REQUEST_UUID" > "$UUID_FILE"
|
||||
debug_log "Saved UUID to file: $UUID_FILE"
|
||||
|
||||
# Wait for notarization to complete with polling
|
||||
debug_log "Waiting for notarization to complete (this may take several minutes)..."
|
||||
|
||||
WAIT_COUNTER=1
|
||||
TOTAL_WAIT=60 # 60 minutes maximum
|
||||
NOTARIZATION_COMPLETED=false
|
||||
|
||||
while [ $WAIT_COUNTER -le $TOTAL_WAIT ]; do
|
||||
if [ $WAIT_COUNTER -gt 1 ]; then
|
||||
debug_log "Waiting 60 seconds before checking again (attempt $WAIT_COUNTER/$TOTAL_WAIT)..."
|
||||
sleep 60
|
||||
fi
|
||||
|
||||
# Check status - make sure UUID is clean and not duplicated
|
||||
STATUS_OUTPUT=$(xcrun notarytool info "$REQUEST_UUID" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" 2>&1)
|
||||
STATUS_CODE=$?
|
||||
|
||||
echo "$STATUS_OUTPUT" > "$WORK_DIR/status_output_$WAIT_COUNTER.txt"
|
||||
cat "$WORK_DIR/status_output_$WAIT_COUNTER.txt" | tee -a "$DEBUG_LOG_PATH"
|
||||
|
||||
if [ $STATUS_CODE -ne 0 ]; then
|
||||
debug_log "WARNING: Status check failed, exit code: $STATUS_CODE"
|
||||
# Continue anyway to retry
|
||||
else
|
||||
# Extract status
|
||||
REQUEST_STATUS=$(echo "$STATUS_OUTPUT" | grep -o "status: [A-Za-z]*" | cut -d' ' -f2)
|
||||
|
||||
if [ -z "$REQUEST_STATUS" ]; then
|
||||
debug_log "WARNING: Could not extract status from output"
|
||||
else
|
||||
debug_log "Notarization status: $REQUEST_STATUS"
|
||||
|
||||
if [ "$REQUEST_STATUS" = "Accepted" ]; then
|
||||
debug_log "Notarization successful!"
|
||||
NOTARIZATION_COMPLETED=true
|
||||
echo "NOTARIZATION_RESULT=true" >> $GITHUB_ENV
|
||||
echo "NOTARIZATION_COMPLETED=true" >> $GITHUB_ENV
|
||||
break
|
||||
elif [ "$REQUEST_STATUS" = "Invalid" ] || [ "$REQUEST_STATUS" = "Rejected" ]; then
|
||||
debug_log "ERROR: Notarization failed with status: $REQUEST_STATUS"
|
||||
NOTARIZATION_COMPLETED=true
|
||||
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
|
||||
echo "NOTARIZATION_COMPLETED=true" >> $GITHUB_ENV
|
||||
|
||||
# Get the log URL to diagnose the issue
|
||||
LOG_URL_OUTPUT=$(xcrun notarytool log "$REQUEST_UUID" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" 2>&1)
|
||||
echo "Notarization log:" | tee -a "$DEBUG_LOG_PATH"
|
||||
echo "$LOG_URL_OUTPUT" | tee -a "$DEBUG_LOG_PATH"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
# In progress - continue waiting
|
||||
fi
|
||||
fi
|
||||
|
||||
WAIT_COUNTER=$((WAIT_COUNTER+1))
|
||||
done
|
||||
|
||||
# Check if we timed out
|
||||
if [ "$NOTARIZATION_COMPLETED" != "true" ]; then
|
||||
debug_log "ERROR: Notarization timed out after $TOTAL_WAIT attempts"
|
||||
echo "NOTARIZATION_RESULT=timeout" >> $GITHUB_ENV
|
||||
echo "NOTARIZATION_COMPLETED=true" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$REQUEST_STATUS" != "Accepted" ]; then
|
||||
debug_log "ERROR: Notarization failed with status: $REQUEST_STATUS"
|
||||
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Success - now staple the ticket
|
||||
debug_log "Notarization complete, proceeding to staple the ticket"
|
||||
xcrun stapler staple "$APP_PATH"
|
||||
STAPLE_RESULT=$?
|
||||
|
||||
if [ $STAPLE_RESULT -eq 0 ]; then
|
||||
debug_log "Notarization ticket stapled successfully"
|
||||
echo "STAPLING_RESULT=true" >> $GITHUB_ENV
|
||||
|
||||
# Verify stapling
|
||||
xcrun stapler validate "$APP_PATH"
|
||||
VALIDATE_RESULT=$?
|
||||
|
||||
if [ $VALIDATE_RESULT -eq 0 ]; then
|
||||
debug_log "Stapling validation successful"
|
||||
echo "VERIFY_RESULT=true" >> $GITHUB_ENV
|
||||
else
|
||||
debug_log "WARNING: Stapling validation failed but continuing"
|
||||
echo "VERIFY_RESULT=false" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
debug_log "ERROR: Failed to staple notarization ticket"
|
||||
echo "STAPLING_RESULT=false" >> $GITHUB_ENV
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Mark this step as having completed successfully for the cleanup step
|
||||
echo "NOTARIZE_STEP_COMPLETED=true" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Clean up
|
||||
id: cleanup
|
||||
if: always()
|
||||
run: |
|
||||
# Debug log helper
|
||||
function debug_log() {
|
||||
echo "DEBUG: $1"
|
||||
if [[ -n "$DEBUG_LOG_PATH" ]]; then
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$DEBUG_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
debug_log "Starting cleanup process..."
|
||||
|
||||
# Check if notarization is still in progress
|
||||
if [[ "$NOTARIZE_STEP_COMPLETED" != "true" && -n "$WORK_DIR" && -f "$WORK_DIR/notarization_uuid.txt" ]]; then
|
||||
debug_log "WARNING: Notarization step did not complete properly. Checking status before cleanup."
|
||||
|
||||
# Read UUID from file
|
||||
REQUEST_UUID=$(cat "$WORK_DIR/notarization_uuid.txt")
|
||||
|
||||
if [[ -n "$REQUEST_UUID" ]]; then
|
||||
debug_log "Found notarization UUID: $REQUEST_UUID"
|
||||
debug_log "Will check status one more time before cleanup..."
|
||||
|
||||
if [[ -f "$API_KEY_FILE" ]]; then
|
||||
STATUS_OUTPUT=$(xcrun notarytool info "$REQUEST_UUID" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" 2>&1 || echo "Status check failed")
|
||||
debug_log "Final notarization status check output:"
|
||||
debug_log "$STATUS_OUTPUT"
|
||||
else
|
||||
debug_log "API key file not available for final status check"
|
||||
fi
|
||||
else
|
||||
debug_log "No UUID file found, skipping final status check"
|
||||
fi
|
||||
else
|
||||
debug_log "Notarization process already completed or not started"
|
||||
fi
|
||||
|
||||
# Save notarization logs if available
|
||||
if [[ -d "$WORK_DIR" ]]; then
|
||||
debug_log "Saving notarization logs from work directory"
|
||||
mkdir -p "$DEBUG_LOG_PATH/../notarization_details" 2>/dev/null || true
|
||||
cp "$WORK_DIR/"*.txt "$DEBUG_LOG_PATH/../notarization_details/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Clean up keychain
|
||||
if [[ -n "$KEYCHAIN_NAME" ]]; then
|
||||
debug_log "Deleting keychain: $KEYCHAIN_NAME"
|
||||
security delete-keychain "$KEYCHAIN_NAME" 2>/dev/null || true
|
||||
debug_log "Keychain deleted"
|
||||
fi
|
||||
|
||||
# Clean up temporary files
|
||||
if [[ -d "$WORK_DIR" ]]; then
|
||||
debug_log "Removing temporary work directory: $WORK_DIR"
|
||||
rm -rf "$WORK_DIR" 2>/dev/null || true
|
||||
debug_log "Temporary files deleted"
|
||||
fi
|
||||
|
||||
debug_log "Cleanup completed"
|
||||
shell: bash
|
||||
|
||||
# Upload debug logs if available
|
||||
- name: Upload Debug Logs
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
# 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: notarize-debug-logs
|
||||
path: debug_logs
|
||||
retention-days: 7
|
||||
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_PATH }}
|
||||
bundle-id: ${{ env.BUNDLE_ID }}
|
||||
fallback-to-adhoc: 'false'
|
||||
|
||||
# Upload only the DMG file as main distribution artifact
|
||||
- name: Upload Mac Distribution DMG
|
||||
# Upload stapled app directly (this is the most reliable approach)
|
||||
- name: Upload Stapled App Bundle
|
||||
uses: actions/upload-artifact@v3
|
||||
if: env.NOTARIZED_STATUS == 'true' && env.SIGNED_STATUS != 'none'
|
||||
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none'
|
||||
with:
|
||||
name: LuckyWorld-Mac-Distribution
|
||||
path: ${{ env.PACKAGE_PATH }}
|
||||
name: LuckyWorld-macOS-Stapled-App-Bundle
|
||||
path: ${{ env.APP_PATH }}
|
||||
retention-days: 30
|
||||
|
||||
# Upload only the DMG file from the macos-notarize action
|
||||
- name: Upload Stapled App DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none'
|
||||
with:
|
||||
name: LuckyWorld-macOS-Signed-Notarized-DMG
|
||||
path: ${{ steps.sign-and-notarize.outputs.package-path }}
|
||||
retention-days: 30
|
||||
|
||||
# Report results
|
||||
- name: Report Results
|
||||
run: |
|
||||
echo "🔐 App signing: ${{ env.SIGNED_STATUS }}"
|
||||
echo "🔏 App notarization: ${{ env.NOTARIZED_STATUS }}"
|
||||
echo "🔐 App signing: ${{ steps.sign-and-notarize.outputs.signed }}"
|
||||
echo "🔏 App notarization: ${{ steps.sign-and-notarize.outputs.notarized }}"
|
||||
|
||||
if [ "${{ env.SIGNED_STATUS }}" != "none" ]; then
|
||||
if [ "${{ steps.sign-and-notarize.outputs.signed }}" != "none" ]; then
|
||||
echo "✅ Packaging completed successfully!"
|
||||
echo "Final package: ${{ env.PACKAGE_PATH }}"
|
||||
echo "Final package: ${{ steps.sign-and-notarize.outputs.package-path }}"
|
||||
else
|
||||
echo "⚠️ App was not signed - check the logs for details"
|
||||
fi
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||
<true/>
|
||||
<!-- Not including get-task-allow permission -->
|
||||
</dict>
|
||||
</plist>
|
@ -1,148 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parametreleri al
|
||||
SIGNING_IDENTITY="$1"
|
||||
APP_PATH="$2"
|
||||
ENTITLEMENTS_PATH="$3"
|
||||
CRASH_ENTITLEMENTS_PATH="$4"
|
||||
|
||||
# Sertifika hash'ini ayıkla (varsa)
|
||||
CERT_HASH=$(echo "$SIGNING_IDENTITY" | grep -o '[0-9A-F]\{40\}')
|
||||
if [ -n "$CERT_HASH" ]; then
|
||||
echo "📝 Using certificate hash: $CERT_HASH"
|
||||
SIGNING_ID="$CERT_HASH"
|
||||
else
|
||||
echo "📝 Using certificate identity: $SIGNING_IDENTITY"
|
||||
SIGNING_ID="$SIGNING_IDENTITY"
|
||||
fi
|
||||
|
||||
echo "📝 Comprehensive signing starting..."
|
||||
echo "App Path: $APP_PATH"
|
||||
echo "Signing Identity: $SIGNING_ID"
|
||||
echo "Entitlements: $ENTITLEMENTS_PATH"
|
||||
echo "CrashReporter Entitlements: $CRASH_ENTITLEMENTS_PATH"
|
||||
|
||||
# Step 1: Tüm dylib dosyalarını imzala (küçük gruplar halinde)
|
||||
echo "🔍 Signing all dylib files..."
|
||||
find "$APP_PATH" -name "*.dylib" | while read -r dylib; do
|
||||
echo "Signing: $dylib"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$dylib" || echo "⚠️ Failed to sign: $dylib"
|
||||
done
|
||||
|
||||
# Step 2: Tüm .so dosyalarını imzala
|
||||
echo "🔍 Signing all .so files..."
|
||||
find "$APP_PATH" -name "*.so" | while read -r so; do
|
||||
echo "Signing: $so"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$so" || echo "⚠️ Failed to sign: $so"
|
||||
done
|
||||
|
||||
# Step 3: Tüm yürütülebilir dosyaları imzala
|
||||
echo "🔍 Signing all executable files..."
|
||||
find "$APP_PATH" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read -r exe; do
|
||||
echo "Signing: $exe"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$exe" || echo "⚠️ Failed to sign: $exe"
|
||||
done
|
||||
|
||||
# Step 4: Tüm framework'leri imzala
|
||||
echo "🔍 Signing all frameworks..."
|
||||
find "$APP_PATH" -path "*.framework" -type d | while read -r framework; do
|
||||
echo "Signing framework: $framework"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$framework" || echo "⚠️ Failed to sign: $framework"
|
||||
done
|
||||
|
||||
# Step 5: CrashReportClient'ı özel olarak imzala
|
||||
echo "🔍 Looking for CrashReportClient.app..."
|
||||
CRASH_REPORTER_PATHS=$(find "$APP_PATH" -path "*CrashReportClient.app" -type d)
|
||||
if [ -n "$CRASH_REPORTER_PATHS" ]; then
|
||||
echo "✅ Found CrashReportClient apps:"
|
||||
echo "$CRASH_REPORTER_PATHS"
|
||||
|
||||
for CRASH_REPORTER in $CRASH_REPORTER_PATHS; do
|
||||
echo "🔐 Special signing for CrashReportClient: $CRASH_REPORTER"
|
||||
|
||||
# CrashReporter içindeki executable'ları imzala
|
||||
find "$CRASH_REPORTER" -type f -perm +111 | while read -r crash_exe; do
|
||||
echo "Signing CrashReporter binary: $crash_exe"
|
||||
codesign --force --options runtime --timestamp --entitlements "$CRASH_ENTITLEMENTS_PATH" --sign "$SIGNING_ID" "$crash_exe" || echo "⚠️ Failed to sign: $crash_exe"
|
||||
done
|
||||
|
||||
# CrashReporter bundle'ı imzala
|
||||
echo "Signing CrashReporter bundle: $CRASH_REPORTER"
|
||||
codesign --force --deep --options runtime --timestamp --entitlements "$CRASH_ENTITLEMENTS_PATH" --sign "$SIGNING_ID" "$CRASH_REPORTER" || echo "⚠️ Failed to sign CrashReportClient bundle"
|
||||
|
||||
# İmzayı doğrula
|
||||
echo "Verifying CrashReportClient signature..."
|
||||
codesign -vvv "$CRASH_REPORTER" || echo "⚠️ CrashReporter signature verification failed"
|
||||
done
|
||||
else
|
||||
echo "⚠️ No CrashReportClient.app found in $APP_PATH"
|
||||
fi
|
||||
|
||||
# Step 6: Boost kütüphaneleri özellikle imzala
|
||||
echo "🔍 Looking for Boost libraries..."
|
||||
BOOST_LIBS=$(find "$APP_PATH" -path "*/UE/LuckyWorld/Binaries/Mac/*.dylib")
|
||||
if [ -n "$BOOST_LIBS" ]; then
|
||||
echo "✅ Found Boost libs, specifically signing them..."
|
||||
for lib in $BOOST_LIBS; do
|
||||
echo "Signing boost lib: $lib"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$lib" || echo "⚠️ Failed to sign: $lib"
|
||||
done
|
||||
else
|
||||
echo "⚠️ No Boost libraries found"
|
||||
fi
|
||||
|
||||
# Step 7: Engine ThirdParty kütüphanelerini imzala
|
||||
echo "🔍 Looking for Engine ThirdParty libraries..."
|
||||
THIRD_PARTY_PATHS=$(find "$APP_PATH" -path "*/Engine/Binaries/ThirdParty" -type d)
|
||||
if [ -n "$THIRD_PARTY_PATHS" ]; then
|
||||
echo "✅ Found ThirdParty directories:"
|
||||
echo "$THIRD_PARTY_PATHS"
|
||||
|
||||
for THIRD_PARTY in $THIRD_PARTY_PATHS; do
|
||||
echo "Processing ThirdParty directory: $THIRD_PARTY"
|
||||
find "$THIRD_PARTY" -name "*.dylib" | while read -r engine_lib; do
|
||||
echo "Signing ThirdParty lib: $engine_lib"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$engine_lib" || echo "⚠️ Failed to sign: $engine_lib"
|
||||
done
|
||||
done
|
||||
else
|
||||
echo "⚠️ No ThirdParty directories found"
|
||||
fi
|
||||
|
||||
# Step 8: Plugin kütüphanelerini imzala
|
||||
echo "🔍 Looking for Plugin libraries..."
|
||||
PLUGIN_PATHS=$(find "$APP_PATH" -path "*/Engine/Plugins" -type d)
|
||||
if [ -n "$PLUGIN_PATHS" ]; then
|
||||
echo "✅ Found Plugin directories:"
|
||||
echo "$PLUGIN_PATHS"
|
||||
|
||||
for PLUGIN_PATH in $PLUGIN_PATHS; do
|
||||
echo "Processing Plugin directory: $PLUGIN_PATH"
|
||||
find "$PLUGIN_PATH" -name "*.dylib" | while read -r plugin_lib; do
|
||||
echo "Signing Plugin lib: $plugin_lib"
|
||||
codesign --force --options runtime --timestamp --sign "$SIGNING_ID" "$plugin_lib" || echo "⚠️ Failed to sign: $plugin_lib"
|
||||
done
|
||||
done
|
||||
else
|
||||
echo "⚠️ No Plugin directories found"
|
||||
fi
|
||||
|
||||
# Step 9: Diğer nested app bundles imzala
|
||||
echo "🔍 Signing nested app bundles..."
|
||||
find "$APP_PATH" -path "*.app" -type d | grep -v CrashReportClient | while read -r nested_app; do
|
||||
if [ "$nested_app" != "$APP_PATH" ]; then
|
||||
echo "Signing nested app: $nested_app"
|
||||
codesign --force --deep --options runtime --timestamp --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_ID" "$nested_app" || echo "⚠️ Failed to sign: $nested_app"
|
||||
fi
|
||||
done
|
||||
|
||||
# Step 10: Ana uygulamayı imzala
|
||||
echo "🔐 Final signing of the main app bundle..."
|
||||
codesign --force --deep --options runtime --timestamp --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_ID" "$APP_PATH" || { echo "❌ ERROR: Main app signing failed"; exit 1; }
|
||||
|
||||
# İmzalamayı doğrula
|
||||
echo "🔍 Verifying main app signature..."
|
||||
codesign -dvv "$APP_PATH" || { echo "❌ ERROR: Main app signature verification failed"; exit 1; }
|
||||
|
||||
echo "✅ Comprehensive signing completed successfully"
|
||||
exit 0
|
Loading…
x
Reference in New Issue
Block a user