fix(actions): enhance macOS notarization workflow by adding comprehensive error handling, improved API key management, and detailed logging for notarization status checks
Some checks failed
Test macOS Build Action / test-macos-build (push) Failing after 28m23s

This commit is contained in:
Ozgur 2025-04-16 15:43:41 +02:00
parent 622b10e10d
commit 79ddd3ff12
No known key found for this signature in database
GPG Key ID: 66CDF27505A35546

View File

@ -246,19 +246,49 @@ jobs:
echo "DMG_PATH=$DMG_PATH" >> $GITHUB_ENV
# Set notarization variables based on method
echo "Using API key method for notarization"
debug_log "Using API key method for notarization"
# Create API key file
# Create API key file - properly decode from base64
API_KEY_FILE="$WORK_DIR/api_key.p8"
echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > "$API_KEY_FILE"
echo "API_KEY_FILE=$API_KEY_FILE" >> $GITHUB_ENV
debug_log "Decoding API key from base64 to: $API_KEY_FILE"
# Verify API key file exists
# 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
# Explicitly decode from base64 as instructed
echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 -d > "$API_KEY_FILE" 2>/dev/null
# 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 after base64 decoding"
exit 1
fi
# Verify key format
if ! grep -q "BEGIN PRIVATE KEY" "$API_KEY_FILE"; then
debug_log "ERROR: API key is not in PEM format (missing BEGIN PRIVATE KEY)"
debug_log "First 10 bytes of API key file: $(hexdump -n 10 -ve '1/1 "%.2x"' "$API_KEY_FILE")"
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 }}"
@ -513,97 +543,136 @@ jobs:
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"
# Submit for notarization
# Submit for notarization - use separate submission and polling
debug_log "Submitting app for notarization..."
# First submit the app to get the request UUID
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 }}")
# Create submission file command from parts to avoid shell re-interpretation
SUBMIT_CMD="xcrun notarytool submit \"$ZIP_PATH\" --key \"$API_KEY_FILE\" --key-id \"${{ secrets.NOTARY_API_KEY_ID }}\" --issuer \"${{ secrets.NOTARY_API_KEY_ISSUER_ID }}\""
debug_log "Running command: $SUBMIT_CMD"
echo "$SUBMIT_OUTPUT" | tee -a "$DEBUG_LOG_PATH"
# Submit with error capture
SUBMIT_OUTPUT=$(eval "$SUBMIT_CMD" 2>&1)
SUBMIT_STATUS=$?
# Extract the request UUID
# 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 (handle different output formats)
REQUEST_UUID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-z0-9-]*" | cut -d' ' -f2)
if [ -z "$REQUEST_UUID" ]; then
debug_log "ERROR: Failed to extract request UUID"
# 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\}")
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 request submitted with UUID: $REQUEST_UUID"
debug_log "Notarization submission UUID: $REQUEST_UUID"
echo "NOTARIZATION_UUID=$REQUEST_UUID" >> $GITHUB_ENV
# Wait for notarization to complete with polling
debug_log "Waiting for notarization to complete (this may take several minutes)..."
# Wait for notarization to complete with verbose output
WAIT_COUNTER=1
while true; do
if [ $WAIT_COUNTER -gt 60 ]; then
debug_log "ERROR: Notarization wait timeout after 60 minutes"
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
exit 1
fi
TOTAL_WAIT=60 # 60 minutes maximum
# Sleep for 60 seconds between checks
while [ $WAIT_COUNTER -le $TOTAL_WAIT ]; do
if [ $WAIT_COUNTER -gt 1 ]; then
debug_log "Waiting 60 seconds before checking again (attempt $WAIT_COUNTER)..."
debug_log "Waiting 60 seconds before checking again (attempt $WAIT_COUNTER/$TOTAL_WAIT)..."
sleep 60
fi
INFO_OUTPUT=$(xcrun notarytool info "$REQUEST_UUID" \
--key "$API_KEY_FILE" \
--key-id "${{ secrets.NOTARY_API_KEY_ID }}" \
--issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}")
# Check status
STATUS_CMD="xcrun notarytool info \"$REQUEST_UUID\" --key \"$API_KEY_FILE\" --key-id \"${{ secrets.NOTARY_API_KEY_ID }}\" --issuer \"${{ secrets.NOTARY_API_KEY_ISSUER_ID }}\""
debug_log "Checking status with: $STATUS_CMD"
STATUS_OUTPUT=$(eval "$STATUS_CMD" 2>&1)
STATUS_CODE=$?
echo "$INFO_OUTPUT" | tee -a "$DEBUG_LOG_PATH"
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 "$INFO_OUTPUT" | grep -o "status: [A-Za-z]*" | cut -d' ' -f2)
REQUEST_STATUS=$(echo "$STATUS_OUTPUT" | grep -o "status: [A-Za-z]*" | cut -d' ' -f2)
debug_log "Current notarization status: $REQUEST_STATUS"
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 completed successfully!"
if [ "$REQUEST_STATUS" = "Accepted" ]; then
debug_log "Notarization successful!"
echo "NOTARIZATION_RESULT=true" >> $GITHUB_ENV
break
elif [ "$REQUEST_STATUS" == "Invalid" ] || [ "$REQUEST_STATUS" == "Rejected" ]; then
elif [ "$REQUEST_STATUS" = "Invalid" ] || [ "$REQUEST_STATUS" = "Rejected" ]; then
debug_log "ERROR: Notarization failed with status: $REQUEST_STATUS"
# Get log URL if available
LOG_URL=$(echo "$INFO_OUTPUT" | grep -o "LogFileURL: [^ ]*" | cut -d' ' -f2)
if [ -n "$LOG_URL" ]; then
debug_log "Downloading log file from: $LOG_URL"
curl -s "$LOG_URL" | tee "$WORK_DIR/notarization_log.json" | tee -a "$DEBUG_LOG_PATH"
fi
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
exit 1
fi
# In progress - continue waiting
fi
fi
WAIT_COUNTER=$((WAIT_COUNTER+1))
done
# Get detailed logs at the end
xcrun notarytool log "$REQUEST_UUID" \
--key "$API_KEY_FILE" \
--key-id "${{ secrets.NOTARY_API_KEY_ID }}" \
--issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" \
"$WORK_DIR/notarization_details.json"
debug_log "Detailed notarization log saved to $WORK_DIR/notarization_details.json"
cat "$WORK_DIR/notarization_details.json" | tee -a "$DEBUG_LOG_PATH"
# Check if notarization was successful
if [[ "$REQUEST_STATUS" == "Accepted" ]]; then
debug_log "Notarization successful"
echo "NOTARIZATION_RESULT=true" >> $GITHUB_ENV
else
debug_log "ERROR: Notarization failed or timed out"
debug_log "Notarization status: $REQUEST_STATUS"
# Check final status
if [ $WAIT_COUNTER -gt $TOTAL_WAIT ]; then
debug_log "ERROR: Notarization wait timeout after $TOTAL_WAIT minutes"
echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV
exit 1
fi
if [ "$REQUEST_STATUS" != "Accepted" ]; then
debug_log "ERROR: Notarization failed or timed out"
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
shell: bash
- name: Staple notarization ticket
@ -709,78 +778,27 @@ jobs:
debug_log "Packaging the signed and notarized app"
# Check if we should use create-dmg if available
if command -v create-dmg &> /dev/null; then
debug_log "Using create-dmg for DMG creation"
# Create a temporary directory for DMG contents
DMG_TEMP_DIR="$WORK_DIR/dmg-contents"
mkdir -p "$DMG_TEMP_DIR"
# Copy the app to the temporary directory
cp -R "$APP_PATH" "$DMG_TEMP_DIR/"
# Create instructions text file
echo "Drag the application to the Applications folder to install it." > "$DMG_TEMP_DIR/README.txt"
# Create symlink to Applications folder
ln -s /Applications "$DMG_TEMP_DIR/Applications"
# Use create-dmg to create a more beautiful DMG
create-dmg \
--volname "$APP_NAME" \
--window-pos 200 120 \
--window-size 800 400 \
--icon-size 100 \
--app-drop-link 600 185 \
--icon "$APP_NAME.app" 200 185 \
--hide-extension "$APP_NAME.app" \
--add-file "README.txt" 400 185 \
--no-internet-enable \
"$DMG_PATH" \
"$DMG_TEMP_DIR"
DMG_CREATE_RESULT=$?
elif command -v hdiutil &> /dev/null; then
debug_log "Using hdiutil for DMG creation"
# Create DMG using hdiutil
debug_log "Creating DMG package..."
hdiutil create -volname "$APP_NAME" -srcfolder "$APP_PATH" -ov -format UDZO "$DMG_PATH"
DMG_CREATE_RESULT=$?
else
debug_log "Neither create-dmg nor hdiutil available. Cannot create DMG."
DMG_CREATE_RESULT=1
fi
# Check DMG creation result
if [ $DMG_CREATE_RESULT -eq 0 ]; then
debug_log "DMG package created successfully at: $DMG_PATH"
DMG_SIZE=$(du -h "$DMG_PATH" | cut -f1)
debug_log "DMG size: $DMG_SIZE"
echo "DMG_CREATED=true" >> $GITHUB_ENV
echo "PACKAGE_PATH=$DMG_PATH" >> $GITHUB_ENV
else
debug_log "ERROR: DMG creation failed with exit code: $DMG_CREATE_RESULT"
debug_log "Falling back to ZIP package"
debug_log "WARNING: DMG creation failed, using ZIP as distribution package"
echo "DMG_CREATED=false" >> $GITHUB_ENV
echo "PACKAGE_PATH=$ZIP_PATH" >> $GITHUB_ENV
fi
# Final verification of distribution artifacts
debug_log "Verifying final distribution package"
FINAL_PACKAGE="${PACKAGE_PATH:-$ZIP_PATH}"
if [[ -f "$FINAL_PACKAGE" ]]; then
PACKAGE_SIZE=$(du -h "$FINAL_PACKAGE" | cut -f1)
debug_log "Distribution package size: $PACKAGE_SIZE"
debug_log "Distribution package ready at: $FINAL_PACKAGE"
else
debug_log "ERROR: Distribution package not found"
exit 1
fi
shell: bash
- name: Clean up
id: cleanup
if: always()
run: |
# Debug log helper
@ -791,7 +809,14 @@ jobs:
fi
}
debug_log "Cleaning up"
debug_log "Cleaning up resources"
# Save state message for better debugging
if [[ "$NOTARIZATION_RESULT" == "true" ]]; then
debug_log "Cleanup after successful notarization"
else
debug_log "Cleanup after notarization state: $NOTARIZATION_RESULT"
fi
# Clean up keychain
if [[ -n "$KEYCHAIN_NAME" ]]; then
@ -801,6 +826,12 @@ jobs:
# Clean up temporary files
if [[ -d "$WORK_DIR" ]]; then
# Save notarization logs first
if [[ -d "$DEBUG_LOG_PATH" ]] && [[ -d "$WORK_DIR" ]]; then
debug_log "Saving work directory files to debug logs"
cp -R "$WORK_DIR/"*.txt "$DEBUG_LOG_PATH/" 2>/dev/null || true
fi
rm -rf "$WORK_DIR" || true
debug_log "Temporary files deleted"
fi