diff --git a/CHANGELOG.md b/CHANGELOG.md index 2de4b42..9afe4e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ ## Changelog +### Gate enforcement — one entry point + pre-push hook (2026-08-02) — NO VERSION BUMP + +**Deliberately no version bump, and no build or deploy.** Nothing compiled changed: this touches +`controller/scripts/` and `.githooks/` only, so no behaviour on any box moves. Stated explicitly so +the omission reads as a decision rather than a miss. + +**`controller/scripts/docker_run_volume_path_gate.py` — one allowlist entry, in its own commit +(`c432f70`).** The gate was RED, flagging `internal/appexport/estimate.go:179`. The finding is +benign: `realVolumeSize` mounts a **named Docker volume** read-only into a throwaway alpine to `du` +it from a container view — no host path is involved, the daemon resolves the volume name daemon-side, +and it is structurally identical to the already-allowlisted `internal/backup/backup.go` entry. The +gate was right to demand review; that diff **is** the review, on its own, because burying an +allowlist widening inside a feature commit is how an allowlist stops meaning anything. +`realVolumeSize` was not touched — the code is correct; the allowlist was incomplete. + +**`controller/scripts/controller_gates.py` (new) — THE entry point.** A census of all thirteen gate +scripts across the four felhom repos found that every check a `CLAUDE.md` names was passing and two +of the four nobody is told to run were failing. This repo had seven gates and `CLAUDE.md` named +two; four more were reachable only through a line in `REUSE.md`, and the docker-`-v` gate through one +line in `REUSE.md` and nothing else — while RED. The runner invokes all seven plus `reuse_refs_check` +on the repo root, streams each gate's own output, and exits worst-wins non-zero. `--fast` selects the +gates that touch no network and no container runtime; today that is all eight. + +**The shared checker is never copied here.** `reuse_refs_check.py` lives in `felhom.eu/scripts/` and +is invoked across the workspace at `/../felhom.eu/scripts/`. A copy would recreate exactly +the drift it exists to detect. If the sibling clone is absent the gate **FAILS** and prints the path +tried — fail-closed. On this repo it now resolves 133 cited paths: 126 exact, 6 by suffix, and +`wgsync/reconciler.go` cross-repo into the hub. + +**`.githooks/pre-push` (new)** — runs `controller_gates.py --fast` and refuses the push. Per-clone +(`git config core.hooksPath .githooks`; a manual run WARNS when the clone is unarmed) and +`--no-verify`-able on purpose; both limits are written into the hook. CI is the unbypassable half and +is owed — `felhom.eu` `OPEN-ITEMS.md` R-168. + +**`controller/scripts/test_controller_gates.py` (new, 4 tests)** — a SEAM test asserting each member +gate's own distinctive stdout, never the runner's summary line, which an inert runner prints while +calling nothing. Red-proofed: replacing `run_gate`'s body with `return 0` still prints "all controller +gates OK" and exits 0, and turns the seam test red. + ### v0.188.0 — D5: an app restore works from the drive alone (2026-07-30) — MinAgent 0.113.0 (unchanged) **Tier-1/Tier-2 no longer depend on the whole-guest tier.** Until now the recovery unit on the diff --git a/controller/README.md b/controller/README.md index 5f60476..10df1ca 100644 --- a/controller/README.md +++ b/controller/README.md @@ -162,11 +162,17 @@ backups, monitoring and notifications. All Proxmox/disk operations are delegated logo-less app shows a placeholder on every list surface instead of a hidden icon; infra rows still override with the server glyph. The felhom brand mark is never an app placeholder (brand = platform identity only). - **Enforcement:** `scripts/template_id_gate.py` (JS element-ID integrity) + `scripts/emoji_gate.py` - (no emoji) + `scripts/native_confirm_gate.py` (zero native confirm/prompt) + - `scripts/app_row_dedup_gate.py` (row markup single-sourced) + `scripts/mojibake_gate.py` - (no double-encoded UTF-8 in templates/Go sources) — run after any template change; the Go - `TestNoEmojiInTemplates` mirrors the emoji gate. + **Enforcement — one entry point (2026-08-02):** run `python3 scripts/controller_gates.py` from + `controller/` after any template change. It is THE runner and invokes every gate: + `template_id_gate.py` (JS element-ID integrity), `emoji_gate.py` (no emoji), + `native_confirm_gate.py` (zero native confirm/prompt), `app_row_dedup_gate.py` (row markup + single-sourced), `mojibake_gate.py` (no double-encoded UTF-8 in templates/Go sources), + `docker_run_volume_path_gate.py` (every `docker … -v` mount reviewed), and `reuse_refs_check.py` + on the repo root. It exits non-zero if any gate does, and a missing gate script is a FAILURE, not + a skip. `--fast` (what `.githooks/pre-push` runs) selects the gates that touch no network and no + container runtime — today all of them. The Go `TestNoEmojiInTemplates` mirrors the emoji gate. + Why a runner: of this project's gates, only the ones named by a `CLAUDE.md` entry point ever got + run — the 2026-08-02 census found the two unnamed ones red, one for nineteen days. - **Europe/Budapest timezone** — All scheduled jobs, timestamps, and UI labels use Hungarian timezone. ### Module Map