gates: catalog_gates --fast + pre-push hook

--fast selects only gates that touch no network and no container runtime: gate 1
(check-image-pins) runs, image-resolvable and volume-persistence do NOT. Default behaviour with
no flag is unchanged. The skip is ANNOUNCED with the reason and with what still owes a periodic
run — a silently narrowed run reads as 'covered everything' when it did not.

Why the runtime gates are never in a hook: a push that pulls images and starts containers gets
bypassed within a week, and the bypass becomes the habit. They stay deliberate periodic runs at
the start of a catalog campaign, before a publish train, and when a template's volumes: block or
image tag changes — on a scratch host, never a customer box.

.githooks/pre-push runs catalog_gates.py --fast and refuses the push. Per-clone and
--no-verify-able, both stated in the hook itself.

test_catalog_gates.py pins --fast's CONTENT, not just its exit code: the runtime gates must not
run, the skip must be announced, and the no-flag path must still select all three. Red-proofed:
an inert run_gate turns it red.
This commit is contained in:
2026-08-02 15:23:08 +02:00
parent fd7747d129
commit c3e4bb18c7
4 changed files with 146 additions and 8 deletions
+6 -1
View File
@@ -40,7 +40,12 @@ deployed `app.yaml` (customer secrets) is never overwritten. Full deploy details
papra** — it would pass on the exact defect it exists to catch. CI was rejected for now: neither
repo has any, and there are no users yet. **R-161 stays open at reduced scope** — this is
convention, run by a person; real automatic enforcement is owed when a second person touches
templates.
templates. **Update 2026-08-02:** `.githooks/pre-push` now runs `catalog_gates.py --fast` on every
push, which is gate 1 (`check-image-pins.py`) only — the other two need network and a container
runtime and take minutes per app, and a push that pulls images and starts containers gets bypassed
within a week, after which the bypass is the habit. They stay deliberate periodic runs. The hook is
per-clone (`git config core.hooksPath .githooks`) and `git push --no-verify` bypasses it, which is
why R-161's automatic half is still owed — it is now tracked as `felhom.eu` `OPEN-ITEMS.md` R-168.
- **Never `:latest` or untagged images in templates** — pin a concrete version tag; an app deployed
anywhere in the fleet is pinned to the digest it is currently running (a pin must never cause a
version jump). Digest pins (`@sha256:`) also count. Gate: `python scripts/check-image-pins.py`