ci(release): gate OSS desktop auto-update promotion - #5398
Conversation
39caf16 to
b20eea4
Compare
Retain the exact generated updater manifest on each immutable versioned release, and stop the tag build from moving the rolling updater pointer. Add a main-only manual promotion workflow that validates release identity, platform assets, signatures, monotonic versioning, and complete manifest state before publishing and verifying latest.json. Document the two-stage operator flow and pin it with structural and mocked behavioral coverage for successful promotion and fail-closed paths. Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
b20eea4 to
09b6776
Compare
wesbillman
left a comment
There was a problem hiding this comment.
Reviewed at 09b67768ab30ee2db2fcebc7d7209e35263707c9 on Wes’s behalf. I would approve, but GitHub does not permit the PR author account to approve its own PR.
The release/promotion split is sound: immutable versioned publication retains the exact updater-manifest.json, while the manual main-only workflow validates release/tag identity, the complete platform set, signatures, canonical version-bound asset URLs, asset existence, monotonic versioning, identical retries, and stale rolling-manifest state before the sole write. Post-write digest verification makes failures explicit.
I also verified the candidate is copied into staged/ before the complete versioned asset upload, so it is actually retained on desktop-vX.Y.Z. The intentional contract change removes automatic rolling-manifest mutation from release.yml; the corresponding release-ref expectations were updated and dedicated structural/behavior coverage was added.
Local verification on that exact clean head:
bash scripts/test-oss-desktop-promotion.sh— passbash scripts/test-oss-desktop-promotion-behavior.sh— passgit diff --check origin/main...HEAD— pass
CI is green. No blocking findings.
…gaps * origin/main: (35 commits) feat(desktop): time-based sweep for stale localStorage caches (#5453) ci(release): gate OSS desktop auto-update promotion (#5398) fix(release): pin desktop PR operations to block/buzz (#5212) fix(search): surface exact short profile names (#5480) Reduce repeated ACP session context (#5423) feat(desktop): NIP-AM agent-usage backend — P2 emission/transport/archive + P4a aggregation/D6 (#4000) fix(desktop): resolve overlapping member mentions (#5225) chore(deps): update react monorepo (#4441) ci(security): allow retired relay pool advisory (#5404) chore(deps): update dependency @tanstack/react-virtual to v3.14.9 (#4439) chore(deps): update all non-major dependencies (#3049) chore(deps): update rust crate anyhow to v1.0.104 (#4447) chore(deps): update rust crate arc-swap to v1.9.2 (#4448) chore(deps): update rust crate async-trait to v0.1.91 (#4458) chore(deps): update rust crate diffy to v0.5.1 (#4466) chore(deps): update rust crate async-compression to v0.4.43 (#4456) chore(deps): update rust crate clap to v4.6.6 (#4465) fix(desktop): preserve Welcome banner dismissal (#5406) fix(agent): retry LLM completion on malformed 2xx JSON body (#5351) fix(desktop): welcome banner overlap and missing dismiss control (#5330) ... # Conflicts: # crates/buzz-acp/src/config.rs
…gaps * origin/main: (35 commits) feat(desktop): time-based sweep for stale localStorage caches (#5453) ci(release): gate OSS desktop auto-update promotion (#5398) fix(release): pin desktop PR operations to block/buzz (#5212) fix(search): surface exact short profile names (#5480) Reduce repeated ACP session context (#5423) feat(desktop): NIP-AM agent-usage backend — P2 emission/transport/archive + P4a aggregation/D6 (#4000) fix(desktop): resolve overlapping member mentions (#5225) chore(deps): update react monorepo (#4441) ci(security): allow retired relay pool advisory (#5404) chore(deps): update dependency @tanstack/react-virtual to v3.14.9 (#4439) chore(deps): update all non-major dependencies (#3049) chore(deps): update rust crate anyhow to v1.0.104 (#4447) chore(deps): update rust crate arc-swap to v1.9.2 (#4448) chore(deps): update rust crate async-trait to v0.1.91 (#4458) chore(deps): update rust crate diffy to v0.5.1 (#4466) chore(deps): update rust crate async-compression to v0.4.43 (#4456) chore(deps): update rust crate clap to v4.6.6 (#4465) fix(desktop): preserve Welcome banner dismissal (#5406) fix(agent): retry LLM completion on malformed 2xx JSON body (#5351) fix(desktop): welcome banner overlap and missing dismiss control (#5330) ... # Conflicts: # crates/buzz-acp/src/config.rs Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Summary
Separate OSS desktop artifact publication from fleet-wide auto-update promotion.
updater-manifest.jsonon each immutabledesktop-vX.Y.Zreleasebuzz-desktop-latest/latest.jsonmain-only manual promotion workflow with one global concurrency groupSafety 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:The repository pre-push hook also passed
branch-skewfor 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, thread8857ce8bbe928e891165eddcf06c666cf6eae16181c3f02a6d8c396d8a536026.