SPB Git

spb/zyquo-agent Public MIT

The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.

Swift 94.7% Shell 4.1% Python 0.7% Makefile 0.5%
4.3 KB · 107 lines shellscript
Raw Blame History
1#!/bin/bash2#3#  notarize.sh4#  Zyquo Agent5#6#  Author: Simon-Pierre Boucher7#  Mail: contact@spboucher.ai8#9#  Developer ID signing, notarization, stapling, and verification for10#  Zyquo Agent. Identity, Team ID, and the notarytool keychain profile are the11#  same ones the Zyquo family already uses (see ~/Desktop/other/OTHER/zyquo-term).12#13#  Usage: notarize.sh <app-dir> <identity> <keychain-profile> <entitlements>14#         notarize.sh <app-dir> <identity> <keychain-profile> <entitlements> dmg15#16#  Signs nested code first, then the bundle, with the Hardened Runtime and a17#  secure timestamp; submits a ditto zip to Apple, waits, staples the ticket,18#  and fails loudly unless `spctl` reports "Notarized Developer ID".19#20#  Entitlements posture (Resources/ZyquoAgent.entitlements): Hardened Runtime21#  ON, App Sandbox deliberately OFF (Zyquo Agent must spawn /bin/bash and22#  /usr/bin/osascript to do its job, like Terminal.app or the sibling Zyquo23#  Term); the only declared entitlement is24#  com.apple.security.automation.apple-events, paired with25#  NSAppleEventsUsageDescription in Info.plist, for AppleScript automation.26#  Keep that file pure ASCII with no XML comments: the AMFI parser codesign27#  uses rejects both.28#29set -euo pipefail3031APP_DIR="${1:?app bundle path required}"32IDENTITY="${2:?signing identity required}"33KEYCHAIN_PROFILE="${3:?notarytool keychain profile required}"34ENTITLEMENTS="${4:?entitlements plist required}"35MAKE_DMG="${5:-}"3637APP_NAME="$(basename "$APP_DIR" .app)"38DIST="$(dirname "$APP_DIR")"39EXEC_NAME="ZyquoAgent"40ZIP_PATH="$DIST/${EXEC_NAME}.zip"41DMG_PATH="$DIST/${EXEC_NAME}.dmg"4243[ -d "$APP_DIR" ] || { echo "ERROR: $APP_DIR missing — run make release/bundle first" >&2; exit 1; }44[ -f "$ENTITLEMENTS" ] || { echo "ERROR: $ENTITLEMENTS missing" >&2; exit 1; }4546# ---------------------------------------------------------------- signing --47echo "=== Signing (Developer ID, hardened runtime) ==="48# Nested code first (frameworks/bundles/helpers), then the main executable,49# then the bundle itself — codesign requires inside-out order.50while IFS= read -r -d '' nested; do51    echo "  nested: $nested"52    codesign --force --options runtime --timestamp \53        --entitlements "$ENTITLEMENTS" --sign "$IDENTITY" "$nested"54done < <(find "$APP_DIR/Contents" \55    \( -name '*.framework' -o -name '*.dylib' -o -name '*.bundle' \) -print0 2>/dev/null)5657codesign --force --options runtime --timestamp \58    --entitlements "$ENTITLEMENTS" --sign "$IDENTITY" \59    "$APP_DIR/Contents/MacOS/$EXEC_NAME"60codesign --force --options runtime --timestamp \61    --entitlements "$ENTITLEMENTS" --sign "$IDENTITY" "$APP_DIR"6263echo "=== Verifying signature ==="64codesign --verify --deep --strict --verbose=2 "$APP_DIR"65codesign --display --entitlements - --verbose=2 "$APP_DIR" 2>&1 | sed -n '1,12p'6667# ------------------------------------------------------------ notarizing --68echo "=== Submitting to Apple notary service (profile: $KEYCHAIN_PROFILE) ==="69rm -f "$ZIP_PATH"70ditto -c -k --keepParent "$APP_DIR" "$ZIP_PATH"71xcrun notarytool submit "$ZIP_PATH" --keychain-profile "$KEYCHAIN_PROFILE" --wait7273echo "=== Stapling ==="74xcrun stapler staple "$APP_DIR"75xcrun stapler validate "$APP_DIR"7677echo "=== Gatekeeper assessment ==="78assessment="$(spctl -a -vv "$APP_DIR" 2>&1)"79echo "$assessment"80case "$assessment" in81    *"source=Notarized Developer ID"*)82        echo "✅ spctl: accepted, source=Notarized Developer ID" ;;83    *)84        echo "❌ spctl did not report a notarized Developer ID signature" >&285        exit 1 ;;86esac8788# Re-zip the stapled bundle so the distributed archive carries the ticket.89rm -f "$ZIP_PATH"90ditto -c -k --keepParent "$APP_DIR" "$ZIP_PATH"91echo "Archive: $ZIP_PATH"9293# ------------------------------------------------------------- optional dmg --94if [ "$MAKE_DMG" = "dmg" ]; then95    echo "=== Building signed + notarized DMG ==="96    rm -f "$DMG_PATH"97    hdiutil create -volname "$APP_NAME" -srcfolder "$APP_DIR" \98        -ov -format UDZO "$DMG_PATH"99    codesign --force --timestamp --sign "$IDENTITY" "$DMG_PATH"100    xcrun notarytool submit "$DMG_PATH" --keychain-profile "$KEYCHAIN_PROFILE" --wait101    xcrun stapler staple "$DMG_PATH"102    spctl -a -vv -t open --context context:primary-signature "$DMG_PATH" 2>&1 | tail -3103    echo "DMG: $DMG_PATH"104fi105106echo "=== Done: $APP_DIR is signed, notarized, and stapled ==="107