Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
Prints notarytool recipe with secret env names; links CI and backlog.
273 lines
8.5 KiB
Shell
Executable file
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
|