PrintToVeraeTimeStamp/platform/macos/menubar/notary-dry-run.sh
George Lambert 9f0881ccfc
Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
feat: notary-dry-run.sh for macOS menubar (no submit without NOTARY_SUBMIT=1)
Prints notarytool recipe with secret env names; links CI and backlog.
2026-10-14 01:08:18 -04:00

273 lines
8.5 KiB
Shell
Executable file

#!/usr/bin/env bash
# notary-dry-run.sh — menubar notarytool dry-run (Issue 1 commercial)
#
# Default: locate notarytool, report APP/ZIP presence, print submit/staple
# recipes using env **names** only. Does NOT codesign, submit, or staple.
#
# Live submit only when ALL of:
# NOTARY_SUBMIT=1
# notarytool on PATH
# a zip (or ditto-able .app) exists
# Never prints .p8 contents, passwords, or real secret values.
#
# Related:
# ci-notarize.yml.example
# NOTARIZE-CHECKLIST.md
# platform/windows/wix/CI-SIGN-NOTARY.md
# docs/COMMERCIAL-INSTALLER-BACKLOG.md
#
# Usage:
# ./notary-dry-run.sh
# ./notary-dry-run.sh ~/Applications/Verae\ Menubar.app
# APP=… ZIP=… ./notary-dry-run.sh
# NOTARY_SUBMIT=1 ZIP=/tmp/VeraeMenubar.zip ./notary-dry-run.sh # gated submit
#
# Exit: 0 on dry-run success (including missing notarytool tip).
# 1 on bad args / failed gated submit.
set -euo pipefail
DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$DIR/../../.." && pwd)"
APP="${APP:-}"
ZIP="${ZIP:-}"
PROFILE="${NOTARY_KEYCHAIN_PROFILE:-verae-notary}"
# Optional positional: path to .app or .zip
if [[ $# -gt 0 ]]; then
arg="$1"
case "$arg" in
*.zip|*.ZIP)
ZIP="$arg"
;;
*.app|*.APP)
APP="$arg"
;;
*)
if [[ -d "$arg" && "$arg" == *.app ]]; then
APP="$arg"
elif [[ -f "$arg" && "$arg" == *.zip ]]; then
ZIP="$arg"
else
echo "usage: $0 [path/to/Verae Menubar.app|.zip]" >&2
echo " env: APP= ZIP= NOTARY_SUBMIT=1 NOTARY_KEYCHAIN_PROFILE=" >&2
exit 1
fi
;;
esac
fi
# Defaults when unset
if [[ -z "$APP" ]]; then
for cand in \
"$DIR/Verae Menubar.app" \
"$HOME/Applications/Verae Menubar.app" \
"/Applications/Verae Menubar.app"
do
if [[ -d "$cand" ]]; then
APP="$cand"
break
fi
done
fi
if [[ -z "$ZIP" ]]; then
for cand in \
"/tmp/VeraeMenubar.zip" \
"$DIR/VeraeMenubar.zip" \
"${TMPDIR:-/tmp}/VeraeMenubar.zip"
do
if [[ -f "$cand" ]]; then
ZIP="$cand"
break
fi
done
fi
ZIP="${ZIP:-/tmp/VeraeMenubar.zip}"
echo "notary-dry-run — does NOT codesign or staple by default; submit only if NOTARY_SUBMIT=1."
echo "Repo: $ROOT"
echo "Docs: platform/macos/menubar/ci-notarize.yml.example"
echo " platform/macos/menubar/NOTARIZE-CHECKLIST.md"
echo " platform/windows/wix/CI-SIGN-NOTARY.md"
echo " docs/COMMERCIAL-INSTALLER-BACKLOG.md"
echo ""
# --- notarytool presence ---
echo "==== notarytool ===="
NOTARYTOOL=""
if command -v xcrun >/dev/null 2>&1; then
if xcrun --find notarytool >/dev/null 2>&1; then
NOTARYTOOL="$(xcrun --find notarytool 2>/dev/null || true)"
fi
fi
if [[ -z "$NOTARYTOOL" ]] && command -v notarytool >/dev/null 2>&1; then
NOTARYTOOL="$(command -v notarytool)"
fi
if [[ -z "$NOTARYTOOL" ]]; then
echo " notarytool: NOT FOUND"
echo ""
echo " Tip: install Xcode Command Line Tools (or full Xcode), then:"
echo " xcode-select --install"
echo " xcrun --find notarytool"
echo " Live CI notary stays gated off — see ci-notarize.yml.example (if: false)"
echo " and CI-SIGN-NOTARY.md. Exiting 0 (dry-run scaffold; no notarytool required)."
exit 0
fi
echo " notarytool: $NOTARYTOOL"
# --- artifacts ---
echo ""
echo "==== Artifacts ===="
if [[ -n "$APP" && -d "$APP" ]]; then
echo " APP: $APP"
if [[ -f "$APP/Contents/Resources/VERSION" ]]; then
echo " VERSION=$(tr -d '\r\n' < "$APP/Contents/Resources/VERSION")"
fi
else
echo " APP: (none found — build with ./build-menubar-app.sh)"
APP=""
fi
if [[ -f "$ZIP" ]]; then
echo " ZIP: $ZIP ($(wc -c < "$ZIP" | tr -d ' ') bytes)"
else
echo " ZIP: $ZIP (missing — ditto after codesign; see recipe below)"
fi
# --- codesign / staple status (informational only) ---
echo ""
echo "==== Status (informational) ===="
if [[ -n "$APP" ]]; then
if command -v codesign >/dev/null 2>&1; then
if codesign --verify --deep --strict "$APP" >/dev/null 2>&1; then
echo " codesign verify: OK"
else
echo " codesign verify: FAIL / unsigned (expected until Developer ID applied)"
fi
else
echo " codesign: not on PATH"
fi
if command -v xcrun >/dev/null 2>&1 && xcrun --find stapler >/dev/null 2>&1; then
if xcrun stapler validate "$APP" >/dev/null 2>&1; then
echo " stapler validate: OK (ticket present)"
else
echo " stapler validate: no ticket (expected until notary Accepted + staple)"
fi
fi
else
echo " (skip — no APP)"
fi
# --- env secret names + recipe ---
echo ""
echo "==== Submit recipe (env names only — no secrets) ===="
echo " Secret / env names (see CI-SIGN-NOTARY.md + ci-notarize.yml.example):"
echo " APPLE_API_KEY_P8_BASE64 # base64 of AuthKey_*.p8 (CI materialize only)"
echo " APPLE_API_KEY_ID"
echo " APPLE_API_ISSUER_ID"
echo " APPLE_TEAM_ID"
echo " APPLE_CODESIGN_IDENTITY # Developer ID Application: … (TEAMID)"
echo " APPLE_INSTALLER_IDENTITY # optional; product .pkg path"
echo " NOTARY_KEYCHAIN_PROFILE # laptop path (default print: $PROFILE)"
echo " NOTARY_KEY_PATH # path to AuthKey_*.p8 after materialize"
echo " NOTARY_KEY_ID / NOTARY_ISSUER_ID # aliases used in NOTARIZE-CHECKLIST"
echo ""
echo " # 0) Build unsigned (dev default)"
echo " ./build-menubar-app.sh \"\${APP:-\$HOME/Applications/Verae Menubar.app}\""
echo ""
echo " # 1) Codesign hardened runtime (operator machine / gated CI — not this dry-run)"
echo " APP=\"\${APP:-\$HOME/Applications/Verae Menubar.app}\""
echo " ENT=\"\$APP/Contents/Resources/entitlements.plist\""
echo " codesign --force --deep --options runtime --timestamp \\"
echo " --entitlements \"\$ENT\" \\"
echo " --sign \"\$APPLE_CODESIGN_IDENTITY\" \\"
echo " \"\$APP\""
echo " codesign --verify --deep --strict --verbose=2 \"\$APP\""
echo ""
echo " # 2) Zip for notarytool"
echo " ZIP=\"\${ZIP:-/tmp/VeraeMenubar.zip}\""
echo " rm -f \"\$ZIP\""
echo " ditto -c -k --keepParent \"\$APP\" \"\$ZIP\""
echo ""
echo " # 3a) Submit — keychain profile (laptops)"
echo " xcrun notarytool submit \"\$ZIP\" \\"
echo " --keychain-profile \"\${NOTARY_KEYCHAIN_PROFILE:-$PROFILE}\" \\"
echo " --wait"
echo ""
echo " # 3b) Submit — App Store Connect API key (CI-friendly)"
echo " xcrun notarytool submit \"\$ZIP\" \\"
echo " --key \"\$NOTARY_KEY_PATH\" \\"
echo " --key-id \"\${APPLE_API_KEY_ID:-\$NOTARY_KEY_ID}\" \\"
echo " --issuer \"\${APPLE_API_ISSUER_ID:-\$NOTARY_ISSUER_ID}\" \\"
echo " --wait"
echo ""
echo " # 4) Staple + Gatekeeper"
echo " xcrun stapler staple \"\$APP\""
echo " xcrun stapler validate \"\$APP\""
echo " spctl --assess --type execute -vv \"\$APP\""
echo ""
echo " CI sketch (unsigned default; notary job if: false):"
echo " platform/macos/menubar/ci-notarize.yml.example"
echo " Backlog: docs/COMMERCIAL-INSTALLER-BACKLOG.md"
echo " This dry-run does not claim notarization shipped."
# --- gated submit ---
echo ""
echo "==== Gated submit ===="
if [[ "${NOTARY_SUBMIT:-}" != "1" ]]; then
echo " NOTARY_SUBMIT is not 1 — no submit performed (print-only)."
echo " To submit for real: NOTARY_SUBMIT=1 ZIP=… [key env] $0"
exit 0
fi
echo " NOTARY_SUBMIT=1 — attempting notarytool submit --wait"
if [[ ! -f "$ZIP" ]]; then
if [[ -n "$APP" && -d "$APP" ]]; then
echo " ZIP missing; creating via ditto from APP…"
rm -f "$ZIP"
ditto -c -k --keepParent "$APP" "$ZIP"
else
echo " ERROR: NOTARY_SUBMIT=1 but no ZIP and no APP to ditto." >&2
exit 1
fi
fi
# Prefer API key env if NOTARY_KEY_PATH set; else keychain profile
set +e
if [[ -n "${NOTARY_KEY_PATH:-}" || -n "${APPLE_API_KEY_ID:-}" ]]; then
KEY_PATH="${NOTARY_KEY_PATH:-}"
KEY_ID="${APPLE_API_KEY_ID:-${NOTARY_KEY_ID:-}}"
ISSUER="${APPLE_API_ISSUER_ID:-${NOTARY_ISSUER_ID:-}}"
if [[ -z "$KEY_PATH" || -z "$KEY_ID" || -z "$ISSUER" ]]; then
echo " ERROR: API-key submit needs NOTARY_KEY_PATH + APPLE_API_KEY_ID + APPLE_API_ISSUER_ID" >&2
exit 1
fi
echo " mode: API key (key-id=\$APPLE_API_KEY_ID — value not printed)"
xcrun notarytool submit "$ZIP" \
--key "$KEY_PATH" \
--key-id "$KEY_ID" \
--issuer "$ISSUER" \
--wait
rc=$?
else
echo " mode: keychain profile (${NOTARY_KEYCHAIN_PROFILE:-$PROFILE})"
xcrun notarytool submit "$ZIP" \
--keychain-profile "${NOTARY_KEYCHAIN_PROFILE:-$PROFILE}" \
--wait
rc=$?
fi
set -e
if [[ $rc -ne 0 ]]; then
echo " notarytool submit failed (exit $rc)" >&2
exit "$rc"
fi
if [[ -n "$APP" && -d "$APP" ]]; then
echo " stapling $APP"
xcrun stapler staple "$APP"
xcrun stapler validate "$APP" || true
fi
echo " submit path finished."
exit 0