Blurt is built, signed, notarized, and published locally from the
maintainer's Mac via scripts/release.sh (see the script headers for the
two-run bump→publish flow). This file covers the security-critical custody and
policy decisions that aren't obvious from the scripts.
The Developer ID Application key (602F699488189767137DF15633B967B1371ACD86,
team B2VQF7Q2QY) is the root of trust: Gatekeeper accepts anything signed with
it, so every published DMG must carry this signature. Protect it accordingly:
-
Keep the private key in a dedicated keychain that stays locked at rest (
~/Library/Keychains/blurt-signing.keychain-db), not the login keychain, with a tight partition-list ACL (onlycodesign/productsignmay use it) and a 15-minute auto-lock. Never store a plaintext.p12on disk or in cloud sync; keep the encrypted.p12backup offline. -
scripts/release-build.shunlocks that keychain for the duration of the build and re-locks it on exit (even on failure). It resolves the keychain password from, in order:BLURT_SIGNING_KEYCHAIN_PASSWORD(a CI secret, orop readinline), thenBLURT_SIGNING_KEYCHAIN_OP(anop://…1Password reference the script runsop readon — Touch ID fires), then an interactive prompt. It does not read the password from the login keychain, so the unlock secret never sits in login. Two equivalent local options:# Inline: read once at invocation BLURT_SIGNING_KEYCHAIN_PASSWORD="$(op read 'op://Employee/Blurt signing keychain/password')" \ scripts/release.sh # Or export the reference once (e.g. in your shell profile) so a bare # `scripts/release.sh` unlocks via 1Password. Set OP_ACCOUNT if you're signed # into more than one 1Password account. export OP_ACCOUNT=assemblyai.1password.com export BLURT_SIGNING_KEYCHAIN_OP='op://Employee/Blurt signing keychain/password' scripts/release.sh
Override the keychain path with
BLURT_SIGNING_KEYCHAINif it lives elsewhere. -
If
blurt-signing.keychain-dbisn't present, the script falls back to whatever identity is on the existing search list (e.g. login) — so a machine that hasn't migrated the key yet still builds. -
It then preflights that the identity is present (
security find-identity -v -p codesigning) and refuses to build without it. -
Everyday dev builds never touch this key. The
Debug/Debug-Localconfigs sign with the Apple Development cert (login keychain, same teamB2VQF7Q2QY), soscripts/dev-build.shand Xcode builds work with the release keychain locked. Onlyrelease-build.shuses the Developer ID key.
If the key is compromised (or the cert expires):
- Revoke the Developer ID Application certificate in the Apple Developer portal.
- Issue a new Developer ID Application certificate on the same team
(
B2VQF7Q2QY). - Update
IDENTITYinscripts/release-build.shto the new cert's SHA-1 (security find-identity -v -p codesigning). - Cut a fresh notarized release.
Rotating to a new cert within the same team (B2VQF7Q2QY) is seamless for
users — Gatekeeper accepts any valid Developer ID from any team, and updates are
a manual DMG download (see Updates in AGENTS.md), so there
is no signing-requirement pin to break. A team change (new Team ID) is still
worth avoiding on principle and announcing, but it no longer strands existing
users the way the former in-app updater's team-pinned requirement did.
The notary Apple-ID app-specific password lives in the blurt-notary keychain
profile (submit-only; it cannot sign). To rotate: revoke the old app-specific
password at appleid.apple.com, mint a new one, and re-run
xcrun notarytool store-credentials blurt-notary --apple-id <you> --team-id B2VQF7Q2QY --password <new-app-specific-password>.
Blurt does not yank published releases. The update check only ever offers
users a strictly higher version (UpdateChecker compares SemanticVersion and
reports .available only when the latest tag is greater), so the fix for any bad
build is to ship a new patch via scripts/release.sh.
The one exception is a fault caught before announcing, while the same version
is still safe to overwrite (e.g. a corrupted upload flagged by the post-publish
verification step): use scripts/release-publish.sh --republish to replace the
artifacts on the same tag. A code bug is never a republish — bump a patch.