The first notarized build: the day a side project became sellable
Notarization is the gate between 'only I can run this' and 'anyone can install it.' Getting Talkak's first notarized + stapled build took a full day — not because of the app, but a sandbox that silently killed every build's network to Apple, a brand-new account Apple processed agonizingly slowly, and a corrupted secrets file. It ended in a green spctl: Notarized Developer ID.
Why this mattered
Talkak ships as a direct-download Mac app, not through the App Store (the App Store sandbox forbids spawning tmux/PTYs/arbitrary CLIs — which is literally what Talkak does). For direct distribution there is exactly one Apple gate: notarization — Apple's automated malware scan that lets any Mac open the app without the "unidentified developer can't be opened" wall. Without it, the app is sellable to exactly one person: me. So this was the commercialization gate.
I'd just become a paid Apple Developer. The pieces seemed simple: a Developer ID
certificate, credentials, tauri build. It took the whole day.
Trap 1 — the build's notarization died on a network error, but my network was fine
Every pnpm tauri build failed the same way:
failed to notarize app: Error … Code=-1009
"The Internet connection appears to be offline." … No network route
… https://appstoreconnect.apple.com/notary/…But a manual xcrun notarytool history to the same Apple endpoint, run by hand,
returned 200 OK. curl https://appstoreconnect.apple.com → 200. So the machine's
network was fine; only the build's notarytool couldn't reach Apple.
The tell was that it was identical every time and failed immediately ("Resolved 0 endpoints in 2ms"). That's not a flaky network — that's something blocking one process. The build was running inside a sandbox that blocked its outbound network. My manual commands ran outside it. Worse: each failed build had started an upload to Apple before dying, leaving zombie submissions stuck "In Progress" forever (incomplete packages Apple could never finish).
The fix: stop notarizing inside the build. Sign in the build, then notarize
manually in the foreground — ditto the signed .app, notarytool submit,
stapler staple. The upload finally printed Successfully uploaded file.
Trap 2 — a missing newline broke the credential (and another app's key)
Mid-debug, status checks suddenly 401'd. The app-specific password in
~/.secrets/api-keys.env read as 68 chars instead of 19 — because a saved edit had
dropped the newline, fusing APPLE_PASSWORD=… straight into the next line's
R2_ACCESS_KEY_ID=…. One missing \n corrupted two credentials at once. (Switched
to an App Store Connect API key — a .p8 file, not a plaintext line — which
can't fuse and never shows up in ps.)
Trap 3 — Apple was just… slow
With a complete upload and clean credentials, the submission still sat In Progress.
And sat. Five submissions, the oldest ~20 hours, all In Progress, while Apple's
status page showed the Notary Service green. I was sure something was still wrong.
It wasn't. Brand-new developer accounts (mine enrolled that same day) appear to get
processed slowly while Apple warms them up. Eventually — quietly, hours later — every
single submission flipped to Accepted.
The green line
xcrun stapler staple Talkak.app → The staple and validate action worked!
spctl --assess --type execute Talkak.app
→ accepted
→ source=Notarized Developer IDZipped the stapled .app; the ticket survives the zip. That file now opens on any
Mac with no warning. A side project became something you can sell.
The lessons
- A reproducible "network" error that only one process hits is not a network error. It's a sandbox/permission boundary. Compare against a hand-run command outside that context before blaming the network — or Apple.
- Decouple notarization from the build. Signing and notarizing are separate steps; doing the Apple round-trip by hand (foreground) is more debuggable and dodges the build's environment entirely.
- Slow ≠ broken. New-account notarization can take hours. Poll, don't re-submit into a pile of zombies.
- One missing newline can corrupt two secrets. Prefer a key file (
.p8) over a plaintext credential line.