Skip to content

fix(release): stamp + verify the macOS bundle version (was shipping stale)#92

Merged
stuffbucket merged 1 commit into
mainfrom
fix/macos-bundle-version
Jun 9, 2026
Merged

fix(release): stamp + verify the macOS bundle version (was shipping stale)#92
stuffbucket merged 1 commit into
mainfrom
fix/macos-bundle-version

Conversation

@stuffbucket

Copy link
Copy Markdown
Owner

Found by verifying the artifact (the "verified resilient" goal)

I downloaded the v0.4.20 signed .dmg and inspected it. The good news:
signing is excellent — both the shell and the bundled sidecar are signed with
Developer ID, hardened runtime on, notarized, Gatekeeper-accepted. The bad
news: the bundle's CFBundleShortVersionString was 0.4.14 — six releases
stale.

Root cause

The self-hosted macos-builder's target/ persists across builds, and
tauri build doesn't always regenerate the bundle's Info.plist. A stale
Maximal.app from an earlier tag (an onboarding test built at v0.4.14)
survived and got signed/shipped with the wrong version. build.sh stamped
tauri.conf.json correctly but never cleaned the old bundle or verified the
result.

Fix (.macos-builder/build.sh)

  1. Stamp robustly + assert — match whatever version is in
    tauri.conf.json (not only the 0.0.0 placeholder) and fail if the stamp
    didn't take.
  2. Remove the stale bundle (rm -rf …/target/release/bundle) before
    building, so the persistent runner can't serve an old .app.
  3. Proactive guard — after tauri build, read the built bundle's
    CFBundleShortVersionString and fail the build if it ≠ the release tag.
    Catches the entire "wrong version in the dmg" class at build time.

Verification

bash -n clean; the robust sed stamps the real tauri.conf.json to the tag;
the PlistBuddy read works on a real plist. Merging cuts a release, which
re-runs the pipeline — so the next artifact proves the fix (I'll confirm its
bundle version matches the tag).

Note: the already-released v0.4.20 .dmg can be re-built via the
macos-build.yml workflow_dispatch once this lands, if you want it corrected
in place.

…tale)

Verifying the v0.4.20 signed .dmg on the artifact (the "verified resilient"
goal) turned up a real defect: the bundle's CFBundleShortVersionString was
0.4.14 — six releases stale — even though signing + notarization were perfect.

Root cause: the self-hosted macos-builder's target/ dir persists across builds,
and `tauri build` doesn't always regenerate the bundle's Info.plist. A stale
Maximal.app from an earlier tag (an onboarding test built at v0.4.14) survived
and got signed/shipped with the wrong version. The build stamped tauri.conf.json
correctly but never cleaned the old bundle or checked the result.

Three fixes to .macos-builder/build.sh:
- Stamp robustly: match whatever version is in tauri.conf.json (not only the
  "0.0.0" placeholder) and ASSERT the stamp took — a silent sed no-op would
  ship the wrong version.
- Remove shell/src-tauri/target/release/bundle before building so no stale
  .app can survive the persistent runner's cache.
- Proactive guard: after `tauri build`, read the built bundle's
  CFBundleShortVersionString and fail the build if it != the release tag. This
  catches the whole "wrong version in the dmg" class at build time instead of
  in a user's About box.

Validated locally: bash -n clean; the robust sed stamps the real
tauri.conf.json to the tag; the PlistBuddy read works. Cutting this release
re-runs the pipeline, which proves the fix on the resulting artifact.
@stuffbucket
stuffbucket merged commit 2b36018 into main Jun 9, 2026
4 checks passed
@stuffbucket
stuffbucket deleted the fix/macos-bundle-version branch June 9, 2026 20:20
stuffbucket added a commit that referenced this pull request Jun 9, 2026
…ct) (#94)

The private stuffbucket/macos-builder was refreshed to a producer/builder split:
the client now ships a declarative `.macos-builder/config` plus an optional
`build.sh` PRODUCER that only *builds the .app* (and pre-signs the Bun sidecar);
the builder owns the entire sign/package/notarize/staple/checksum tail via its
own lib/package-macos.sh and no longer hands the producer APPLE_*.

Our old all-in-one build.sh (build + sign app + dmg + notarize + staple) is
incompatible with that — it expects Apple creds the new builder doesn't pass —
so the v0.4.21 macOS build produced NO signed .dmg (the release shipped without
one). This onboards us:

- Add `.macos-builder/config` — app_path, volname, bundle_id=co.stuffbucket.maximal,
  entitlements=bun-runtime, artifact=dmg. (Matches the builder's seeded policy
  for this repo, so the per-repo policy gate passes.)
- Rewrite `.macos-builder/build.sh` as a producer: stamp version, build the Bun
  sidecar, pre-sign it with the builder's enumerated bun-runtime entitlements
  ($ENTITLEMENTS_DIR), `tauri build --bundles app`, done. No app sign / dmg /
  notarize / staple / OUTPUT_DIR.

Kept my #92 version-correctness hardening in the producer (the canonical example
lacks it): robust version stamp + assert, `rm -rf` the bundle to defeat the
persistent runner's stale-Info.plist cache, and a post-build assertion that the
built bundle's CFBundleShortVersionString equals the tag.

The dispatch workflow (macos-build.yml), the MACOS_BUILDER_PAT secret, and the
app-repoman install are already in place. Validated: bash -n clean, executable,
contains no packaging/notarize calls, version stamp verified locally. Cutting
this release re-runs the pipeline under the new contract, which proves the
signed .dmg builds (and at the correct version).
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