forked from heavy-duty/ceremony
docs(runner-probes): arming is two layers, because a commit cannot contain its own SHA (#202)
@codex-reviewer-andresmgsl found that the procedure was not executable as
written, and the reason is structural rather than a wording slip.
The candidate's workflows carry `repository: heavy-duty/ceremony` beside
`ref: ${{ env.CEREMONY_SELF_REF }}`, so arming must rewrite them. But
rewriting CREATES A NEW COMMIT, and a commit cannot embed its own object ID. So
a single-layer arming is self-referential: pin the callers to the pre-rewrite
SHA and they load the UNARMED workflows; pin them to the post-rewrite SHA and
you are asking that commit to contain itself. My step 3 asked for exactly that.
Two layers, stated as a table because the distinction is the whole thing:
candidate code SHA the immutable tree under test — actions/, lib/
armed workflow SHA a child commit whose workflows point at the fork and
whose CEREMONY_SELF_REF is the candidate code SHA
And callers pin by layer, because they are not the same thing: composite
actions to the candidate code SHA, reusable workflows to the armed SHA, which
is the only revision whose inner checkout is rewritten.
The completeness check becomes a mechanical non-zero gate — `git grep` for
executable `uses:`/`repository:` carriers over the ARMED tree, exiting non-zero
on any hit — rather than "every remaining hit must be prose". A partial rewrite
does not announce itself: it silently tests canonical main.
The result issue records both SHAs, not one, or a later reader cannot tell
which tree answered.
test/run.sh 28/28; shellcheck 0.10.0 and changelog-armed clean.
Refs #202
This commit is contained in:
parent
b80767e36c
commit
e27acd8ab9
2 changed files with 71 additions and 41 deletions
|
|
@ -19,9 +19,17 @@
|
||||||
assumed: a fleet identity gets 403 on org repo creation and 201 in its own
|
assumed: a fleet identity gets 403 on org repo creation and 201 in its own
|
||||||
namespace (#202).
|
namespace (#202).
|
||||||
|
|
||||||
- It carries an executable arming procedure — fork ref, canonical SHA, both
|
- It carries an executable two-layer arming procedure: an immutable candidate
|
||||||
`CEREMONY_SELF_REF` carriers rewritten, and what the result must record
|
code SHA and an armed workflow commit on top of it. A single layer is
|
||||||
(#202).
|
self-referential — rewriting a workflow makes a new commit, and a commit
|
||||||
|
cannot contain its own object ID (#202).
|
||||||
|
|
||||||
|
- Callers are pinned by layer: composite actions to the candidate code SHA,
|
||||||
|
reusable workflows to the armed SHA, which is the only revision whose inner
|
||||||
|
checkout points at the fork (#202).
|
||||||
|
|
||||||
|
- A `git grep` over the armed tree gates the rewrite non-zero, so a partial one
|
||||||
|
refuses instead of silently testing canonical main (#202).
|
||||||
|
|
||||||
- Probe results are written to an issue in the probe repo and carried to the
|
- Probe results are written to an issue in the probe repo and carried to the
|
||||||
ceremony issue by a human, so the probe holds no path that can write to the
|
ceremony issue by a human, so the probe holds no path that can write to the
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,9 @@ exists rather than assuming it here.
|
||||||
1. Reset the repo to a clean state — the probe's own fixtures only, no
|
1. Reset the repo to a clean state — the probe's own fixtures only, no
|
||||||
leftovers from the last one. A probe that inherits state is a probe whose
|
leftovers from the last one. A probe that inherits state is a probe whose
|
||||||
result you cannot attribute.
|
result you cannot attribute.
|
||||||
2. **Arm it against the candidate ref** (below), if the probe is about
|
2. **Arm it against the candidate** (below) — two layers, candidate code and
|
||||||
ceremony's own code rather than about a bare API call.
|
armed workflow — if the probe is about ceremony's own machinery rather than
|
||||||
|
about a bare API call.
|
||||||
3. **Run it as an Actions job under `${{ github.token }}`.** This is the whole
|
3. **Run it as an Actions job under `${{ github.token }}`.** This is the whole
|
||||||
point of the venue and the one step that cannot be shortcut. A `curl` from a
|
point of the venue and the one step that cannot be shortcut. A `curl` from a
|
||||||
laptop with a PAT answers a different question — see the 204/500 split
|
laptop with a PAT answers a different question — see the 204/500 split
|
||||||
|
|
@ -83,48 +84,69 @@ exists rather than assuming it here.
|
||||||
## Arming a candidate ref
|
## Arming a candidate ref
|
||||||
|
|
||||||
A probe that exercises ceremony's own machinery needs the candidate tree
|
A probe that exercises ceremony's own machinery needs the candidate tree
|
||||||
reachable from a `uses:` line. The shape is the drill rehearsal's, reused
|
reachable from a `uses:` line. This is the fork-ref shape `drills/README.md`
|
||||||
rather than reinvented (`drills/README.md` step 2):
|
step 2 points at, written out — and it has **two layers**, which is the part
|
||||||
|
that is easy to get wrong and impossible to fix afterwards.
|
||||||
|
|
||||||
1. **The candidate is a commit SHA, on a fork ref.** Push the candidate tree to
|
**Why two.** The candidate's own workflows contain
|
||||||
a fork under the identity running the probe —
|
`repository: heavy-duty/ceremony` beside `ref: ${{ env.CEREMONY_SELF_REF }}`,
|
||||||
`<identity>/ceremony@probe-<issue>` — and take its canonical SHA. Never
|
so they must be rewritten to point at the fork and at the candidate. But
|
||||||
create a branch on `heavy-duty/ceremony` named like a tag: it shadows that
|
rewriting them **creates a new commit**, and a commit cannot contain its own
|
||||||
tag for every consumer until somebody remembers to delete it.
|
object ID. A single-layer arming is therefore self-referential: pin the callers
|
||||||
2. **Rewrite the COORDINATE, not only the ref.** The candidate SHA exists only
|
to the pre-rewrite SHA and they load the *unarmed* workflows; pin them to the
|
||||||
in your fork, so a stub still saying `heavy-duty/ceremony/...@<sha>` cannot
|
post-rewrite one and you are asking a commit to embed itself
|
||||||
resolve it — it would fail, or worse, resolve something else. In the probe
|
(@codex-reviewer-andresmgsl, #202 review).
|
||||||
repo, every caller `uses:` becomes
|
|
||||||
`<identity>/ceremony/<path>@<canonical-sha>`.
|
|
||||||
3. **Rewrite the candidate's own self-checkout, both halves.** `labels.yml` and
|
|
||||||
the release doors hardcode `repository: heavy-duty/ceremony` beside
|
|
||||||
`ref: ${{ env.CEREMONY_SELF_REF }}`. Changing only the ref makes the
|
|
||||||
candidate fetch your SHA *from the canonical repository*, where it does not
|
|
||||||
exist. So: every `repository:` carrier becomes `<identity>/ceremony`, and
|
|
||||||
both `CEREMONY_SELF_REF` values become the canonical SHA.
|
|
||||||
|
|
||||||
**Then prove the rewrite was total**, because a partial one silently tests
|
So:
|
||||||
canonical `main` instead of the candidate:
|
|
||||||
|
| layer | what it is | what it carries |
|
||||||
|
|---|---|---|
|
||||||
|
| **candidate code SHA** | the immutable tree under test | `actions/`, `lib/` — untouched |
|
||||||
|
| **armed workflow SHA** | a small child commit on top of it | workflows rewritten to the fork + `CEREMONY_SELF_REF` = the candidate code SHA |
|
||||||
|
|
||||||
|
### The procedure
|
||||||
|
|
||||||
|
1. **Push the candidate tree** to a fork under the identity that will run the
|
||||||
|
probe — `<identity>/ceremony@probe-<issue>` — and record its SHA. That is
|
||||||
|
the **candidate code SHA**. Never create a branch on
|
||||||
|
`heavy-duty/ceremony` named like a tag: it shadows that tag for every
|
||||||
|
consumer until somebody remembers to delete it.
|
||||||
|
2. **Commit the arming on top of it.** In that same fork branch, rewrite every
|
||||||
|
workflow carrier — `repository:` → `<identity>/ceremony`, and both
|
||||||
|
`CEREMONY_SELF_REF` values → the **candidate code SHA** from step 1. Record
|
||||||
|
the resulting SHA. That is the **armed workflow SHA**.
|
||||||
|
3. **Pin the probe repo's callers by layer**, because they are not the same
|
||||||
|
thing:
|
||||||
|
- composite-action callers →
|
||||||
|
`<identity>/ceremony/actions/<name>@<candidate-code-sha>`;
|
||||||
|
- reusable-workflow callers →
|
||||||
|
`<identity>/ceremony/.github/workflows/<file>@<armed-workflow-sha>`, since
|
||||||
|
that is the only revision whose inner checkout is rewritten.
|
||||||
|
4. **Gate the rewrite mechanically, against the armed tree** — not against
|
||||||
|
whichever checkout happens to be current, and not by eyeballing prose:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
grep -rn 'heavy-duty/ceremony' .github/ docs/CONSUMERS.md
|
git -C <armed-checkout> grep -nE \
|
||||||
|
'(uses:|repository:)[[:space:]]*heavy-duty/ceremony' -- .github \
|
||||||
|
&& { echo "arming incomplete" >&2; exit 1; }
|
||||||
```
|
```
|
||||||
|
|
||||||
Every remaining hit must be prose. A `uses:`, a `repository:` or a pin among
|
Exit non-zero on any hit. A partial rewrite does not fail loudly on its
|
||||||
them means the probe is not armed, and its result is about the wrong tree.
|
own — it silently tests canonical `main`, and the probe's answer is then
|
||||||
4. **Invoke the probe by the event it is about**, and record which: a
|
about the wrong tree.
|
||||||
`workflow_dispatch` of the caller, or the real board event the probe is
|
5. **Invoke the probe by the event it is about**, and record which: a
|
||||||
testing. A probe that fires a different event than the one under test
|
`workflow_dispatch`, or the real board event under test. A probe that fires
|
||||||
proves something else.
|
a different event than the one under test proves something else.
|
||||||
5. **Record the fork ref, the rewritten pin, the workflow invoked and the run
|
6. **The result issue records all of it**: the fork repository, the candidate
|
||||||
number** in the probe repo's result issue. Those four are what make the
|
code SHA, the armed workflow SHA, every rewritten carrier, the workflow
|
||||||
result reproducible; without the pin especially, a later reader cannot tell
|
invoked and the run number. Those are what make the result reproducible;
|
||||||
which tree answered.
|
without the two SHAs distinguished, a later reader cannot tell which tree
|
||||||
6. **Reset removes the candidate-specific EXECUTABLE state**: the caller stubs,
|
answered.
|
||||||
the probe workflow, the candidate branch — so the next probe cannot inherit
|
7. **Reset removes the candidate-specific EXECUTABLE state**: the caller stubs,
|
||||||
a pin it did not choose. **Result issues are never deleted.** They may be
|
the probe workflow, the candidate and armed branches — so the next probe
|
||||||
closed or relabelled; deleting them would recreate the expiring-log problem
|
cannot inherit a pin it did not choose. **Result issues are never deleted.**
|
||||||
this venue exists to avoid.
|
They may be closed or relabelled; deleting them would recreate the
|
||||||
|
expiring-log problem this venue exists to avoid.
|
||||||
|
|
||||||
## Who may reset it
|
## Who may reset it
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue