drills/README.md — the standing runner-probe venue, and why the drill disposal rule does not apply to it (#202) #207
2 changed files with 72 additions and 35 deletions
|
|
@ -33,8 +33,12 @@
|
|||
equal the candidate code SHA, and callers match the layer they belong to
|
||||
(#202).
|
||||
|
||||
- It counts the `CEREMONY_SELF_REF` carriers as well as comparing them, which
|
||||
is what catches one that vanished rather than being rewritten (#202).
|
||||
- It enumerates the carriers from the tree rather than encoding a count, and
|
||||
distinguishes ceremony's internal self-checkouts from the consumer checkouts
|
||||
that must stay `${{ github.repository }}` (#202).
|
||||
|
||||
- The published snippet parses, lints clean and runs: driven against an unarmed
|
||||
tree it refuses, naming the carrier (#202).
|
||||
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -124,43 +124,76 @@ So:
|
|||
- 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 arming POSITIVELY, against the armed tree.** Absence of the old
|
||||
literal is not proof of correct arming: a negative grep stays green if
|
||||
`CEREMONY_SELF_REF` names a tag, the *armed* SHA or some other commit; if a
|
||||
carrier was rewritten to the wrong fork; if an executable carrier lives
|
||||
outside `.github`; or if a carrier simply disappeared
|
||||
(@codex-reviewer-andresmgsl, #202 review). So assert what each carrier
|
||||
**is**, not merely what it is not:
|
||||
4. **Gate the arming POSITIVELY, and against the tree each check is about.**
|
||||
Absence of the old literal proves nothing: a negative grep stays green if
|
||||
`CEREMONY_SELF_REF` names a tag or the *armed* SHA, if a carrier went to the
|
||||
wrong fork, or if a carrier vanished instead of being rewritten. So assert
|
||||
what each carrier **is** — and enumerate them, because the set is a property
|
||||
of the current tree rather than a number to remember
|
||||
(@codex-reviewer-andresmgsl, #202 review).
|
||||
|
||||
**The carriers on `main` today.** Re-derive this list each time rather than
|
||||
trusting it; workflows come and go:
|
||||
|
||||
```sh
|
||||
fork=<identity>/ceremony ; code_sha=<candidate-code-sha> ; armed_sha=<armed-workflow-sha>
|
||||
fail() { echo "arming incomplete: $*" >&2; exit 1; }
|
||||
|
||||
# every self-checkout points at the fork
|
||||
for v in $(git grep -hoP '(?<=repository:\s)\S+' -- .github); do
|
||||
[ "$v" = "$fork" ] || fail "repository: $v"
|
||||
done
|
||||
# both CEREMONY_SELF_REF carriers name the CANDIDATE CODE sha
|
||||
n=0
|
||||
for v in $(git grep -hoP '(?<=CEREMONY_SELF_REF:\s)"?\K[^"]+' -- .github); do
|
||||
[ "$v" = "$code_sha" ] || fail "CEREMONY_SELF_REF: $v"; n=$((n+1))
|
||||
done
|
||||
[ "$n" -eq 2 ] || fail "expected 2 CEREMONY_SELF_REF carriers, found $n"
|
||||
# and in the PROBE repo: workflows pin the armed sha, actions the code sha
|
||||
git grep -hoP '(?<=uses:\s)\S+' -- .github | while read -r u; do
|
||||
case "$u" in
|
||||
*/.github/workflows/*) [ "${u##*@}" = "$armed_sha" ] || fail "workflow caller $u" ;;
|
||||
*/actions/*) [ "${u##*@}" = "$code_sha" ] || fail "action caller $u" ;;
|
||||
esac
|
||||
done
|
||||
# the negative check stays, as a cheap extra rather than as the proof
|
||||
! git grep -qE '(uses:|repository:)[[:space:]]*heavy-duty/ceremony' -- .github \
|
||||
|| fail "canonical coordinate still present"
|
||||
git grep -n 'CEREMONY_SELF_REF:' -- .github/workflows
|
||||
git grep -n 'repository:' -- .github/workflows
|
||||
```
|
||||
|
||||
**A count, not just a comparison** — `n -eq 2` is what catches a carrier
|
||||
that vanished rather than being rewritten, which a per-value loop alone
|
||||
cannot see.
|
||||
| carrier | on current `main` | armed value |
|
||||
|---|---|---|
|
||||
| `CEREMONY_SELF_REF` | `labels-sweep.yml`, `labels.yml`, `release.yml` | the **candidate code** SHA |
|
||||
| internal self-checkout | `labels-sweep.yml`, `labels.yml`, `release.yml` ×2 | `<identity>/ceremony` |
|
||||
| **consumer** checkout | `labels-sweep.yml`, `labels.yml`, `release-exercise.yml` | **unchanged** — `${{ github.repository }}` |
|
||||
|
||||
That third row is the one an over-broad rewrite destroys. Those checkouts
|
||||
fetch the **caller's** repository; pointing them at the fork changes what
|
||||
the probe exercises into something else entirely.
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env bash
|
||||
# check-arming <armed-checkout> <probe-checkout> <fork> <code-sha> <armed-sha>
|
||||
set -euo pipefail
|
||||
armed="$1"; probe="$2"; fork="$3"; code_sha="$4"; armed_sha="$5"
|
||||
fail() { echo "arming incomplete: $*" >&2; exit 1; }
|
||||
|
||||
# (a) every self-ref carrier names the CANDIDATE CODE sha — enumerated, so a
|
||||
# carrier that vanished is a failure rather than one fewer loop pass.
|
||||
mapfile -t refs < <(git -C "$armed" grep -hoP '(?<=CEREMONY_SELF_REF: ")[^"]+' \
|
||||
-- .github/workflows)
|
||||
[ "${#refs[@]}" -gt 0 ] || fail "no CEREMONY_SELF_REF carriers found"
|
||||
for v in "${refs[@]}"; do [ "$v" = "$code_sha" ] || fail "CEREMONY_SELF_REF=$v"; done
|
||||
|
||||
# (b) internal checkouts point at the fork; consumer checkouts stay dynamic.
|
||||
mapfile -t repos < <(git -C "$armed" grep -hoP '(?<=repository: ).*' \
|
||||
-- .github/workflows)
|
||||
for v in "${repos[@]}"; do
|
||||
case "$v" in
|
||||
'${{ github.repository }}') ;; # the caller's repo — must NOT change
|
||||
"$fork") ;; # an internal self-checkout, armed
|
||||
*) fail "repository: $v" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# (c) in the PROBE repo: workflow callers pin the armed sha, action callers
|
||||
# the code sha.
|
||||
mapfile -t uses < <(git -C "$probe" grep -hoP '(?<=uses: ).*' -- .github)
|
||||
for u in "${uses[@]}"; do
|
||||
case "$u" in
|
||||
*/.github/workflows/*@*) [ "${u##*@}" = "$armed_sha" ] || fail "workflow caller $u" ;;
|
||||
*/actions/*@*) [ "${u##*@}" = "$code_sha" ] || fail "action caller $u" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# (d) the negative check, as a cheap extra rather than as the proof.
|
||||
! git -C "$armed" grep -qE '(uses:|repository:)[[:space:]]*heavy-duty/ceremony' \
|
||||
-- .github || fail "canonical coordinate still present"
|
||||
```
|
||||
|
||||
**`mapfile`, not a pipeline.** `git grep | while … fail` runs the loop in a
|
||||
subshell, so `fail` exits *that* subshell and the gate continues. Collect
|
||||
first, validate after — and run under `set -euo pipefail`, which the snippet
|
||||
declares rather than assumes.
|
||||
|
||||
5. **Invoke the probe by the event it is about**, and record which: a
|
||||
`workflow_dispatch`, or the real board event under test. A probe that fires
|
||||
|
|
|
|||
Loading…
Reference in a new issue