|
| 1 | +# Releasing Atom++ (build → strip → sign → notarize → publish) |
| 2 | + |
| 3 | +How to turn the source into a **de-Microsoft'd, Developer-ID-signed, notarized, stapled** `.dmg` that |
| 4 | +launches cleanly on any Mac with no Gatekeeper warning — in one command once the one-time setup is done. |
| 5 | + |
| 6 | +> **Status (2026-07-01):** Apple Developer Program **enrolled**; the *Developer ID Application* cert is |
| 7 | +> installed (`AJ27Y4Z2HS`) and the `atompp-notary` credential is stored. `scripts/notarize.sh` + |
| 8 | +> `scripts/atompp.entitlements` + the `make-dmg.sh`/`build-macos.sh` wiring are all in place. |
| 9 | +> Without `CODESIGN_IDENTITY` set, `make-dmg.sh` still produces an **ad-hoc** dmg (local/tester use; |
| 10 | +> other Macs need right-click→Open or `xattr -dr com.apple.quarantine`). |
| 11 | +
|
| 12 | +## 0. Where we're going |
| 13 | + |
| 14 | +| | Ad-hoc (default) | Developer ID + notarized (release) | |
| 15 | +| --- | --- | --- | |
| 16 | +| Signature | `codesign --sign -` | `Developer ID Application: … (TEAMID)` | |
| 17 | +| Hardened runtime | no | **yes** (`--options runtime`) | |
| 18 | +| Entitlements | none | Electron/V8 JIT (`scripts/atompp.entitlements`) | |
| 19 | +| Notarized + stapled | no | **yes** (`notarytool` + `stapler`) | |
| 20 | +| Proprietary MS/Copilot code | **stripped** either way | **stripped** (`scripts/strip-proprietary.mjs`) | |
| 21 | +| Other Macs | Gatekeeper blocks | **launches cleanly** | |
| 22 | + |
| 23 | +**Pipeline:** build → de-Microsoft strip → sign inside-out (hardened runtime + entitlements) → build dmg → notarize → staple → verify → publish. |
| 24 | + |
| 25 | +## 1. One-time setup *(manual — only you can do this)* |
| 26 | + |
| 27 | +**a. Developer ID Application certificate.** ⚠️ Pick the exact type — outside-the-App-Store distribution |
| 28 | +needs **"Developer ID Application"** (NOT "Apple Distribution", NOT "Developer ID Installer" which is for |
| 29 | +`.pkg`). Easiest via Xcode → **Settings → Accounts → Manage Certificates… → + → Developer ID Application** |
| 30 | +(creates the private key in your login keychain). Confirm + note your Team ID: |
| 31 | +```bash |
| 32 | +security find-identity -v -p codesigning |
| 33 | +# → "Developer ID Application: SERGII DEMIANCHUK (AJ27Y4Z2HS)" ← the (…) is your TEAM ID |
| 34 | +``` |
| 35 | +Back it up: Keychain Access → My Certificates → right-click → **Export** the `.p12` somewhere safe |
| 36 | +(losing the private key means re-issuing). |
| 37 | + |
| 38 | +**b. Notary credential** (stored once; no secret ever enters the repo): |
| 39 | +```bash |
| 40 | +# App-specific password: appleid.apple.com → Sign-In and Security → App-Specific Passwords → Generate |
| 41 | +xcrun notarytool store-credentials "atompp-notary" \ |
| 42 | + --apple-id "you@example.com" --team-id "AJ27Y4Z2HS" --password "xxxx-xxxx-xxxx-xxxx" |
| 43 | +``` |
| 44 | +(For CI, use an App Store Connect API key instead: `--key AuthKey_XXXX.p8 --key-id KEYID --issuer ISSUER-UUID`.) |
| 45 | + |
| 46 | +**c. Export for your shell** (or your release env): |
| 47 | +```bash |
| 48 | +export CODESIGN_IDENTITY="Developer ID Application: SERGII DEMIANCHUK (AJ27Y4Z2HS)" |
| 49 | +export NOTARY_PROFILE="atompp-notary" |
| 50 | +``` |
| 51 | + |
| 52 | +## 2. Cut a release |
| 53 | + |
| 54 | +```bash |
| 55 | +./scripts/bootstrap.sh # first time / after an upstream bump (clone + brand + patch + npm ci) |
| 56 | +./scripts/build-macos.sh # → VSCode-darwin-<arch>/Atom++.app, then auto-strips proprietary MS/Copilot code from the app |
| 57 | +./scripts/make-dmg.sh # de-Microsoft (defensive) → sign (Developer ID) → dmg → notarize → staple → verify |
| 58 | +``` |
| 59 | +With `CODESIGN_IDENTITY` + `NOTARY_PROFILE` set, `make-dmg.sh` runs the whole signed+notarized pipeline; |
| 60 | +without them it's ad-hoc (unnotarized). **The de-Microsoft strip runs on the built *app*, never the source |
| 61 | +`vscode/` checkout** — so dev mode (`run-dev.sh` → typecheck) still sees the real packages. |
| 62 | + |
| 63 | +## 3. Verify it will pass Gatekeeper on a clean Mac |
| 64 | + |
| 65 | +```bash |
| 66 | +xcrun stapler validate Atom++-arm64.dmg |
| 67 | +spctl -a -t open --context context:primary-signature -v Atom++-arm64.dmg # → "source=Notarized Developer ID" / "accepted" |
| 68 | +``` |
| 69 | +Best real test: copy the dmg to a **different Mac** (or fresh user account), open it, drag to Applications, |
| 70 | +double-click — it should launch with no warning. |
| 71 | + |
| 72 | +Confirm the app carries no proprietary code: |
| 73 | +```bash |
| 74 | +find VSCode-darwin-arm64/Atom++.app \( -path "*@github/copilot*" -o -path "*mxc-sdk*" \) \ |
| 75 | + \( -name "*.node" -o -name "*.dylib" -o -name "mxc-exec-mac" \) -print # → prints NOTHING |
| 76 | +``` |
| 77 | + |
| 78 | +Build **both architectures** on matching hardware (Apple silicon → `arm64`, Intel → `x64`) to ship both dmgs. |
| 79 | + |
| 80 | +## 4. Publish |
| 81 | + |
| 82 | +```bash |
| 83 | +gh release create v0.1.0 --title "Atom++ v0.1.0" --notes "First public build. …" \ |
| 84 | + Atom++-arm64.dmg Atom++-x64.dmg |
| 85 | +``` |
| 86 | +Stable URL: `https://github.com/atom-plus-plus/atompp/releases/latest/download/Atom++-arm64.dmg` — link it |
| 87 | +from **atompp.ai/download**. |
| 88 | + |
| 89 | +## 5. Point the update feed at the release |
| 90 | + |
| 91 | +The notify-only updater (`extensions/atom-updater`) polls a feed from `tools/update-server`. After |
| 92 | +publishing, update the feed's release entry (version + the release-asset URLs above) so running installs |
| 93 | +see the new version. Keep the feed version in lockstep with the tag. |
| 94 | + |
| 95 | +## 6. Troubleshooting *(the ones that actually bit us are marked ⚑)* |
| 96 | + |
| 97 | +| Symptom | Cause / fix | |
| 98 | +| --- | --- | |
| 99 | +| ⚑ `security find-identity` → **0 valid identities**, cert shows **"not trusted"** in Keychain Access | The Apple **intermediate** is missing. Install the Developer ID **G2** CA: `curl -O https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer` → double-click. Do NOT hand-set trust on the leaf — leave "Use System Defaults". | |
| 100 | +| ⚑ `notarytool store-credentials` → **HTTP 401 Invalid credentials** | You used your Apple ID password, or never generated an app-specific one. appleid.apple.com → App-Specific Passwords → **Generate** → paste that (with the dashes). | |
| 101 | +| ⚑ Notarization stuck **In Progress** for hours | Apple-side queue/incident (check [system status](https://developer.apple.com/system-status/)). The submission is server-side — `Ctrl-C` the `--wait`, then `xcrun notarytool info <id> --keychain-profile atompp-notary` later and `stapler staple` once `Accepted`. Don't resubmit (duplicates just queue behind it). | |
| 102 | +| `notarytool` → **Invalid** | `xcrun notarytool log <id> --keychain-profile atompp-notary` names the exact file/entitlement. Usually: sign with the Developer ID identity + `--options runtime`. | |
| 103 | +| App crashes on launch (SIGKILL / code 137) after signing | Missing JIT entitlements on the main app or a helper — check `scripts/atompp.entitlements` is applied to the helper `.app`s too (notarize.sh does this). | |
| 104 | +| "signature does not include a secure timestamp" | Add `--timestamp` (needs network) — notarize.sh always does. | |
| 105 | +| Gatekeeper still warns after notarizing | Forgot to **staple**, or stapled the app but not the dmg. | |
| 106 | +| Chat won't open / shortcut dead in a build | `atompp.ai.focus` is `Ctrl+Cmd+I` (moved off the `Cmd+Alt+I` DevTools collision); the chat also auto-reveals until the first message is sent. | |
| 107 | + |
| 108 | +## 7. CI (optional) |
| 109 | + |
| 110 | +On a `macos` runner: base64-encode the `.p12` Developer ID export + store it (plus cert password, |
| 111 | +`APPLE_ID`, `TEAM_ID`, `APP_SPECIFIC_PASSWORD`) as repo secrets; import the cert into a temp keychain at |
| 112 | +job start, then run `build-macos.sh` → `make-dmg.sh` with `APPLE_ID`/`TEAM_ID`/`APP_SPECIFIC_PASSWORD` |
| 113 | +set (make-dmg.sh uses those when `NOTARY_PROFILE` is absent). |
0 commit comments