PrintToVeraeTimeStamp/platform/macos/menubar/NOTARIZE-CHECKLIST.md
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

6.2 KiB
Raw Blame History

Menu bar .app notarization checklist

Step list for Developer ID codesign + notarytool + stapler of the optional Verae menu bar app (ai.verae.timestamping.menubar).

This is a checklist only. It does not embed API keys, .p12 material, app-specific passwords, or signing.env values. Keep credentials in the keychain, CI secrets, or an out-of-repo env file (e.g. the pkg path’s $HOME/fie/installers/macos/signing.env).

Related runbooks: README.txt, docs/PACKAGING.md § Codesign + notarization, platform/macos/pkg/build-pkg.sh (product .pkg, separate from this menubar stub).


Prerequisites (once per machine / CI)

  • Apple Developer Program membership; team id known (TEAM_ID=… placeholder)
  • Developer ID Application certificate installed in the signing keychain
  • Notary credentials stored outside git, one of:
    • Keychain profile via xcrun notarytool store-credentials
      (profile name placeholder: verae-notary)
    • App Store Connect API key: AuthKey_XXXXXXXXXX.p8 path + Key ID + Issuer ID
      (paths/ids as env placeholders only — never commit the .p8)
  • Xcode CLT with codesign, notarytool, stapler, spctl, ditto
  • Entitlements file available (builder copies pkg entitlements into the app):
    platform/macos/pkg/entitlements.plist or
    $APP/Contents/Resources/entitlements.plist after build

Do not paste secrets into this checklist or the repo.


Build unsigned app

  • From repo root or platform/macos/menubar/:

    ./build-menubar-app.sh ~/Applications/Verae\ Menubar.app
    # optional version pin (default = internal/job.HelperVersion):
    # VERSION=x.y.z ./build-menubar-app.sh ~/Applications/Verae\ Menubar.app
    
  • Confirm bundle id ai.verae.timestamping.menubar, LSUIElement=true

  • Confirm Contents/Resources/VERSION and packaging-metadata.txt match HelperVersion (or your VERSION= override)


Codesign (hardened runtime)

Placeholders: YOUR ORG, TEAMID, APP.

APP="${APP:-$HOME/Applications/Verae Menubar.app}"
ENT="$APP/Contents/Resources/entitlements.plist"
# fallback: ENT="../../pkg/entitlements.plist" from menubar dir
IDENTITY="Developer ID Application: YOUR ORG (TEAMID)"

codesign --force --deep --options runtime --timestamp \
  --entitlements "$ENT" \
  --sign "$IDENTITY" \
  "$APP"

codesign --verify --deep --strict --verbose=2 "$APP"
codesign -dvv "$APP"   # inspect hardened runtime + team
  • codesign --verify succeeds
  • Hardened runtime present (flags=0x10000(runtime) or equivalent)
  • No unexpected nested Mach-O left unsigned (menubar is a thin Swift binary)

Zip for notarytool

ZIP="${ZIP:-/tmp/VeraeMenubar.zip}"
rm -f "$ZIP"
ditto -c -k --keepParent "$APP" "$ZIP"
  • Zip created with --keepParent (bundle layout preserved)

Submit notarization (notarytool)

Option A — keychain profile (preferred on operator laptops)

# One-time (interactive; stores in keychain — not in git):
# xcrun notarytool store-credentials "verae-notary" \
#   --apple-id "YOUR_APPLE_ID@example.com" \
#   --team-id  "TEAMID" \
#   --password "@keychain:AC_PASSWORD"   # or app-specific password prompt

xcrun notarytool submit "$ZIP" \
  --keychain-profile "verae-notary" \
  --wait

Option B — App Store Connect API key (CI-friendly)

# Env placeholders only — inject from CI secrets / signing.env:
# NOTARY_KEY_PATH=/path/to/AuthKey_XXXXXXXXXX.p8
# NOTARY_KEY_ID=XXXXXXXXXX
# NOTARY_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

xcrun notarytool submit "$ZIP" \
  --key "$NOTARY_KEY_PATH" \
  --key-id "$NOTARY_KEY_ID" \
  --issuer "$NOTARY_ISSUER_ID" \
  --wait
  • Submission status Accepted
  • On Invalid: xcrun notarytool log <submission-id> --keychain-profile "verae-notary"
    (or same key flags as submit); fix entitlements / signing; do not commit logs with tokens

Staple + Gatekeeper verify

xcrun stapler staple "$APP"
xcrun stapler validate "$APP"
spctl --assess --type execute -vv "$APP"
  • stapler validate OK
  • spctl --assess accepted (source = Notarized Developer ID)
  • Optional: copy app to a clean Mac / fresh user, confirm no right-click Open workaround

Distribute (optional)

  • Publish stapled .app as zip or DMG + SHA256 (naming example:
    VeraeMenubar-<HelperVersion>.app.zip)
  • If DMG: notarize/staple the DMG as well when it is the download vessel
  • Do not ship unstapled builds as the primary customer download
  • Product .pkg path remains separate: ../pkg/build-pkg.sh (already has notarytool + stapler when SIGNING_ENV is set)

Automation gap (still backlog)

  • CI workflow example (unsigned default; notary secret names only, gated off):
    ci-notarize.yml.example — copy into .github/workflows/ or .forgejo/workflows/ when enabling; do not treat the example as a live release job
  • Local dry-run (print submit recipe / tip; no submit unless gated):
    notary-dry-run.sh — if notarytool present prints codesign/ditto/submit/staple with env names only; else Xcode CLT tip (exit 0). Links ci-notarize.yml.example + docs/COMMERCIAL-INSTALLER-BACKLOG.md. Never submits unless NOTARY_SUBMIT=1.
  • Wire build-menubar-app.sh (or shared sign-and-notarize.sh) to run the above when SIGNING_ENV / CI secrets exist; keep unsigned default for dev
  • Promote example → live CI macOS runner: import Developer ID + notary key → staple → checksums
  • Smoke: spctl + stapler validate on signed hosts only

Until live CI + automated sign path land, this checklist + notary-dry-run.sh are the operator runbook.


Secrets hygiene (standing rules)

  • Never commit signing.env, .p8, .p12, notary passwords, or keychain exports
  • Never put real Apple IDs, Team IDs used as production secrets, or API key IDs into sample commands in PRs if policy forbids — placeholders only
  • Rotate credentials out-of-band if leaked; revoke via App Store Connect