mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 22:35:42 +00:00
When multiple runners on the same machine try to sign simultaneously,
they were conflicting on the shared keychain names (build.keychain,
ios-build.keychain). This caused errSecInternalComponent errors.
Changes:
- mac_build.yml: Use build-${run_id}.keychain
- ios_testflight.yml: Use ios-build-${run_id}.keychain
- codesign_mac_app.sh: Support KEYCHAIN_NAME env var with fallback
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
110 lines
4.0 KiB
Bash
Executable File
110 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Code sign a macOS .app bundle for distribution
|
|
# Usage: codesign_mac_app.sh <app_path> [entitlements_path]
|
|
#
|
|
# Environment variables:
|
|
# SIGNING_IDENTITY - The signing identity (default: "Developer ID Application")
|
|
# KEYCHAIN_PASSWORD - Password to unlock the build keychain (optional)
|
|
# KEYCHAIN_NAME - Name of the keychain to unlock (default: "build.keychain")
|
|
|
|
set -euxo pipefail
|
|
|
|
APP_PATH="$1"
|
|
ENTITLEMENTS_PATH="${2:-}"
|
|
SIGNING_IDENTITY="${SIGNING_IDENTITY:-Developer ID Application}"
|
|
KEYCHAIN_NAME="${KEYCHAIN_NAME:-build.keychain}"
|
|
|
|
if [ ! -d "$APP_PATH" ]; then
|
|
echo "ERROR: App not found at $APP_PATH"
|
|
exit 1
|
|
fi
|
|
|
|
# Unlock keychain if password provided
|
|
if [ -n "${KEYCHAIN_PASSWORD:-}" ]; then
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" || true
|
|
fi
|
|
|
|
echo "=== Signing nested components first ==="
|
|
|
|
# Sign all dylibs
|
|
find "$APP_PATH" -name "*.dylib" -print0 | while IFS= read -r -d '' item; do
|
|
echo "Signing dylib: $item"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
done
|
|
|
|
# Sign all bundles (plugins)
|
|
find "$APP_PATH" -name "*.bundle" -print0 | while IFS= read -r -d '' item; do
|
|
echo "Signing bundle: $item"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
done
|
|
|
|
# Sign XPC services (but skip ones inside Sparkle.framework - they're already signed)
|
|
find "$APP_PATH" -name "*.xpc" -print0 | while IFS= read -r -d '' item; do
|
|
if [[ "$item" == *"Sparkle.framework"* ]]; then
|
|
echo "Skipping Sparkle XPC service (pre-signed): $item"
|
|
continue
|
|
fi
|
|
echo "Signing XPC service: $item"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
done
|
|
|
|
# Sign nested apps (but skip ones inside Sparkle.framework - they're already signed)
|
|
find "$APP_PATH" -path "*/Frameworks/*.app" -print0 | while IFS= read -r -d '' item; do
|
|
if [[ "$item" == *"Sparkle.framework"* ]]; then
|
|
echo "Skipping Sparkle nested app (pre-signed): $item"
|
|
continue
|
|
fi
|
|
echo "Signing nested app: $item"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
done
|
|
|
|
# Sign standalone executables inside frameworks (but skip Sparkle.framework internals)
|
|
find "$APP_PATH" -path "*/Frameworks/*/Versions/*/Autoupdate" -type f -print0 | while IFS= read -r -d '' item; do
|
|
if [[ "$item" == *"Sparkle.framework"* ]]; then
|
|
echo "Skipping Sparkle executable (pre-signed): $item"
|
|
continue
|
|
fi
|
|
echo "Signing executable: $item"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
done
|
|
|
|
# Sign all frameworks (after their contents are signed)
|
|
# Use --deep for Sparkle.framework to handle its XPC services
|
|
find "$APP_PATH" -name "*.framework" -print0 | while IFS= read -r -d '' item; do
|
|
if [[ "$item" == *"Sparkle.framework" ]]; then
|
|
echo "Signing Sparkle framework with --deep: $item"
|
|
codesign --deep --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
else
|
|
echo "Signing framework: $item"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$item"
|
|
fi
|
|
done
|
|
|
|
echo "=== Signing main app bundle ==="
|
|
|
|
if [ -n "$ENTITLEMENTS_PATH" ] && [ -f "$ENTITLEMENTS_PATH" ]; then
|
|
echo "Using entitlements: $ENTITLEMENTS_PATH"
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--entitlements "$ENTITLEMENTS_PATH" \
|
|
--sign "$SIGNING_IDENTITY" "$APP_PATH"
|
|
else
|
|
codesign --force --verify --verbose --timestamp --options runtime \
|
|
--sign "$SIGNING_IDENTITY" "$APP_PATH"
|
|
fi
|
|
|
|
echo "=== Verifying signature ==="
|
|
codesign --verify --verbose=4 "$APP_PATH"
|
|
|
|
echo "=== Checking Gatekeeper assessment ==="
|
|
spctl --assess --type exec -v "$APP_PATH" || echo "Note: Gatekeeper may reject until notarized"
|
|
|
|
echo "Code signing complete: $APP_PATH"
|