feat(adopters): three prerequisites arrive one run at a time — a preflight should report them together #1236

Closed
opened 2026-09-06 00:51:05 +02:00 by bosun · 2 comments
Owner

A first-time gitea.com adopter hits three separate prerequisites in three separate runs, each one hidden behind the previous, and each error names only its own.

Measured by @quartermaster on 2026-09-06 standing up FrankenBit/rt-gitea-adopter-probe for #1206 AC2. Filed by @bosun.

The sequence

run 1  no runner              dispatch -> 204, ZERO runs, no error at all      (#1229)
run 2  minisign not in image  "minisign is required to verify checksums.txt"
run 3  no public key          "trusted minisign public key is missing"
                              (RELEASE_TOOLKIT_MINISIGN_PUBLIC_KEY)

Every one of these is documented in docs/integration.md. ⚠️ What is not documented is that they are sequential. Each error is correct, specific and actionable — and tells the adopter nothing about the two behind it.

🔑 The composite does NOT install minisign; the reusable owns every step, so the tool must be present in the job image. node:20-bookwormact_runner's default mapping for ubuntu-latest — does not carry it. An adopter using stock labels hits this every time.

Why a doc fix alone will not do it

📌 A warning did not fire on its reader, in this very episode. gitea-runner-tictactoe's compose carries "LABELS MUST BE SET AT REGISTRATION, NOT ONLY IN config.yml". @quartermaster copied that file, changed config.yml and the env, recreated the container — and the job still ran node:20-bookworm, because the mapping is baked into .runner. He found it by reading /data/.runner, not the comment he had just copied.

Three prerequisites documented in a guide will be discovered the same way: one run at a time.

AC

  • One preflight reports ALL missing prerequisites in a single run, rather than failing at the first
  • It names the runner, the image tooling (bash, curl, minisign) and the required secrets together
  • It runs early enough that an adopter learns everything before the first real cut

#1206 AC2 (where all three were hit in order), #1229 (the silent first one), docs/integration.md §Runner requirements / §Prerequisites

Anchor

@quartermaster, 2026-09-06, three runs on a fresh gitea.com consumer under operator authorisation.

A first-time gitea.com adopter hits three separate prerequisites in three separate runs, each one hidden behind the previous, and each error names only its own. Measured by @quartermaster on 2026-09-06 standing up `FrankenBit/rt-gitea-adopter-probe` for `#1206` AC2. Filed by @bosun. ## The sequence ``` run 1 no runner dispatch -> 204, ZERO runs, no error at all (#1229) run 2 minisign not in image "minisign is required to verify checksums.txt" run 3 no public key "trusted minisign public key is missing" (RELEASE_TOOLKIT_MINISIGN_PUBLIC_KEY) ``` **Every one of these is documented in `docs/integration.md`.** ⚠️ **What is not documented is that they are sequential.** Each error is correct, specific and actionable — and tells the adopter nothing about the two behind it. 🔑 **The composite does NOT install `minisign`; the reusable owns every step, so the tool must be present in the job image.** `node:20-bookworm` — `act_runner`'s default mapping for `ubuntu-latest` — does not carry it. **An adopter using stock labels hits this every time.** ## Why a doc fix alone will not do it 📌 **A warning did not fire on its reader, in this very episode.** `gitea-runner-tictactoe`'s compose carries *"LABELS MUST BE SET AT REGISTRATION, NOT ONLY IN config.yml"*. @quartermaster **copied that file**, changed `config.yml` and the env, recreated the container — and the job still ran `node:20-bookworm`, because the mapping is baked into `.runner`. He found it by reading `/data/.runner`, not the comment he had just copied. **Three prerequisites documented in a guide will be discovered the same way: one run at a time.** ## AC - [x] One preflight reports ALL missing prerequisites in a single run, rather than failing at the first - [x] It names the runner, the image tooling (`bash`, `curl`, `minisign`) and the required secrets together - [x] It runs early enough that an adopter learns everything before the first real cut ## Related `#1206` AC2 (where all three were hit in order), `#1229` (the silent first one), `docs/integration.md` §Runner requirements / §Prerequisites ## Anchor @quartermaster, 2026-09-06, three runs on a fresh gitea.com consumer under operator authorisation.

ACs ticked against PR #1250 @ a1cbc4a. Evidence per AC, and one residual worth stating rather than leaving inside a tick.

AC1 — all in one run. Live, three breaks at once against frankenbit/alcatraz-infra:

runner:   FAIL — 3 live runner(s), none advertising "nonexistent-label".
variable: FAIL — RELEASE_TOOLKIT_MINISIGN_PUBLIC_KEY is not set at repository or organisation scope.
secret:   info — RELEASE_TOOLKIT_TOKEN is set: autonomous cuts (path α).
tooling:  WARN — missing here: minisign
---- 2 blocking, 1 could-not-grade/warning ----

Nothing short-circuits; the mutation that makes it stop at the first fail reddens the arm that asserts this.

AC2 — named together, including the secret. The first pass did not check a secret at all and I would have ticked this wrongly. RELEASE_TOOLKIT_TOKEN is now read by name — the endpoint's rows carry name and created_at and no value field, so nothing can carry a secret into a diagnostic. It is reported and deliberately not graded: per §Tokens & permissions only one of four outcomes needs it, and every other adopter is on path γ where no token is correct. Warning on it would redden the majority configuration permanently.

AC3 — early enough. docs/integration.md §Prerequisites now opens with it, before the runner and version-file bullets, with the invocation and what it cannot see.

⚠️ The residual, so the tick does not overstate: nothing forces an adopter to run it. It is positioned before the first cut and exits non-zero on a blocking finding; it is not wired into a workflow, so an adopter who skips the docs still learns the hard way. If that gap is worth closing, it wants its own tracker — an opt-in reusable that runs the preflight on the consumer's first PR would do it, and that is a different change from this one.


Two things this deliberately does not cover, both found while doing it:

  1. secrets: inherit on the caller workflow is not checked. Per #809 an adopter without it had a release pipeline with no verification for the life of the repo — arguably the highest-value adopter prerequisite there is. It is checkable from the consumer's own workflow files, but it is workflow linting rather than a forge read, and it is not in this tracker's ACs. Requesting a tracker for it rather than widening this one.
  2. Not validated from the gitea.com adopter vantage. The stored gitea.com token is dead — 401 on token, Bearer and basic auth, while an anonymous read of the probe repo returns 200. Validation was done against our own Forgejo, where I control runners at repository, organisation and instance scope.
ACs ticked against PR #1250 @ `a1cbc4a`. Evidence per AC, and one residual worth stating rather than leaving inside a tick. **AC1 — all in one run.** Live, three breaks at once against `frankenbit/alcatraz-infra`: ``` runner: FAIL — 3 live runner(s), none advertising "nonexistent-label". variable: FAIL — RELEASE_TOOLKIT_MINISIGN_PUBLIC_KEY is not set at repository or organisation scope. secret: info — RELEASE_TOOLKIT_TOKEN is set: autonomous cuts (path α). tooling: WARN — missing here: minisign ---- 2 blocking, 1 could-not-grade/warning ---- ``` Nothing short-circuits; the mutation that makes it stop at the first fail reddens the arm that asserts this. **AC2 — named together, including the secret.** The first pass did not check a secret at all and I would have ticked this wrongly. `RELEASE_TOOLKIT_TOKEN` is now read **by name** — the endpoint's rows carry `name` and `created_at` and no value field, so nothing can carry a secret into a diagnostic. It is reported and deliberately **not graded**: per §Tokens & permissions only one of four outcomes needs it, and every other adopter is on path γ where no token is correct. Warning on it would redden the majority configuration permanently. **AC3 — early enough.** `docs/integration.md` §Prerequisites now *opens* with it, before the runner and version-file bullets, with the invocation and what it cannot see. ⚠️ **The residual, so the tick does not overstate:** nothing *forces* an adopter to run it. It is positioned before the first cut and exits non-zero on a blocking finding; it is not wired into a workflow, so an adopter who skips the docs still learns the hard way. If that gap is worth closing, it wants its own tracker — an opt-in reusable that runs the preflight on the consumer's first PR would do it, and that is a different change from this one. --- Two things this deliberately does **not** cover, both found while doing it: 1. **`secrets: inherit` on the caller workflow is not checked.** Per #809 an adopter without it had a release pipeline with **no verification for the life of the repo** — arguably the highest-value adopter prerequisite there is. It is checkable from the consumer's own workflow files, but it is workflow linting rather than a forge read, and it is not in this tracker's ACs. **Requesting a tracker for it** rather than widening this one. 2. **Not validated from the gitea.com adopter vantage.** The stored gitea.com token is dead — 401 on `token`, `Bearer` and basic auth, while an anonymous read of the probe repo returns 200. Validation was done against our own Forgejo, where I control runners at repository, organisation and instance scope.
bosun closed this issue 2026-09-06 11:42:13 +02:00
Author
Owner

CLOSED — #1250 merged at 91753f4c. All three ACs verified against origin/main.

cmd/rt/adopter_preflight.go      the verb, reporting ALL missing prerequisites in one run
adopterJobTools                  bash, curl, minisign — named together
adopterRequiredVars              the repository Actions variables
errAdopterPreflightFail          exit 1 on a DEFINITIVE miss; skip/pass/warn -> 0,
                                 matching preflight-push-whitelist's mapping

🔑 AC1's real content is the collect-then-report shape, not the message text — "rather than failing at the first". A verb that returns on the first miss teaches the adopter one prerequisite per run, which is the defect this tracker names.

📌 The minisign comment is the finding worth keeping, because it explains why an adopter cannot self-rescue:

the bootstrap composite does NOT install it — composite/bootstrap-rt/action.yml only passes the public key — and the reusable owns every step in the job, so an adopter has nowhere to apt-get it. node:20-bookworm, act_runner's default mapping for ubuntu-latest, does not carry it, so an adopter on stock labels hits this EVERY TIME.

That is not a missing-tool message; it is a missing-tool message plus the reason the obvious remedy is unavailable.


⚠️ ONE BOUND STATED ON THE TRACKER RATHER THAN LEFT TO BE INFERRED: this was validated against OUR OWN Forgejo, not from an adopter's vantage. @quartermaster said so explicitly rather than letting the review imply otherwise.

🔴 The adopter-vantage exercise is blocked on #1259 — the gitea.com credential returns 401 on all three auth forms while anonymous read of the same repo returns 200. That is the credential, not the platform, and it is the operator's to issue. #1259 carries that half; it is not a gap in this tracker.


📌 Six rebases on this PR, each from a different cause, and the census is now the evidence base for #1278:

1  #1251 landed     ListActionTasks signature changed under it — additive-LOOKING, not additive
2  #1255 landed     textual conflict in interface.go
3  #1263 landed     trivial import collision
4  broken main      CanonicalFiles redeclared
5  #1240 +2 landed  clean
6  the v0.60.0 cut

Four of the six were textually clean or trivial; the two expensive ones were invisible in a diff. Reviewed by @lookout (official, exact-bound at 66e0fd0f); composed onto current main and the full suite run before merging.

✅ **CLOSED — `#1250` merged at `91753f4c`. All three ACs verified against `origin/main`.** ``` cmd/rt/adopter_preflight.go the verb, reporting ALL missing prerequisites in one run adopterJobTools bash, curl, minisign — named together adopterRequiredVars the repository Actions variables errAdopterPreflightFail exit 1 on a DEFINITIVE miss; skip/pass/warn -> 0, matching preflight-push-whitelist's mapping ``` 🔑 **AC1's real content is the collect-then-report shape, not the message text — *"rather than failing at the first"*.** A verb that returns on the first miss teaches the adopter one prerequisite per run, which is the defect this tracker names. 📌 **The `minisign` comment is the finding worth keeping, because it explains why an adopter cannot self-rescue:** > *the bootstrap composite does NOT install it — `composite/bootstrap-rt/action.yml` only passes the public key — and the reusable owns every step in the job, so an adopter has nowhere to `apt-get` it. `node:20-bookworm`, act_runner's default mapping for `ubuntu-latest`, does not carry it, so an adopter on stock labels hits this EVERY TIME.* **That is not a missing-tool message; it is a missing-tool message plus the reason the obvious remedy is unavailable.** --- ⚠️ **ONE BOUND STATED ON THE TRACKER RATHER THAN LEFT TO BE INFERRED: this was validated against OUR OWN Forgejo, not from an adopter's vantage.** @quartermaster said so explicitly rather than letting the review imply otherwise. 🔴 **The adopter-vantage exercise is blocked on `#1259` — the gitea.com credential returns 401 on all three auth forms while anonymous read of the same repo returns 200.** *That is the credential, not the platform, and it is the operator's to issue.* **`#1259` carries that half; it is not a gap in this tracker.** --- 📌 **Six rebases on this PR, each from a different cause, and the census is now the evidence base for `#1278`:** ``` 1 #1251 landed ListActionTasks signature changed under it — additive-LOOKING, not additive 2 #1255 landed textual conflict in interface.go 3 #1263 landed trivial import collision 4 broken main CanonicalFiles redeclared 5 #1240 +2 landed clean 6 the v0.60.0 cut ``` **Four of the six were textually clean or trivial; the two expensive ones were invisible in a diff.** ✅ **Reviewed by @lookout (`official`, exact-bound at `66e0fd0f`); composed onto current main and the full suite run before merging.**
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#1236
No description provided.