## Summary
Separate OSS desktop artifact publication from fleet-wide auto-update
promotion.
- retain the exact generated updater manifest as `updater-manifest.json`
on each immutable `desktop-vX.Y.Z` release
- stop the tag-triggered build from mutating
`buzz-desktop-latest/latest.json`
- add a `main`-only manual promotion workflow with one global
concurrency group
- validate stable semver, release/tag commit identity, draft/prerelease
state, exact platform set, signatures, version-bound asset URLs, asset
existence, monotonicity, idempotent retries, and a final stale-state
check before writing
- document the operator flow and pin the split with focused contract
tests
## Safety behavior
Publishing a versioned GitHub release no longer exposes it through the
in-app updater. Operators can install and test those exact
signed/notarized artifacts, then manually run **Promote OSS Desktop
Auto-Update** with the stable version.
Promotion rejects downgrades. A same-version retry succeeds only when
the rolling and candidate manifests are byte-identical. The workflow
re-reads the current rolling version immediately before its only write
and records the actor, source tag commit, previous version, manifest
digest, and run URL.
## Verification
Verified at commit `39caf1603be06bb476905225ec55f7bbbe86b237`:
```text
scripts/test-oss-desktop-promotion.sh
OSS desktop promotion contract passed
scripts/test-release-ref-contract.sh
release ref contract passed
git diff --check origin/main...HEAD
(clean)
```
The repository pre-push hook also passed `branch-skew` for the exact
pushed head; package suites were correctly skipped because this change
only touches release workflows, scripts, and documentation.
Originating conversation: Buzz channel `separate-publish-step-release`,
thread
`8857ce8bbe928e891165eddcf06c666cf6eae16181c3f02a6d8c396d8a536026`.
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
Redesign the permanent Desktop release flow so unrelated merges to
`main` cannot invalidate an already reviewed, green release candidate.
- Tag the immutable, API-confirmed release PR head instead of its later
squash commit.
- Treat the merged PR—including an authorized owner/admin bypass—as
publication authorization, while requiring trusted check evidence that
was complete at merge time.
- Make tag creation idempotent and collision-safe: an existing tag
succeeds only at the exact candidate SHA, and create races refetch
before accepting equality.
- Replace ancestry-based previous-release discovery with a validated
metadata ledger for side-history candidate tags.
- Compute the next release from the prior frozen base to the new frozen
base, excluding only the prior release squash SHA so unrelated commits
remain in the changelog.
- Preserve schema-1 production-tag migration and reject malformed
metadata or equal/decreasing versions.
- Update operator documentation for the normal squash-merge workflow.
This is the reusable release process for `0.5.6` onward, not the retired
one-shot `0.5.5` recovery path.
### Invariants covered
- Candidate creation → unrelated `main` merge → authorized squash merge
→ immutable candidate tag.
- Trusted producer IDs and merge-time completion timestamps; DCO's
bounded post-merge exception remains isolated.
- Missing/spoofed checks, tampered candidates, ambiguous PR
associations, conflicting tags, and equal/decreasing versions fail
closed.
- Same-SHA retries succeed; different-SHA collisions fail.
- Legacy schema-1 tag-on-main migration and schema-2 side-history
accounting both preserve the correct next-release changelog.
### Related issue
N/A — follows the Desktop release failures in #4788 and #4800 and the
recovery revert in #4808.
### Testing
At clean commit `6a91fbed8147a48cf174997de0c3e4cb2fb26474`:
- `scripts/test-desktop-release-candidate.sh`
- `scripts/test-release-ref-contract.sh`
Both focused suites passed with HEAD unchanged. Princess Donut cleared
the security/provenance surface, including the hostile merge-time
timestamp cases. Mongo cleared the side-history ledger, migration,
version-order, documentation, and contract-test surface.
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- document exact-head trusted approval as the only desktop tagging
authorization
- explicitly require `desktop_ref=desktop-v<version>` for the internal
desktop handoff
- replace the stale `squareup/sprout-releases` repository name with
`squareup/buzz-releases`
## Audit coverage
Compared `block/buzz` release documentation and automation with
`squareup/buzz-releases` `main`
(`5b09e5c5d71c80a0849a33458f4e45695df515d7`), including its README,
agent guide, Buildkite field hint, desktop validator, release validation
tests, and protected updater promotion instructions.
## Validation
- `bash scripts/test-release-ref-contract.sh`
- `git diff --check origin/main...HEAD`
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- validate desktop release candidates before merge and keep the
repository squash-only
- tag the squash commit only after proving frozen-base parent and
complete-tree identity with the validated PR head
- accept either an exact-head approval or the durable Default-ruleset
bypass record as release authorization
- remove the unusable App-backed preparation workflow; retain `just
release-desktop`
## Ruleset follow-up
After this PR merges, update Default ruleset `13596885` to:
- enable strict required status checks
- dismiss stale reviews on push and require approval after the last push
- require the integration-bound `Desktop Release Candidate` check
The next desktop release should be cut only after that settings update.
## Verification
At commit `d8c254db427eedbcffac1a6e078e90d1d0f5e151` with a clean
worktree:
- `scripts/test-release-ref-contract.sh`
- `scripts/test-desktop-release-candidate.sh`
- `bash -n scripts/verify-desktop-release-merge.sh
scripts/prepare-desktop-release.sh scripts/test-release-ref-contract.sh`
- `git diff --check`
The bypass test fixture is the captured rule-suite shape from real
squash merge PR #2864 / suite `3520068134`.
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- document `Prepare Desktop Release` as the canonical desktop release
entry point
- describe the frozen candidate, exact-head approval, and true
merge-commit contract
- document all platform outputs and complete release App/signing
configuration
- link the release runbook from the README
- allow stable reruns to repair the rolling updater manifest after the
versioned release has already published
## Release blocker
The live repository cannot currently complete this flow: repository
settings disable merge commits and the `main` ruleset allows only
squash, while `scripts/verify-desktop-release-merge.sh` requires a
two-parent merge whose second parent is the approved candidate. Those
settings must allow merge commits before a desktop release PR is merged.
## Validation
- `bash scripts/test-desktop-release-candidate.sh`
- `bash scripts/test-release-ref-contract.sh`
- `git diff --check`
- verified live repository merge settings, `main` ruleset, release tag
ruleset, Actions variable names, and secret names with GitHub API
- independent review by Princess Donut; incorporated all findings,
including the rolling-manifest retry gap and unsigned Windows labeling
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- add a manual desktop release preparer that regenerates one
version-only candidate from current `origin/main`
- validate deterministic complete changelog accounting, candidate
authorship, allowed files, exact-head approval, required checks, and
two-parent merge topology before tagging the reviewed candidate
- move desktop tags/releases from `v*` to `desktop-v*` while preserving
relay, chart, push-chart, and mobile behavior
- stage all four platform outputs in Actions artifacts and grant GitHub
release write access only to one final all-platform-gated publisher
- publish the versioned release only after complete artifact assembly;
update stable `latest.json` last; never promote prereleases or published
rebuild outputs
## Safety properties
- desktop tags point to the reviewed candidate SHA, not the merge commit
- release builds remain tag-bound and reverify tag == checked-out HEAD
- one final writer fails closed on artifact basename collisions
- per-tag concurrency serializes publication without cancellation
- published reruns do not replace immutable versioned assets or promote
signatures from a rebuild
- candidate branches use an explicit remote OID lease when regenerated
## Validation
- `scripts/test-desktop-release-candidate.sh`
- `scripts/test-release-ref-contract.sh`
- `scripts/test-mobile-release-contract.sh`
- changed workflow YAML parsing (Ruby Psych)
- changed shell syntax (`bash -n`)
- `git diff --check`
- push hooks: branch-skew, Rust workspace tests (1,853 passed), desktop
Tauri tests (3 passed)
## Coordinated companion
- squareup/buzz-releases#79 updates the manually entered desktop
source-tag contract to stable-only `desktop-v*`
- merge the private contract companion before the first namespaced
desktop release
## Rollout blockers (no settings changed here)
Before the first candidate/release:
1. enable merge commits in repository settings
2. allow `merge` in ruleset `13596885`
3. require approval after the last push in ruleset `13596885`
4. include `refs/tags/desktop-v*` explicitly in release ruleset
`14378754`
5. prove the non-publishing candidate/merge/tag/artifact validation path
before any production release
Do not test the old workflow with a prerelease: it can still mutate the
production rolling updater release.
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Why
Native profilers such as `ddprof` need symbols to resolve optimized Buzz
relay stacks, while ordinary deployments should keep the current compact
stripped image.
## What
- Build optimized relay binaries with line-table debug information and
derive the stripped release binaries from the same ELF files
- Publish matching multi-arch `debug-*` tags while preserving existing
stripped tags and runtime behavior
- Document the debug image as an optimized symbol-bearing release, not a
debug-mode build
## Risk Assessment
Medium — this changes the relay image release workflow and adds a second
image variant, but existing tags remain stripped and use the same
runtime base, user, entrypoint, and optimized machine code.
## References
- Follows Envoy's optimized unstripped `debug-*` image pattern:
https://github.com/envoyproxy/envoy/blob/main/distribution/binary/BUILD
- Built both Docker targets locally; verified matching GNU build IDs and
`.text` hashes, with DWARF and symbol sections present only in the debug
variant
- Pre-push checks passed: branch skew, org policy, desktop checks/tests,
Rust tests, mobile tests, Tauri tests, and workspace tests
Generated with Amp
Signed-off-by: David Grochowski <dgrochowski@squareup.com>
Co-authored-by: Amp <amp@ampcode.com>