Skip to content

Commit 6d2f601

Browse files
author
Matthew
committed
ci: verify what we publish from the consumer side
Nothing in this repo has ever checked the artifact a user downloads. ci.yml proves the code builds and its tests pass; release.yml's verify-assets proves the upload step believed itself, asserted from inside the run that did the uploading. Neither is evidence about the published thing. That gap shipped twice in this fleet. webrequest-hook v1.0.4 published as a zero-asset phantom: tag, Release object, nothing to download. headroom-hook's published Docker bundle could not boot the gateway, because its shipped docker/bundle/config.yaml still used config shapes busbar 1.5.3 retired, so the container exits 1 during config load and never binds a port. Both were green everywhere. Adds consumer-verify.yml, which calls the fleet's shared GetBusbar/busbar/.github/workflows/plugin-consumer-verify.yml. It checks out nothing, so a fix that is committed but never published still fails it. It asserts the Release is published rather than a still-draft, that every platform archive it owes is present and downloadable THROUGH /releases/latest/download/ (a count can never see a missing platform, only a name can), that one archive really is a plugin busbar would accept - manifest name/alias/kind/version, the sha256 binding the cdylib beside it, a real shared library, a non-empty signature - and, where a runnable bundle is published, that the image BOOTS AND SERVES. The same job is appended to release.yml as its final step, so a broken publish turns the RELEASE red rather than leaving a green release beside a red run nobody correlates. On failure the shared workflow opens or updates ONE labelled issue naming the failing check, its expected and observed values and the run URL, and closes it again when a run passes. The inputs are read off the PUBLISHED manifest rather than guessed from the crate name: this fleet genuinely disagrees with itself about naming (the store repos drop the trailing -plugin the auth repos keep, and store-valkey publishes as busbar-store-redis).
1 parent 941efe5 commit 6d2f601

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: consumer-verify
2+
3+
# Does what this repo PUBLISHED actually work when a user gets it?
4+
#
5+
# Every other workflow here reports on itself. ci.yml proves the code builds and its tests pass.
6+
# release.yml's verify-assets proves the upload step believed it succeeded, asserted from inside the
7+
# run that did the uploading. None of that is evidence about the artifact a user downloads, and the
8+
# gap is not theoretical: webrequest-hook v1.0.4 published as a zero-asset phantom, and
9+
# headroom-hook's published bundle could not boot the gateway because its shipped config used shapes
10+
# busbar 1.5.3 retired. Both were green everywhere. Nothing anywhere noticed.
11+
#
12+
# The logic lives in ONE place for the whole fleet, exactly like plugin-ci.yml, so a fix reaches
13+
# every plugin at once instead of being copied ten times and drifting nine.
14+
#
15+
# WHY BOTH TRIGGERS. release: published catches a broken publish immediately, and it fires whether or
16+
# not the release workflow itself finished happy - which matters, because a verifier that only runs
17+
# when everything already worked is not a verifier. The daily schedule catches ROT: an artifact that
18+
# published fine can stop working later when nothing about it changed (a bundle that no longer boots
19+
# against a newer engine, an asset deleted by hand, a release un-flagged as latest). A
20+
# publish-time-only check structurally cannot see that class.
21+
on:
22+
release:
23+
types: [published]
24+
schedule:
25+
- cron: " * * *"
26+
workflow_dispatch:
27+
inputs:
28+
version:
29+
description: "Version to verify (e.g. 1.0.4). Empty means the newest published release."
30+
required: false
31+
type: string
32+
33+
permissions:
34+
contents: read
35+
issues: write
36+
actions: read
37+
38+
jobs:
39+
consumer:
40+
uses: GetBusbar/busbar/.github/workflows/plugin-consumer-verify.yml@dev
41+
with:
42+
version: ${{ inputs.version || '' }}
43+
# Read off the PUBLISHED artifact, not guessed from the crate name: the filename prefix and the
44+
# manifest name genuinely differ across this fleet (the store repos drop the trailing -plugin
45+
# that the auth repos keep, and store-valkey publishes as busbar-store-redis).
46+
asset_prefix: busbar-store-redis
47+
plugin_name: busbar-store-redis-plugin
48+
plugin_alias: redis
49+
plugin_kind: store
50+
# This repo publishes a runnable bundle, so the check does not stop at 'the tarball exists':
51+
# the image is pulled fresh and the container must BOOT and answer /healthz. That is the
52+
# assertion that was missing when the published bundle shipped a config busbar had retired.
53+
bundle_image: 3 10
54+
bundle_env: ""
55+
secrets: inherit

.github/workflows/release.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,40 @@ jobs:
257257
-f event_type=upstream-release \
258258
-f "client_payload[repo]=${GITHUB_REPOSITORY}" \
259259
-f "client_payload[tag]=${GITHUB_REF_NAME}"
260+
261+
# THE LAST STEP: does what we just published work for a user?
262+
#
263+
# Everything above verifies what THIS RUN produced, from inside this run. verify-assets asserts the
264+
# assets it uploaded are present, which proves the run believed itself. It cannot prove the tarball
265+
# downloads for a stranger, unpacks into a plugin busbar will load, or (where a bundle is
266+
# published) boots. Those are the failures that shipped: a zero-asset phantom release, and a
267+
# published bundle that exits 1 on startup.
268+
#
269+
# Consumer verification is POST-PUBLICATION by nature - you cannot download an asset that was never
270+
# uploaded - so this cannot block the publish and does not pretend to. What it does is make the
271+
# verdict impossible to miss: a failure is THIS release run's failure, and the shared workflow also
272+
# opens or updates one labelled issue naming the failing check, expected, observed and the run URL.
273+
#
274+
# !cancelled() because a needs: on a FAILED job skips its dependent by default - the exact shape
275+
# that skips a release's own guard precisely when the release is broken.
276+
consumer-verification:
277+
name: consumer verification (LAST STEP)
278+
needs: [verify-assets]
279+
if: ${{ !cancelled() }}
280+
uses: GetBusbar/busbar/.github/workflows/plugin-consumer-verify.yml@dev
281+
with:
282+
version: ${{ github.ref_name }}
283+
asset_prefix: busbar-store-redis
284+
plugin_name: busbar-store-redis-plugin
285+
plugin_alias: redis
286+
plugin_kind: store
287+
# This repo publishes a runnable bundle, so the check does not stop at 'the tarball exists':
288+
# the image is pulled fresh and the container must BOOT and answer /healthz. That is the
289+
# assertion that was missing when the published bundle shipped a config busbar had retired.
290+
bundle_image: 3 10
291+
bundle_env: ""
292+
permissions:
293+
contents: read
294+
issues: write
295+
actions: read
296+
secrets: inherit

0 commit comments

Comments
 (0)