From e14118746063350f033ad663ec6ddadc72e48c42 Mon Sep 17 00:00:00 2001 From: TZGyn Date: Thu, 8 Oct 2026 10:04:08 +0800 Subject: [PATCH] Require notarization for GUI releases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shipping an unnotarized build left the user with an app Gatekeeper rejects, and the skill previously suggested quarantine workarounds that hid the problem. Notarization is now a hard gate, with the account-level agreement failure documented so it is diagnosed instead of bypassed. 💘 Generated with Crush Assisted-by: Crush:kimi-k3 --- SKILL.md | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/SKILL.md b/SKILL.md index e4ec838..503c5ee 100644 --- a/SKILL.md +++ b/SKILL.md @@ -19,8 +19,14 @@ The reference implementations to copy from are `~/Git/kapture` and `gitea.tzgyn.dev`. SSH: `git@gitea.tzgyn.dev:TZGyn/.git`. - **Always print the upgrade script** (the `brew` commands below) in the final answer after any release or version bump. The user wants it every time. +- **Every GUI release must be notarized and stapled.** An unnotarized build is + not a release: never publish one, and never paper over Gatekeeper with + `xattr -dr com.apple.quarantine` or `brew install --cask --no-quarantine`. + If notarization fails, fix the cause (see + [Troubleshooting](#notarization-troubleshooting)) before publishing. - Never commit build artifacts. `.gitignore` covers `.build/`, `*.app/`, `dist/`, `.swiftpm/`, `xcuserdata/`, `DerivedData/`, `.DS_Store`. + (`go build ./...` drops a binary next to the source — ignore it explicitly.) - Never commit secrets (`.p8`, API keys) or push to a remote unless asked. - Commit messages: concise, why-focused, first line < 72 chars; add a body only when it helps a future reader. @@ -124,7 +130,9 @@ Two scripts per repo: `build-app.sh ` and `release.sh `. 4. **Bump the cask** (`version` + `sha256`), push the tap, pull Homebrew's clone, `brew audit`. Verify by downloading the asset back and comparing the sha256, and `spctl -a -vv .app` → `accepted` / - `source=Notarized Developer ID`. + `source=Notarized Developer ID`. If `spctl` does not say + `source=Notarized Developer ID`, stop and fix notarization first — do not + publish the release or the cask. 5. **Print the upgrade script**: @@ -162,11 +170,33 @@ xcrun stapler staple .app && xcrun stapler validate .app spctl -a -vv .app # want: accepted, source=Notarized Developer ID ``` -Wire `release.sh` so it notarizes when `NOTARY_*` env vars are set and otherwise -skips gracefully (build + zip + sha only). An unnotarized app is still signed but -Gatekeeper warns on other machines; the user can bypass with -`xattr -dr com.apple.quarantine .app` or install with -`brew install --cask --no-quarantine `. +`release.sh` **must** notarize. Treat any skip or failure as a failed release: +do not publish the tag, the release, or the cask, and do not suggest +quarantine workarounds (`xattr -dr com.apple.quarantine`, +`brew install --cask --no-quarantine`) — those hand the user a build macOS +rejects. Only publish once `spctl -a -vv .app` reports `accepted` with +`source=Notarized Developer ID`. + +### Notarization troubleshooting + +| Symptom | Cause / fix | +| --- | --- | +| `HTTP status code: 403. A required agreement is missing or has expired.` | The **Apple Developer Program License Agreement** for the team is unsigned or expired. The Account Holder must accept it in App Store Connect → **Business → Agreements** *and* at `developer.apple.com/account` → **Agreements**. Account-wide: every call fails, including read-only `notarytool history`, until it is accepted; allow a few minutes to propagate. | +| The same 403 *after* accepting | The wrong agreement was accepted (App Store Connect "Paid Apps" instead of the Program License Agreement) or it was accepted under a different team's account. | +| `401 Authentication credentials are incorrect` | Wrong key id / issuer, or the key belongs to another team. | + +Confirm the team before blaming the credentials — do not "fix" this by +switching teams or re-signing: + +```bash +security find-identity -v -p codesigning # the Developer ID team must match the key's team +spctl -a -vv /Applications/.app # an already-notarized app proves the team/key pair works +xcrun notarytool history --key ... --key-id ... --issuer ... # 403 here = account agreement, not the app +``` + +`notarytool history` failing the same way as the submit is the tell: the +problem is the account, not the bundle, so there is nothing to change in the +app or the scripts. ## 5. Mobile