docs(runner-probes): restore !207's release notes; per-run links; honest security lesson
All checks were successful
CI / test (pull_request) Successful in 3m15s
CI / release-exercise (pull_request) Successful in 11s
CI / self-guards (pull_request) Successful in 7s
CI / action-exercise (pull_request) Successful in 6s
CI / docs-sync-exercise (pull_request) Successful in 6s
Refs guard / refs-not-closing (pull_request) Successful in 6s
labels / labels (pull_request) Successful in 8s
All checks were successful
CI / test (pull_request) Successful in 3m15s
CI / release-exercise (pull_request) Successful in 11s
CI / self-guards (pull_request) Successful in 7s
CI / action-exercise (pull_request) Successful in 6s
CI / docs-sync-exercise (pull_request) Successful in 6s
Refs guard / refs-not-closing (pull_request) Successful in 6s
labels / labels (pull_request) Successful in 8s
Four corrections from @codex-reviewer-andresmgsl on 9c17a9e:
- changelog.d/202.md keeps !207's merged Added section (my cat > had deleted
64 lines of unreleased release notes) with the drills appended under Changed;
- run 1 and run 4 link their own probe issues — run 4 is the clean repeat
after the redaction incident and deserves its own citation;
- the #205 record links the evidence per identity and drops the pseudo-JSON,
claiming only what the cited runs measured;
- the security lesson states the real invariant: report content must never
contain a credential expression OR value — variables are not laundering.
Refs #202
This commit is contained in:
parent
9c17a9e4d8
commit
07a32c4fa8
2 changed files with 91 additions and 13 deletions
|
|
@ -1,11 +1,76 @@
|
|||
### Added
|
||||
|
||||
- `docs/RUNNER-PROBES.md` documents the standing runner-probe venue,
|
||||
`heavy-duty/ceremony-runner-probe` — the place runner-only facts are measured
|
||||
on demand, ruled as option A by the operator (#202).
|
||||
|
||||
- `drills/README.md` cross-links it beside the disposal rule, so the exception
|
||||
is visible where the dangerous habit lives (#202).
|
||||
|
||||
- The runbook states that the drill disposal rule does **not** apply to it.
|
||||
Archiving it defeats its purpose, and that is exactly how the three existing
|
||||
drill repos each became unavailable (#202).
|
||||
|
||||
- It records that a probe must run as an Actions job under the workflow token:
|
||||
the same call answers 500 there and 204 under a PAT, so a probe run any other
|
||||
way produces a confident wrong answer (#202).
|
||||
|
||||
- Creating the repo is recorded as the operator's step, measured rather than
|
||||
assumed: a fleet identity gets 403 on org repo creation and 201 in its own
|
||||
namespace (#202).
|
||||
|
||||
- It carries an executable two-layer arming procedure: an immutable candidate
|
||||
code SHA and an armed workflow commit on top of it. A single layer is
|
||||
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).
|
||||
|
||||
- The arming gate asserts what each carrier IS, not only that the old literal
|
||||
is gone: every `repository:` equals the fork, every `CEREMONY_SELF_REF` value
|
||||
equal the candidate code SHA, and callers match the layer they belong to
|
||||
(#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).
|
||||
|
||||
- Both published snippets are ShellCheck-clean when extracted and linted
|
||||
directly, not merely as part of the repository sweep (#202).
|
||||
|
||||
- The checker validates the MANIFEST against the target it was given, so a
|
||||
manifest that describes a wrong arming consistently — wrong fork, or the
|
||||
armed SHA where the candidate belongs — refuses instead of matching a tree
|
||||
rewritten to the same wrong value (#202).
|
||||
|
||||
- The manifest is generated from the PRE-arming tree, which is the only order
|
||||
that enumerates the carriers that must change (#202).
|
||||
|
||||
- Both published snippets were driven against a constructed candidate/probe
|
||||
pair: deletion, both role swaps, wrong owner, wrong
|
||||
SHA, wrong path, a deleted caller class and an extra carrier all refuse, and
|
||||
the armed control passes (#202).
|
||||
|
||||
- The manifest records complete caller coordinates, so a path swapped under the
|
||||
right owner and SHA is caught (#202).
|
||||
|
||||
- Generator and checker share one domain — ceremony callers — so a third-party
|
||||
`actions/checkout` is neither manifested nor reported as unrecognised (#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
|
||||
live board (#202).
|
||||
|
||||
### Changed
|
||||
|
||||
- `docs/RUNNER-PROBES.md` records the venue's first delivered drills: the
|
||||
- `docs/RUNNER-PROBES.md` records the venue's first delivered drills — the
|
||||
#192 asymmetry re-observed on demand under the workflow token, the dispatch
|
||||
route's 204 under both identities, and #215's boundary finding — each with
|
||||
the probe-issue URL it is recorded in (#202).
|
||||
|
||||
- Two venue lessons join the runbook where the next probe author will look:
|
||||
findings must be written to issues because the venue's log route 404s for
|
||||
non-admin reads, and report templates must never interpolate `${{ … }}`
|
||||
expressions (#202).
|
||||
non-admin reads, and report content sent to the forge must never contain a
|
||||
credential expression or value (#202).
|
||||
|
|
|
|||
|
|
@ -345,13 +345,22 @@ memory.
|
|||
afterward — the failure observable in the set, not merely a status — then
|
||||
`PUT` full-set clear → **200**, set actually empty. Record:
|
||||
[probe issue #1](https://forgejo.heavyduty.builders/heavy-duty/ceremony-runner-probe/issues/1)
|
||||
(runs 1 and 4).
|
||||
(run 1) and
|
||||
[probe issue #2](https://forgejo.heavyduty.builders/heavy-duty/ceremony-runner-probe/issues/2)
|
||||
(run 4 — the clean independent repeat after the redaction incident below).
|
||||
- **ceremony#205** — DELIVERED with a correction to the line above's
|
||||
premise. The dispatch route answers **204** to a valid
|
||||
`{"ref":"refs/heads/<branch>" | "<branch>", "inputs":{…}}` under both a PAT
|
||||
and the workflow token; the earlier opaque `500` came from a bare
|
||||
unresolvable ref or an unknown/unparseable workflow — the diagnostic !213
|
||||
ships now names this. The `GET /actions/workflows` listing still 404s.
|
||||
premise. The dispatch route answers **204** to a valid body carrying the
|
||||
bare resolvable ref `main` — under the workflow token
|
||||
([ceremony#205 comment #6263](https://forgejo.heavyduty.builders/heavy-duty/ceremony/issues/205#issuecomment-6263),
|
||||
run 504, and again as
|
||||
[probe issue #4](https://forgejo.heavyduty.builders/heavy-duty/ceremony-runner-probe/issues/4),
|
||||
run 6) and under a PAT
|
||||
([probe issue #5](https://forgejo.heavyduty.builders/heavy-duty/ceremony-runner-probe/issues/5),
|
||||
run 7, and ceremony run 459). The earlier opaque `500` came from a bare
|
||||
UNRESOLVABLE ref or an unknown/unparseable workflow — the diagnostic !213
|
||||
ships now names this; a fully-qualified bad ref gets a clean 404 instead.
|
||||
The `GET /actions/workflows` listing still 404s. Claims here are limited to
|
||||
what those runs measured.
|
||||
- **ceremony#215** — the discriminator drill: REST-body `inputs` DO reach a
|
||||
top-level dispatched workflow, both contexts
|
||||
(`inputs.*` and `github.event.inputs.*`), both identities. What loses the
|
||||
|
|
@ -368,7 +377,11 @@ look:
|
|||
- **Rule 4 is load-bearing on this instance**: the probe repo's web log route
|
||||
404s for non-admin reads, and a log-only observation (run 2) was lost where
|
||||
issue-written ones were not.
|
||||
- **Never let a report template interpolate `${{ … }}`** — an escaped
|
||||
`${{ github.token }}` in a comment body was expanded by the runner into the
|
||||
recorded text (the run's ephemeral token; redacted in place). Build report
|
||||
strings from plain shell variables only.
|
||||
- **Report content sent to the forge must never contain a credential
|
||||
expression OR a credential value** — moving a secret from `${{ … }}` syntax
|
||||
into a shell variable does not make it safe to emit. Name identities in
|
||||
literal prose ("the workflow token"), allowlist the fields a report emits,
|
||||
and treat anything else as unsendable. The incident this teaches from: an
|
||||
escaped `${{ github.token }}` in a comment template was expanded by the
|
||||
runner into the recorded text (the run's ephemeral token); it was redacted
|
||||
in place and the drill repeated clean (probe issue #2, run 4).
|
||||
|
|
|
|||
Loading…
Reference in a new issue