mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 22:35:42 +00:00
- Use ditto instead of cp -R to copy Sparkle.framework (preserves bundle structure) - Skip individual signing of Sparkle's internal XPC services, apps, and executables - Use --deep flag when signing Sparkle.framework to handle its internal components - Verify cached Sparkle.framework has proper symlink structure, re-download if corrupted Fixes "bundle format unrecognized" error during codesigning. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
108 lines
3.9 KiB
Bash
Executable File
108 lines
3.9 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)
|
|
|
|
set -euxo pipefail
|
|
|
|
APP_PATH="$1"
|
|
ENTITLEMENTS_PATH="${2:-}"
|
|
SIGNING_IDENTITY="${SIGNING_IDENTITY:-Developer ID Application}"
|
|
|
|
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" build.keychain || 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"
|