Skip to content

fix(release): notarize before publish + repair DMG verification#16

Merged
julia-kafarska merged 12 commits into
mainfrom
fix-notarize-immutable-flow
Jun 6, 2026
Merged

fix(release): notarize before publish + repair DMG verification#16
julia-kafarska merged 12 commits into
mainfrom
fix-notarize-immutable-flow

Conversation

@julia-kafarska

Copy link
Copy Markdown
Member

Why

While fixing v1.0.9's notarization (only the arm64 DMG was notarized; the Intel DMG wasn't, and neither was stapled) I found two bugs in the release tooling.

1. Bogus DMG verification aborted the notarize loop

notarize-release.mjs verified each stapled DMG with spctl --assess on the unmounted .dmg. A disk image has no code signature of its own, so that always returns no usable signature and exits non-zero. It threw right after stapling the arm64 DMG, aborting the loop before the x64 DMG was ever submitted — exactly why every past release only has an arm64 notarization on record.

Fix:

  • Verify with xcrun stapler validate (authoritative for a stapled DMG).
  • Separately mount the DMG and spctl-assess the .app inside (the real Gatekeeper check).
  • Retry stapler staple (Apple's ticket CDN lags a few seconds behind notarytool submit --wait).
  • Isolate per-DMG failures so one arch can't abort the others; only re-upload DMGs that were successfully stapled.

2. Publish-before-notarize is incompatible with Immutable Releases

release.mjs un-drafted the release before notarizing. GitHub "Immutable releases" freezes a release's assets at publish time permanently, so the stapled DMGs could never be re-uploaded (HTTP 422: Cannot delete asset from an immutable release).

Fix: notarize while the release is still a draft, then publish. Docs updated to match.

🤖 Generated with Claude Code

julia-kafarska and others added 12 commits June 4, 2026 17:22
Publishes site/manifest.json to https://light-cloud-com.github.io/out-loud/manifest.json
so the in-app announcements + update notice can be driven remotely.
…panel

Accessibility:
- Talker mode (Settings toggle, default off): Enter speaks + clears, text box
  stays editable during playback, audio click + screen-reader status.
- Cmd/Ctrl+Enter speaks anywhere; Shift+Enter = newline; Esc refocuses the box;
  textarea autofocuses on launch.

Speech:
- Pause tags: [1s], [500ms], <pause=1s>, <break time="1s"/> (forgiving units).
- Highlighting now treats pause tags as silence so it stays in sync.

Updates & help:
- In-app update check against GitHub releases with a direct per-platform
  download button (skipped in MAS builds). Replaces the remote-manifest
  approach (removes site/manifest.json and the Pages workflow).
- Help/About panel (footer ? button) with version, shortcuts, and pause docs.

Bumps version to 1.0.6; updates CHANGELOG, README, and architecture docs.
- Point the Help/About link, tray About item, and Chrome extension download
  banner at https://www.out-loud.io (was out-loud.pro).
- Update the default example text to demonstrate inline <pause=...> tags.
- Bump version to 1.0.7; update CHANGELOG.
Add scripts/release.mjs (npm run release <version>): bump → PR → wait CI →
squash-merge → tag → wait build → notarize → publish, in a single command.
Update releasing docs.
Repo-level tag ruleset protecting v* tags from deletion/force-push while
allowing creation (so npm run release works); admins bypass always. Already
applied to the repo via the GitHub API.
* release: 1.0.9

* v1.0.9
Two bugs left v1.0.9's Intel DMG unnotarized and its arm64 DMG unstapled:

1. notarize-release.mjs verified each stapled DMG with `spctl --assess` on the
   unmounted .dmg, which always reports "no usable signature" (a disk image has
   no code signature of its own — the ticket is validated by `stapler`). That
   threw right after stapling the arm64 DMG, aborting the loop before the x64
   DMG was ever submitted. Fix: verify with `stapler validate`, and separately
   assess the .app inside the mounted DMG (the real Gatekeeper check). Also:
   retry `stapler staple` (Apple's ticket CDN lags behind `submit --wait`),
   isolate per-DMG failures so one arch can't abort the others, and only
   re-upload DMGs that were successfully stapled.

2. release.mjs published (un-drafted) BEFORE notarizing. GitHub "Immutable
   releases" freezes assets at publish time — permanently — so the stapled DMGs
   could never be re-uploaded. Fix: notarize while the release is still a draft,
   then publish. Docs updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@julia-kafarska julia-kafarska merged commit ac74f4a into main Jun 6, 2026
1 check passed
@julia-kafarska julia-kafarska deleted the fix-notarize-immutable-flow branch June 6, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant