From ec93fd25929d4f2d49372affc5dd1d0381932425 Mon Sep 17 00:00:00 2001 From: William Aaron Cheung Date: Tue, 8 Sep 2026 19:28:24 +0800 Subject: [PATCH 1/2] ci: attach the release binaries to the GitHub Release on-release.yml builds stateless-validator and debug-trace-server at the released tag and attaches them, with SHA256SUMS, to the Release page via the shared release-assets action. A workflow_dispatch on a tag ref with dry_run=true rehearses the build and checksums without attaching. The Artifact Registry archive stays in release.yaml / release-tracing.yaml. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_013eLFMaDpEwgDzyDBzCQzLH (cherry picked from commit 88d5ca6d882ce8d4fd8b42494ec26b2ae6cc3587) --- .github/workflows/on-release.yml | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/on-release.yml diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml new file mode 100644 index 00000000..b94297ac --- /dev/null +++ b/.github/workflows/on-release.yml @@ -0,0 +1,71 @@ +name: On Release + +# Publish target for a stateless-validator release: the two binaries as +# downloads on the GitHub Release page, with a SHA256SUMS file. Runs when the +# release pipeline publishes the Release (release-publish creates it after +# the tag), and on demand for a rehearsal on a tag ref: +# gh workflow run on-release.yml --ref vX.Y.Z -f dry_run=true +# The tag being released is always the run's own ref; there is no tag input. +# +# The internal archive to Artifact Registry stays in release.yaml and +# release-tracing.yaml, which the same tag push fires. + +on: + release: + types: [published] + workflow_dispatch: + inputs: + dry_run: + description: "Build and checksum everything; attach nothing" + required: false + type: boolean + default: true + +permissions: + contents: read + +env: + TAG: ${{ github.ref_name }} + # A release event is never a dry run; a dispatch defaults to one. + DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false }} + +jobs: + binaries: + runs-on: ubuntu-24.04 + timeout-minutes: 60 + permissions: + contents: write # release-assets attaches to the Release + steps: + - name: Require a tag ref + run: | + [[ "$GITHUB_REF_TYPE" == "tag" ]] || { echo "::error::this workflow publishes the run's own ref, which must be a tag (got $GITHUB_REF_TYPE $GITHUB_REF_NAME); dispatch it with --ref vX.Y.Z"; exit 1; } + + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + ref: ${{ env.TAG }} + persist-credentials: false + + - uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1 + with: + cache: false + + - uses: foundry-rs/foundry-toolchain@b00af27efadbc7b4ca8b82abbd903b17cc874d2a # v1 + + - name: Build + run: cargo build --release --locked --bin stateless-validator --bin debug-trace-server + + - name: Report binary versions + # Informational: stateless-validator's CLI does not carry a clap + # version, so this cannot be a gate the way it is for mega-evme. + run: | + for b in stateless-validator debug-trace-server; do + echo "$b: $(target/release/$b --version 2>/dev/null || echo '') ($(stat -c %s target/release/$b) bytes)" + done + + - uses: megaeth-labs/.github/.github/actions/release-assets@main + with: + tag: ${{ env.TAG }} + files: | + target/release/stateless-validator + target/release/debug-trace-server + dry_run: ${{ env.DRY_RUN }} From 8680901da5b180768fd70f0916dd550b2f180800 Mon Sep 17 00:00:00 2001 From: William Aaron Cheung Date: Wed, 9 Sep 2026 14:00:19 +0800 Subject: [PATCH 2/2] ci(on-release): gate on the binary version, serialise runs per tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review follow-ups on the on-release workflow: - Verify the built stateless-validator reports the tag's version (it carries a clap version; the old comment claimed otherwise) — warning on a dry run, hard stop on a release, as mega-evme does. Run debug-trace-server --help so a binary that cannot load fails the step instead of printing "" and shipping. - Add a per-tag concurrency group (cancel-in-progress: false) so a release run and a same-tag dispatch cannot race on the --clobber asset upload. - Document that the file must exist on the release branch: a release event resolves the workflow at the tagged commit, so a branch cut before this file landed needs it cherry-picked first. Co-Authored-By: Claude Fable 5.1 (cherry picked from commit 89aedf49da7508f97e15db1539b9d7f84c58b580) --- .github/workflows/on-release.yml | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index b94297ac..b6c893fe 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -7,6 +7,14 @@ name: On Release # gh workflow run on-release.yml --ref vX.Y.Z -f dry_run=true # The tag being released is always the run's own ref; there is no tag input. # +# This file must exist on the release branch: a `release` event resolves the +# workflow from the tagged commit's tree, not from the default branch, and the +# tag sits on the release branch. A branch cut from a default branch that has +# this file carries it; a branch cut before it landed needs it cherry-picked +# (via its own PR — the `release-*` ruleset requires one) before the settle PR +# merges, or the Release publishes with nothing attached and no failed run. +# A rehearsal likewise only works on a tag whose tree has this file. +# # The internal archive to Artifact Registry stays in release.yaml and # release-tracing.yaml, which the same tag push fires. @@ -21,6 +29,13 @@ on: type: boolean default: true +# One run per tag: a release run and a dispatch on the same tag both end in a +# `--clobber` upload (delete-then-upload), so overlapping runs would race. +# Never cancel an upload mid-flight; queue instead. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + permissions: contents: read @@ -54,13 +69,30 @@ jobs: - name: Build run: cargo build --release --locked --bin stateless-validator --bin debug-trace-server - - name: Report binary versions - # Informational: stateless-validator's CLI does not carry a clap - # version, so this cannot be a gate the way it is for mega-evme. + - name: Verify the binaries + # stateless-validator carries a clap version (`#[clap(version)]`), so + # it is a gate: the built binary must report the tag's version, which + # also catches a tag / Cargo.toml mismatch nothing else checks here. + # debug-trace-server has no version flag; `--help` proves it loads and + # runs (a missing library or a crash fails the step) without gating. run: | + set -euo pipefail + expected="stateless-validator ${TAG#v}" + actual="$(target/release/stateless-validator --version)" + if [[ "$actual" != "$expected" ]]; then + if [[ "$DRY_RUN" == "true" ]]; then + # A rehearsal reports what a real run would refuse, and carries on. + echo "::warning::built binary reports '$actual', expected '$expected' — a real release would stop here" + else + echo "::error::built binary reports '$actual', expected '$expected'; refusing to publish a mislabeled binary" + exit 1 + fi + fi + target/release/debug-trace-server --help > /dev/null for b in stateless-validator debug-trace-server; do - echo "$b: $(target/release/$b --version 2>/dev/null || echo '') ($(stat -c %s target/release/$b) bytes)" + echo "$b: $(stat -c %s target/release/$b) bytes" done + echo "$actual" - uses: megaeth-labs/.github/.github/actions/release-assets@main with: