Rulings 2026-10-01 built: report, STATUS (standing monthly line), decision 57 (mealie lockout, decided by CC unattended), R-747 narrowed, evidence
gates / gates (push) Successful in 26s
gates / gates (push) Successful in 26s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -16,6 +16,15 @@
|
||||
> and holds nothing of its own; this file does hold its own content, namely the standing rulings below.
|
||||
|
||||
|
||||
> **2026-10-01 — the three rulings built; decision 57 decided by CC unattended (operator may reverse).** 54/55: the first
|
||||
> full monthly re-test — nextcloud `3b59dfb` and sonarr `1a37032` re-tested on both venues and written (~17 min per app);
|
||||
> `retest-floating.py` fixed for a fresh bench (R-749). 56: controller v0.285.0 (keeps running + previous controller image,
|
||||
> previous from the swap record); R-751 nil-stack crash fixed; floor 0.285.0; demo-hp 84 → 2 and N100 76 → 2 controller
|
||||
> images; golden 0.285.0 baked + vouched (gate OK). **57 (R-747):** mealie `SECURITY_USER_LOCKOUT_TIME=1` (catalog
|
||||
> `a4597cd`) — measured 120 min lock on 9202. R-746 digest resolver `804884a`; R-744 outline fixture `9fc7052`.
|
||||
> Opened R-749..R-752 (R-752: calibre-web-automated, wger, Grafana, BookStack lockable by strangers — read, not measured).
|
||||
> Report: `REPORT-rulings-2026-10-01.md`.
|
||||
|
||||
> **Rulings 2026-10-01 (operator) — `09` §3 decisions 54–56, recorded before the work.** **54 (R-743 1A):** the monthly
|
||||
> re-test is run by a CC session the operator starts with the standing brief `claude/MONTHLY-security-retest.md` (project);
|
||||
> STATUS carries "Monthly security re-test: last run <date>, next due <date>". **55 (R-743 2A):** it covers every app with a
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# REPORT — the operator's three rulings of 2026-10-01 built (day session)
|
||||
|
||||
Evidence: `documentation/audits/rulings-2026-10-01/` (A–D, T, tools) · `documentation/audits/retest-2026-10/` (the monthly
|
||||
run) · golden: `documentation/tests/golden-0.285.0-2026-10-01/`.
|
||||
Architecture read: `09` §3 decisions 30, 45, 52, 53 and §6.5; `03-host-agent.md` (the controller swap) with agent
|
||||
`internal/localapi/controllerswap.go`; `07` (R-698); `runbooks/monthly-floating-retest.md`; `audits/night-rulings-2026-09-30/`.
|
||||
Baselines (live Gitea ~07:10 CEST): controller `a70c398` (0.284.2), agent `d766666` (0.138.0), felhom.eu `3159892`, catalog
|
||||
`efd492d`. Register 383 rows by `register_shape_gate`'s method; highest id R-748; last decision 53.
|
||||
|
||||
## The Part table
|
||||
|
||||
| Part | done / not done / changed | why |
|
||||
|---|---|---|
|
||||
| **Rulings 54–56** | **done** — recorded first in `09` §3 and CONTEXT (`2076bf9`) | before any work |
|
||||
| **A — the full re-test** | **done** — nextcloud `3b59dfb` and sonarr `1a37032` re-tested on both venues and written, pushed through the pre-push gates | first start refused in one minute: the script checked the bench for its own files before copying them (R-749, fixed `9e53205`) |
|
||||
| A1 runbook | **done** — every app by default, `--engines-only` the switch, the standing brief, cost | — |
|
||||
| A4 linuxserver cost | **done** — see below | — |
|
||||
| A5 STATUS standing line | **done** — "last run 2026-10-01, next due ~2026-11-01" | — |
|
||||
| **B — two controller versions** | **done — controller v0.285.0**, floor 0.285.0 (MinAgent 0.131.0 declared) | measured first: the agent rolls back to the RUNNING image |
|
||||
| B3 live | **done** on 9202 (version-order fallback) and both demo boxes (the swap record) | 9202's self-update is off (no hub), so the record path was shown on the demo boxes |
|
||||
| — R-751 | **added** — a nil-stack panic in the update clean-up, found by the full suite, fixed in the same release | a panic in a goroutine ends the controller |
|
||||
| **C — mealie** | **done — decided by CC unattended (decision 57):** `SECURITY_USER_LOCKOUT_TIME=1`, catalog `a4597cd`; 9202 proof 120 min | no fix stops an hourly renewal without changing the login name (option d, left open) |
|
||||
| C other apps | **done (read, not measured)** — four more lockable: R-752 | source reading by a sub-agent at each pinned tag |
|
||||
| **D1 — R-746** | **done** `804884a`, red-proofed (unit + live registry) | — |
|
||||
| **D2 — R-744** | **done** `9fc7052`, proven on 9202 at 1.10.1 | outline has no newer release, so no step |
|
||||
| **E — release, floor, golden** | **done** — demo boxes on 0.285.0 within ~6 s; golden 0.285.0 baked, round-trip identical, vouched; the gate prints **OK** | — |
|
||||
|
||||
## Claims in the brief that turned out wrong (or right)
|
||||
|
||||
1. **"`previousImage` … handed to the agent's `SwapController`"** — **wrong.** `SwapController(ctx, target)` carries the
|
||||
target only; `previousImage` goes into `update-state.json`. The agent reads `/etc/felhom-controller-image` when the swap
|
||||
begins and rolls back to THAT — the running image. On all three boxes it equals `<image>:<current version>`, so the
|
||||
practical outcome matches; the mechanism does not.
|
||||
2. **"The sweep skips every controller image today"** — **right**, twice over: the sweep's repositories never include the
|
||||
controller's, and it skips any repo containing `felhom-controller`.
|
||||
3. **"nextcloud and sonarr still differ"** — **right**, and only those two (bookstack, radarr, code-server did not differ today).
|
||||
4. **"mealie's lock is per account"** — **right** (`login_attemps` / `locked_at` on the user). Also: the lock outlives its
|
||||
hours until mealie's HOURLY job resets the counter, so `1` means 1–2 h (measured 120 min).
|
||||
5. **"The golden's image is not needed after first boot"** — right **after the first swap**; until then it IS the running
|
||||
image (kept as such). A whole-guest restore brings its own Docker store (`mp0 backup=1`).
|
||||
6. **"Is an old controller tag still in the registry?"** — **no, below 0.213.0** (2026-08-12): `0.201.0` answers 404. Nobody
|
||||
recorded what removed them (R-750). This session deleted no registry tag.
|
||||
7. "Live on 9202 … after the release" for the record path — 9202 has self-update off; the record path ran on the demo boxes.
|
||||
|
||||
## Part A — the run
|
||||
|
||||
| app | result | bench | box |
|
||||
|---|---|---|---|
|
||||
| nextcloud `34.0.4-apache` | **DONE** — written `3b59dfb` | 05:19–05:32 UTC (proven, peak 23.7 %) | ~5 min: old digest installed, seeded, the guarded Update ran the re-test step, new digest running, read back, badge "Naprakész" |
|
||||
| sonarr `4.0.20` (linuxserver) | **DONE** — written `1a37032` | 05:38–05:50 (proven, peak 13.9 %) | ~3 min, same steps |
|
||||
|
||||
**Monthly cost.** ~17 min per app (bench ~13 incl. the 10-minute watch, box ~4) plus ~15 min to set up and tear down. The
|
||||
four linuxserver apps with ladders (bookstack, radarr, sonarr, code-server) are rebuilt weekly, but the monthly run tests
|
||||
only the day's digest — **at most 4 re-tests a month from them (~70 min of bench, ~16 min of 9202), not 16.** Acceptable.
|
||||
|
||||
## Part B — images before → after
|
||||
|
||||
| box | controller images | Docker images (`system df`) | `/var/lib/docker` used |
|
||||
|---|---|---|---|
|
||||
| 9202 | 5 → 2 | 3.17 → 3.10 GB (layers are shared) | 3.5 → 3.4 GB |
|
||||
| demo-hp 9201 | 84 → 2 (82 deleted) | 15.2 → 11.65 GB | 18 → 15 GB |
|
||||
| N100 9201 | 76 → 2 (74 deleted) | 6.07 → 1.11 GB | 6.0 → 1.2 GB |
|
||||
|
||||
Each kept 0.285.0 (running) and 0.284.2 (previous). Red-proofs (`B/B1-red-proofs.txt`): previous dropped → 0.284.2
|
||||
deleted; record ignored → 0.283.1 deleted; no swap check → deleted while swapping; no in-use check → a used image deleted;
|
||||
no success check → a failed swap's image named previous; no nil-stack check → panic. The first in-use red attempt
|
||||
removed a line and did not build; redone with the condition disabled (recorded).
|
||||
|
||||
## Part C — mealie
|
||||
|
||||
Settings (v3.28.0 source): `SECURITY_MAX_LOGIN_ATTEMPTS` 5, `SECURITY_USER_LOCKOUT_TIME` 24 (hours), per account, lifted
|
||||
by an hourly job; `POST /api/admin/users/unlock` exists but the only admin is the locked account. Fix and 9202 proof: see
|
||||
decision 57 (`C/C1-mealie-lockout-1h.txt`: right password 200 → 5 wrong 401 → 423 → right password 423 for 120 min → 200;
|
||||
a wrong one 401 after). Other apps (R-752): calibre-web-automated (per username, 3/min and 40/day), wger (per IP = traefik's,
|
||||
30 min, everyone), Grafana (per account, 5 min), BookStack (e-mail|IP, 60 s); gokapi and claper cannot.
|
||||
|
||||
## Rows
|
||||
|
||||
**383 → 387.** Opened R-749 (re-test start), R-750 (old registry tags gone), R-751 (update clean-up crash), R-752 (four
|
||||
lockable apps). Closed R-743, R-744, R-745, R-746, R-749, R-751. Narrowed R-747.
|
||||
|
||||
## Teardown
|
||||
|
||||
- **Machine:** 9202 back on the live catalog (`repo_url` read back), the same six containers as at the start, controller
|
||||
0.285.0 (the release); the apps this session installed (nextcloud, sonarr, outline, mealie) removed through the product.
|
||||
Bench 9401 destroyed with its template. Drill VM: CT 9100 destroyed, token/runner/log shredded, qemu exited, reverted to
|
||||
`virgin`. Drill catalog reset to live (`a4597cd`), image lines identical.
|
||||
- **Host:** demo-hp `pct list` = 9201, 9202 (as at the start); the N100 untouched except the floor's controller update.
|
||||
- **Hub:** two form saves — the floor (0.285.0, MinAgent 0.131.0) and the vouch (golden 0.285.0); one floor attempt without
|
||||
the credential answered 302 `/login` and stored nothing.
|
||||
@@ -1,9 +1,90 @@
|
||||
# REPORT — 2026-09-27 evening: a restore and a drive move keep the app's records
|
||||
# REPORT — the operator's three rulings of 2026-10-01 built (day session)
|
||||
|
||||
Evidence: `documentation/audits/records-carried-2026-09-27/` (README = the session record).
|
||||
Evidence: `documentation/audits/rulings-2026-10-01/` (A–D, T, tools) · `documentation/audits/retest-2026-10/` (the monthly
|
||||
run) · golden: `documentation/tests/golden-0.285.0-2026-10-01/`.
|
||||
Architecture read: `09` §3 decisions 30, 45, 52, 53 and §6.5; `03-host-agent.md` (the controller swap) with agent
|
||||
`internal/localapi/controllerswap.go`; `07` (R-698); `runbooks/monthly-floating-retest.md`; `audits/night-rulings-2026-09-30/`.
|
||||
Baselines (live Gitea ~07:10 CEST): controller `a70c398` (0.284.2), agent `d766666` (0.138.0), felhom.eu `3159892`, catalog
|
||||
`efd492d`. Register 383 rows by `register_shape_gate`'s method; highest id R-748; last decision 53.
|
||||
|
||||
- `07` §6.6: new paragraph "What a restore keeps from the app it replaces" (and: a drive move is not a restore).
|
||||
- Register: 336 → 337 rows. Opened R-700 (WATCHING, live proof open), R-701 (demo-hp restore test refused for space); closed R-697 (to
|
||||
`CLOSED-ITEMS.md`); R-691 annotated: (2) not built, and why.
|
||||
- Hub: no code change; global floor 0.276.0 (MinAgent 0.131.0) via `POST /configuration/global-floor`.
|
||||
- STATUS and CONTEXT updated. Capability map: not changed.
|
||||
## The Part table
|
||||
|
||||
| Part | done / not done / changed | why |
|
||||
|---|---|---|
|
||||
| **Rulings 54–56** | **done** — recorded first in `09` §3 and CONTEXT (`2076bf9`) | before any work |
|
||||
| **A — the full re-test** | **done** — nextcloud `3b59dfb` and sonarr `1a37032` re-tested on both venues and written, pushed through the pre-push gates | first start refused in one minute: the script checked the bench for its own files before copying them (R-749, fixed `9e53205`) |
|
||||
| A1 runbook | **done** — every app by default, `--engines-only` the switch, the standing brief, cost | — |
|
||||
| A4 linuxserver cost | **done** — see below | — |
|
||||
| A5 STATUS standing line | **done** — "last run 2026-10-01, next due ~2026-11-01" | — |
|
||||
| **B — two controller versions** | **done — controller v0.285.0**, floor 0.285.0 (MinAgent 0.131.0 declared) | measured first: the agent rolls back to the RUNNING image |
|
||||
| B3 live | **done** on 9202 (version-order fallback) and both demo boxes (the swap record) | 9202's self-update is off (no hub), so the record path was shown on the demo boxes |
|
||||
| — R-751 | **added** — a nil-stack panic in the update clean-up, found by the full suite, fixed in the same release | a panic in a goroutine ends the controller |
|
||||
| **C — mealie** | **done — decided by CC unattended (decision 57):** `SECURITY_USER_LOCKOUT_TIME=1`, catalog `a4597cd`; 9202 proof 120 min | no fix stops an hourly renewal without changing the login name (option d, left open) |
|
||||
| C other apps | **done (read, not measured)** — four more lockable: R-752 | source reading by a sub-agent at each pinned tag |
|
||||
| **D1 — R-746** | **done** `804884a`, red-proofed (unit + live registry) | — |
|
||||
| **D2 — R-744** | **done** `9fc7052`, proven on 9202 at 1.10.1 | outline has no newer release, so no step |
|
||||
| **E — release, floor, golden** | **done** — demo boxes on 0.285.0 within ~6 s; golden 0.285.0 baked, round-trip identical, vouched; the gate prints **OK** | — |
|
||||
|
||||
## Claims in the brief that turned out wrong (or right)
|
||||
|
||||
1. **"`previousImage` … handed to the agent's `SwapController`"** — **wrong.** `SwapController(ctx, target)` carries the
|
||||
target only; `previousImage` goes into `update-state.json`. The agent reads `/etc/felhom-controller-image` when the swap
|
||||
begins and rolls back to THAT — the running image. On all three boxes it equals `<image>:<current version>`, so the
|
||||
practical outcome matches; the mechanism does not.
|
||||
2. **"The sweep skips every controller image today"** — **right**, twice over: the sweep's repositories never include the
|
||||
controller's, and it skips any repo containing `felhom-controller`.
|
||||
3. **"nextcloud and sonarr still differ"** — **right**, and only those two (bookstack, radarr, code-server did not differ today).
|
||||
4. **"mealie's lock is per account"** — **right** (`login_attemps` / `locked_at` on the user). Also: the lock outlives its
|
||||
hours until mealie's HOURLY job resets the counter, so `1` means 1–2 h (measured 120 min).
|
||||
5. **"The golden's image is not needed after first boot"** — right **after the first swap**; until then it IS the running
|
||||
image (kept as such). A whole-guest restore brings its own Docker store (`mp0 backup=1`).
|
||||
6. **"Is an old controller tag still in the registry?"** — **no, below 0.213.0** (2026-08-12): `0.201.0` answers 404. Nobody
|
||||
recorded what removed them (R-750). This session deleted no registry tag.
|
||||
7. "Live on 9202 … after the release" for the record path — 9202 has self-update off; the record path ran on the demo boxes.
|
||||
|
||||
## Part A — the run
|
||||
|
||||
| app | result | bench | box |
|
||||
|---|---|---|---|
|
||||
| nextcloud `34.0.4-apache` | **DONE** — written `3b59dfb` | 05:19–05:32 UTC (proven, peak 23.7 %) | ~5 min: old digest installed, seeded, the guarded Update ran the re-test step, new digest running, read back, badge "Naprakész" |
|
||||
| sonarr `4.0.20` (linuxserver) | **DONE** — written `1a37032` | 05:38–05:50 (proven, peak 13.9 %) | ~3 min, same steps |
|
||||
|
||||
**Monthly cost.** ~17 min per app (bench ~13 incl. the 10-minute watch, box ~4) plus ~15 min to set up and tear down. The
|
||||
four linuxserver apps with ladders (bookstack, radarr, sonarr, code-server) are rebuilt weekly, but the monthly run tests
|
||||
only the day's digest — **at most 4 re-tests a month from them (~70 min of bench, ~16 min of 9202), not 16.** Acceptable.
|
||||
|
||||
## Part B — images before → after
|
||||
|
||||
| box | controller images | Docker images (`system df`) | `/var/lib/docker` used |
|
||||
|---|---|---|---|
|
||||
| 9202 | 5 → 2 | 3.17 → 3.10 GB (layers are shared) | 3.5 → 3.4 GB |
|
||||
| demo-hp 9201 | 84 → 2 (82 deleted) | 15.2 → 11.65 GB | 18 → 15 GB |
|
||||
| N100 9201 | 76 → 2 (74 deleted) | 6.07 → 1.11 GB | 6.0 → 1.2 GB |
|
||||
|
||||
Each kept 0.285.0 (running) and 0.284.2 (previous). Red-proofs (`B/B1-red-proofs.txt`): previous dropped → 0.284.2
|
||||
deleted; record ignored → 0.283.1 deleted; no swap check → deleted while swapping; no in-use check → a used image deleted;
|
||||
no success check → a failed swap's image named previous; no nil-stack check → panic. The first in-use red attempt
|
||||
removed a line and did not build; redone with the condition disabled (recorded).
|
||||
|
||||
## Part C — mealie
|
||||
|
||||
Settings (v3.28.0 source): `SECURITY_MAX_LOGIN_ATTEMPTS` 5, `SECURITY_USER_LOCKOUT_TIME` 24 (hours), per account, lifted
|
||||
by an hourly job; `POST /api/admin/users/unlock` exists but the only admin is the locked account. Fix and 9202 proof: see
|
||||
decision 57 (`C/C1-mealie-lockout-1h.txt`: right password 200 → 5 wrong 401 → 423 → right password 423 for 120 min → 200;
|
||||
a wrong one 401 after). Other apps (R-752): calibre-web-automated (per username, 3/min and 40/day), wger (per IP = traefik's,
|
||||
30 min, everyone), Grafana (per account, 5 min), BookStack (e-mail|IP, 60 s); gokapi and claper cannot.
|
||||
|
||||
## Rows
|
||||
|
||||
**383 → 387.** Opened R-749 (re-test start), R-750 (old registry tags gone), R-751 (update clean-up crash), R-752 (four
|
||||
lockable apps). Closed R-743, R-744, R-745, R-746, R-749, R-751. Narrowed R-747.
|
||||
|
||||
## Teardown
|
||||
|
||||
- **Machine:** 9202 back on the live catalog (`repo_url` read back), the same six containers as at the start, controller
|
||||
0.285.0 (the release); the apps this session installed (nextcloud, sonarr, outline, mealie) removed through the product.
|
||||
Bench 9401 destroyed with its template. Drill VM: CT 9100 destroyed, token/runner/log shredded, qemu exited, reverted to
|
||||
`virgin`. Drill catalog reset to live (`a4597cd`), image lines identical.
|
||||
- **Host:** demo-hp `pct list` = 9201, 9202 (as at the start); the N100 untouched except the floor's controller update.
|
||||
- **Hub:** two form saves — the floor (0.285.0, MinAgent 0.131.0) and the vouch (golden 0.285.0); one floor attempt without
|
||||
the credential answered 302 `/login` and stored nothing.
|
||||
|
||||
@@ -2,54 +2,56 @@
|
||||
|
||||
**Ready for the first real tester (Tester-2): yes. You confirmed the tunnel route and the connect mails (2026-09-30).**
|
||||
|
||||
**Updated 2026-09-30 (late evening). Both demo boxes run controller 0.284.2 and host agent 0.138.0. Hub 0.126.0. New installs get golden 0.284.2 with agent 0.138.0.**
|
||||
**Updated 2026-10-01. Both demo boxes run controller 0.285.0 and host agent 0.138.0. Hub 0.126.0. New installs get golden 0.285.0 with agent 0.138.0.**
|
||||
|
||||
**Tester-2 — read only, from the hub.** The customer record exists. Tester-2's box has not registered yet.
|
||||
|
||||
## Your two decisions of tonight — built
|
||||
## A decision I took myself (you may reverse it)
|
||||
|
||||
- **Security fixes under the same name (your A).** The catalog can now re-test a database image's new fix and record
|
||||
it as a tested step. A box then takes it at night by itself. Tested from start to end on the scratch box: the night
|
||||
run took the fix, the app kept its data, and the page went back to "up to date". **Today there was nothing to re-test**
|
||||
for the database and redis images.
|
||||
- **Old program files on the disk (your A).** A box now keeps each app's current program and the one before it, and
|
||||
deletes the older ones. It never deletes one that another app still uses. On the first start it cleaned up once:
|
||||
**the HP demo box freed 11 GB**, the scratch box 21 GB. All apps kept running.
|
||||
- **mealie: a stranger can now lock the household out for 1 to 2 hours, not a whole day.** mealie locks the account after
|
||||
five wrong passwords, and its login name is public. I set the lock to mealie's shortest time (1 hour; its hourly
|
||||
clean-up makes it up to 2). Tested on the scratch box: locked for 2 hours, then the right password worked. The guard
|
||||
against password guessing stays. **What it does not fix:** a stranger can lock it again every hour. The other way would
|
||||
be a secret login name, but that changes what the household types — so I did not do it.
|
||||
|
||||
## Your three decisions of today — built
|
||||
|
||||
- **The monthly security re-test covers every tested app (your 2A).** First full run today: **nextcloud and sonarr** had
|
||||
a new build under the same name. Both passed on the test bench and on the scratch box, and are now in the catalog. Boxes
|
||||
take them at night. It took about 17 minutes per app.
|
||||
- **You start the monthly run (your 1A).** Give the standing brief `MONTHLY-security-retest.md` to CC once a month. The
|
||||
runbook now says so.
|
||||
- **A box keeps only two controller versions (your 3A).** The new controller 0.285.0 deletes the older ones. The HP demo
|
||||
box went from 84 versions to 2 (Docker images 15.2 → 11.7 GB). The N100 went from 76 to 2 (6.1 → 1.1 GB). All apps kept
|
||||
running. I checked first: if an update fails, the box goes back to the version it was running, and that one is always kept.
|
||||
|
||||
## What else I did, and it worked
|
||||
|
||||
- **The short login risk is closed.** After an install, an app with a known default password is now closed to
|
||||
strangers until the box has changed that password. Tested on two apps: no stranger got in.
|
||||
- **wger's phone app can log in** now (its missing key is made at the first start).
|
||||
- **New controller 0.284.2** is on both demo boxes, and **a new golden 0.284.2** is baked and vouched. The golden check
|
||||
is green (not just waived).
|
||||
- **A crash fixed.** The image clean-up after an app update could crash the controller if the app was removed right
|
||||
after. The test suite found it. Fixed in 0.285.0.
|
||||
- **Two test-tool fixes:** the digest check now refuses an image build that is gone, and the outline test works with
|
||||
outline's newest version.
|
||||
- **New controller 0.285.0** is on both demo boxes, and **a new golden 0.285.0** is baked and vouched. The golden check is
|
||||
green.
|
||||
|
||||
## What broke, and what I did
|
||||
|
||||
- **The clean-up first missed most images.** Two mistakes, both found on the scratch box before any demo box got the
|
||||
release: it did not run on the Remove button, and it could not see images stored without a name. Both fixed and
|
||||
tested. That is why the version is 0.284.2 (0.284.0 and 0.284.1 never went out).
|
||||
- **wanderer** can now run on the test bench, but its update is not tested yet: I could not create test data in it.
|
||||
Also found: its search engine needs one extra setting before any update, or it refuses to start.
|
||||
- **Two exact versions were rebuilt by their makers under the same name** (nextcloud and sonarr). The monthly re-test
|
||||
finds them. Tonight I only did the database images, as you ruled.
|
||||
- **mealie locks the account after five wrong passwords** — also when a stranger types them. Written down.
|
||||
- **Old controller versions** still pile up on each box (about 50). Your rule covered apps only. Written down.
|
||||
- **The monthly re-test could not start on a fresh test bench.** It checked for its own files before it copied them. Fixed.
|
||||
- **Four more apps can be locked by strangers like mealie:** calibre-web (up to a day), wger (30 minutes, and everyone at
|
||||
once), Grafana (5 minutes), BookStack (1 minute). I read this in their code; not tested on a box yet. Written down.
|
||||
- **Very old controller versions are gone from our own registry** (everything before mid-August). Nothing needs them
|
||||
today. I do not know what removed them. Written down.
|
||||
|
||||
**Rows.** Tonight: 5 closed, 3 narrowed, 6 opened. The list went from 377 to 383 rows (counted with every row, including three whose number has a letter — the old check skipped those).
|
||||
**Rows.** Today: 6 closed, 1 narrowed, 4 opened. The list went from 383 to 387 rows.
|
||||
|
||||
## What needs you
|
||||
|
||||
1. **Who presses the monthly re-test?** It is one command, but it needs the test bench and the scratch box set up
|
||||
first, so it cannot run by itself (the steps are written down). Options: CC does it in a monthly session, or you
|
||||
start it. If nobody presses it, same-name security fixes wait until the next time we move that app.
|
||||
2. **Should the monthly re-test cover every app, or only databases?** Exact versions get rebuilt too (nextcloud,
|
||||
sonarr). If you do nothing, only databases are re-tested.
|
||||
3. **Old controller versions:** keep only the current and the previous one? If you do nothing, about 150 MB per release
|
||||
keeps piling up.
|
||||
4. **No golden bake is due** — tonight's bake carries the newest controller.
|
||||
1. **Nothing urgent.** If you want the household to be safe from the hourly re-lock in mealie, say so: then I give it a
|
||||
secret login name, and the app page shows it. If you do nothing, a stranger who keeps trying can keep mealie locked.
|
||||
2. **Do you know what removed the old controller versions from the registry?** If you do nothing, I look at the Gitea
|
||||
settings next time (read only).
|
||||
|
||||
## Standing steps
|
||||
|
||||
- **Monthly:** the same-name security re-test (runbook `monthly-floating-retest.md`).
|
||||
- **Weekly:** the golden bake (around 7 October).
|
||||
- **Monthly security re-test: last run 2026-10-01, next due ~2026-11-01.** (You start it with the standing brief.)
|
||||
- **Weekly:** the golden bake (around 8 October).
|
||||
|
||||
@@ -621,6 +621,21 @@ R-636's louder repeated alarm.
|
||||
**Why:** about 50 old controller versions sat on each demo box (R-745); a release is ~400 MB unpacked and several ship
|
||||
a day. Registry tags are never deleted by this.
|
||||
|
||||
### 2026-10-01 — decided by CC unattended, operator may reverse
|
||||
|
||||
57. **mealie's account lock lasts 1 hour (in practice 1–2 h), not 24** — *decided by CC unattended 2026-10-01 (R-747) —
|
||||
operator may reverse.* **Question:** how long may a stranger's five wrong passwords lock the household out of mealie?
|
||||
**Options:** (a) keep mealie's default 24 h — the strongest guard against guessing, and a stranger who knows the public
|
||||
login (`admin` / `changeme@example.com`) locks the household out for a day; (b) `SECURITY_USER_LOCKOUT_TIME=1` — the
|
||||
unit's minimum; mealie's hourly job lifts it, so 1–2 h; still 5 tries per lock against guessing; (c) no lock (a huge
|
||||
attempt limit) — strangers cannot lock anyone out, and nothing slows guessing but the hash; (d) rename the login to
|
||||
something unguessable after install — the guard stays and strangers cannot aim it, but it changes what the household
|
||||
types and what the app page shows. **Why (b):** the brief prefers a short lockout over none; a household would not
|
||||
notice the weaker guard (5 tries per 1–2 h against a generated 30-character first password); (d) changes a promise on
|
||||
the page and stays open as an option. **Measured on 9202:** 5 wrong → the right password 423 for 120 min, then 200; a
|
||||
wrong one 401 after. **Limit, stated:** the lock is per account and the name is public, so a stranger can renew it
|
||||
every hour. Catalog `a4597cd`.
|
||||
|
||||
### 2026-09-30 (day) — operator notes, recorded before the work
|
||||
|
||||
- **The day brief runs by day.** Every backup and automatic-update test is started by hand — the night chain's debug
|
||||
|
||||
@@ -28,3 +28,64 @@
|
||||
06:34:53 +18 min right password: 423
|
||||
06:36:53 +20 min right password: 423
|
||||
06:38:53 +22 min right password: 423
|
||||
06:40:53 +24 min right password: 423
|
||||
06:42:53 +26 min right password: 423
|
||||
06:44:53 +28 min right password: 423
|
||||
06:46:53 +30 min right password: 423
|
||||
06:48:53 +32 min right password: 423
|
||||
06:50:53 +34 min right password: 423
|
||||
06:52:53 +36 min right password: 423
|
||||
06:54:53 +38 min right password: 423
|
||||
06:56:53 +40 min right password: 423
|
||||
06:58:53 +42 min right password: 423
|
||||
07:00:53 +44 min right password: 423
|
||||
07:02:53 +46 min right password: 423
|
||||
07:04:53 +48 min right password: 423
|
||||
07:06:53 +50 min right password: 423
|
||||
07:08:53 +52 min right password: 423
|
||||
07:10:53 +54 min right password: 423
|
||||
07:12:53 +56 min right password: 423
|
||||
07:14:53 +58 min right password: 423
|
||||
07:16:53 +60 min right password: 423
|
||||
07:18:53 +62 min right password: 423
|
||||
07:20:53 +64 min right password: 423
|
||||
07:22:53 +66 min right password: 423
|
||||
07:24:53 +68 min right password: 423
|
||||
07:26:54 +70 min right password: 423
|
||||
07:28:54 +72 min right password: 423
|
||||
07:30:54 +74 min right password: 423
|
||||
07:32:54 +76 min right password: 423
|
||||
07:34:54 +78 min right password: 423
|
||||
07:36:54 +80 min right password: 423
|
||||
07:38:54 +82 min right password: 423
|
||||
07:40:54 +84 min right password: 423
|
||||
07:42:54 +86 min right password: 423
|
||||
07:44:54 +88 min right password: 423
|
||||
07:46:54 +90 min right password: 423
|
||||
07:48:54 +92 min right password: 423
|
||||
07:50:54 +94 min right password: 423
|
||||
07:52:54 +96 min right password: 423
|
||||
07:54:54 +98 min right password: 423
|
||||
07:56:54 +100 min right password: 423
|
||||
07:58:54 +102 min right password: 423
|
||||
08:00:54 +104 min right password: 423
|
||||
08:02:54 +106 min right password: 423
|
||||
08:04:54 +108 min right password: 423
|
||||
08:06:54 +110 min right password: 423
|
||||
08:08:54 +112 min right password: 423
|
||||
08:10:54 +114 min right password: 423
|
||||
08:12:54 +116 min right password: 423
|
||||
08:14:54 +118 min right password: 423
|
||||
08:16:55 +120 min right password: 200
|
||||
08:16:55 RESULT: locked for 120 min (last answer 200)
|
||||
08:16:55 right password again: 200 | a wrong one after: 401
|
||||
08:16:58 INFO 2026-10-01T10:12:54 - [192.168.0.180:0] 423 Locked "POST /api/auth/token HTTP/1.1"
|
||||
ERROR 2026-10-01T10:14:54 - User is locked out from 192.168.0.180
|
||||
ERROR 2026-10-01T10:14:54 - User is locked out from 192.168.0.180
|
||||
INFO 2026-10-01T10:14:54 - [192.168.0.180:0] 423 Locked "POST /api/auth/token HTTP/1.1"
|
||||
INFO 2026-10-01T10:16:22 - locked users reset
|
||||
|
||||
10:17:00 [X] stop -> 200 {'ok': True, 'message': 'Stack mealie stop completed'}
|
||||
10:17:32 [X] remove (with drive data) -> 200 {'ok': True, 'data': {'removed': 'mealie', 'volumes_removed': ['mealie_mealie_data'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'hdd_note': 'Az alkalm
|
||||
10:17:40 [X] after remove: deployed=False leftovers='/opt/docker/stacks/mealie'
|
||||
08:17:40 removed: False
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# The operator's three rulings of 2026-10-01 built (day session)
|
||||
|
||||
Report and Part table: `felhom.eu/REPORT-rulings-2026-10-01.md`. Monthly run evidence: `../retest-2026-10/`. Golden:
|
||||
`documentation/tests/golden-0.285.0-2026-10-01/`.
|
||||
|
||||
| folder | what |
|
||||
|---|---|
|
||||
| `A/` | the bench created (60 GB, swap 0), the drill reset, 9202 pointed at the drill, 9202's containers before |
|
||||
| `B/` | controller image retention: `B0` the boxes before, `B1` red-proofs, `B2` 9202 deploy + pass (`B2-9202-selfupdate.txt` is empty: that attempt found self-update off on 9202 and was stopped), `B3`/`B4`/`B5` demo boxes before, the floor, after |
|
||||
| `C/` | mealie: `C0` the drill-only commit, `C1` the 1-hour lock measured as a stranger (120 min) |
|
||||
| `D/` | `D1` R-746 digest resolver (unit red + live registry), `D2` R-744 outline fixture on 9202 |
|
||||
| `T/` | teardown: bench destroyed, 9202 back on live, drill reset |
|
||||
| `tools/` | `walk.py`, `repoint.py` (this folder's paths), `b_9202.py`, `b_selfupdate.py`, `c_mealie.py`, `d_outline.py` |
|
||||
@@ -0,0 +1,15 @@
|
||||
git:
|
||||
branch: main
|
||||
repo_url: https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git
|
||||
sync_interval: 15m
|
||||
token: <redacted>
|
||||
username: ""
|
||||
hub:
|
||||
0
|
||||
|
||||
felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.285.0
|
||||
filebrowser gtstef/filebrowser:1.3.3-stable
|
||||
paperless-postgres postgres:18-alpine
|
||||
paperless-redis redis:7-alpine
|
||||
paperless-webserver ghcr.io/paperless-ngx/paperless-ngx:2.20.15
|
||||
traefik traefik:v3.6.7
|
||||
@@ -0,0 +1,5 @@
|
||||
# drill reset 2026-10-01T08:18:54Z
|
||||
drill before: df5a2a2; live: a4597cd
|
||||
df5a2a2 DRILL mealie: SECURITY_USER_LOCKOUT_TIME=1 (R-747 proof on 9202)
|
||||
drill after: a4597cd
|
||||
image lines IDENTICAL
|
||||
@@ -858,7 +858,7 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server`
|
||||
| **R-744** | **[P3-LOW] outline's fixture cannot seed outline 1.10.1: no `csrfToken` cookie after `installation.create`.** MEASURED 2026-09-30 on both venues (bench and 9202, the end-to-end re-test's first attempt): `POST /api/installation.create` answered 302 with the session, and `GET /home` set no `csrfToken` cookie (1.9.1 did; the 1.9.1 → 1.10.1 step read back that afternoon because its read-back uses the API key made at 1.9.1). So the NEXT outline step, and any re-test of outline, stops at C1 with „no csrfToken cookie from GET /home". **Needs:** the fixture reads outline 1.10.1's CSRF the way its page does (measure first). `audits/night-rulings-2026-09-30/A/e2e/*outline-attempt*` **-- 2026-10-01:** Outline 1.10 names the cookie `__Host-csrfToken` on a secure request (`server/utils/csrf.ts`); the fixture accepts both names (catalog `9fc7052`). Proven on 9202 at the live pin 1.10.1: seed, read back, unknown id and wrong key refused. Outline has no newer release than 1.10.1, so no step. `audits/rulings-2026-10-01/D/D2-outline-fixture-9202.txt` | **CLOSED 2026-10-01 — fixture fixed, proven on 9202** |
|
||||
| **R-745** | **[P3-LOW] Old CONTROLLER images are never deleted: ~50 versions on each demo box.** MEASURED 2026-09-30 after v0.284.2's one-time sweep: every image no container uses on demo-hp and on the N100 is a `felhom-controller` tag (0.201.0 … 0.283.1); the N100 still reads 3.6 GB reclaimable. Decision 53 covers APP images, and the sweep leaves the controller's own images alone on purpose (the self-update may need the previous one). A release is ~150 MB and there are several a day. **Needs:** the same rule for the controller — keep the running and the previous tag — as a decision (the self-update's rollback reads which image?). `audits/night-rulings-2026-09-30/E/` **-- 2026-10-01:** Decision 56 built: controller v0.285.0 keeps the running image + the previous (the swap record; version order as fallback), deletes older/untagged ones. **Measured first:** the agent rolls back to the RUNNING image (what `/etc/felhom-controller-image` named), never to a previous one the controller hands it. After the floor: demo-hp 84 → 2 controller images (Docker images 15.2 → 11.65 GB), the N100 76 → 2 (6.07 → 1.11 GB), 9202 5 → 2. `audits/rulings-2026-10-01/B/` | **CLOSED 2026-10-01 — controller v0.285.0, floor 0.285.0** |
|
||||
| **R-746** | **[P3-LOW] `image_digest.resolve` ignores a `@digest` in its argument — it answers the TAG's current digest.** MEASURED 2026-09-30: `resolve('redis:7-alpine@sha256:000…0')` returned `sha256:858f…` (the tag's), while a manifest request for that digest answers 404. Every gate today passes it a plain tag, so no gate is wrong; a caller that passes `ref@digest` to ask "is THIS digest still served" gets a false yes. **Needs:** refuse a digest-carrying ref, or ask for the manifest by digest (with a test). `scripts/image_digest.py` **-- 2026-10-01:** `resolve()` asks the registry for the manifest BY DIGEST when the ref carries one; a malformed digest is refused without a request (catalog `804884a`, `scripts/test_image_digest.py`; red: the old resolver fails 3 of 4). Live: `redis:7-alpine@sha256:000…0` → HTTP 404 (was the tag's digest). `audits/rulings-2026-10-01/D/D1-r746-digest.txt` | **CLOSED 2026-10-01 — catalog 804884a** |
|
||||
| **R-747** | **[P3-LOW] A stranger can lock the household out of mealie with five wrong logins.** MEASURED 2026-09-30 on 9202 (the R-741 proof): after the install hold opened, a stranger's default-login tries were refused (401) and after five of them mealie answered 423 (locked) to every login — the generated, correct password included. mealie's own brute-force guard, on an app published on the internet; the setup gate and the install hold do not cover an app after its first setup. Not measured: how long the lock lasts. **Needs:** measure the lock's length; decide whether the page tells the household what to do. `audits/night-rulings-2026-09-30/C/C3-mealie-poll.txt` | **READY — rank P3-LOW; owner: CC** |
|
||||
| **R-747** | **[P3-LOW] A stranger can lock the household out of mealie with five wrong logins.** MEASURED 2026-09-30 on 9202 (the R-741 proof): after the install hold opened, a stranger's default-login tries were refused (401) and after five of them mealie answered 423 (locked) to every login — the generated, correct password included. mealie's own brute-force guard, on an app published on the internet; the setup gate and the install hold do not cover an app after its first setup. Not measured: how long the lock lasts. **Needs:** measure the lock's length; decide whether the page tells the household what to do. `audits/night-rulings-2026-09-30/C/C3-mealie-poll.txt` **-- 2026-10-01:** Measured at v3.28.0 (source + 9202): 5 wrong logins lock the ACCOUNT (not the IP) for `SECURITY_USER_LOCKOUT_TIME` hours (default 24); the lock is lifted by an hourly job; an admin can unlock others via `POST /api/admin/users/unlock`, but the household's only admin is the locked account. Both login names are public (`admin`, `changeme@example.com`). **Fixed** (`09` §3 decision 57, decided by CC unattended — operator may reverse): `SECURITY_USER_LOCKOUT_TIME=1`, catalog `a4597cd`; on 9202 the right password answered 423 for 120 min, then 200; a wrong one still 401 (`audits/rulings-2026-10-01/C/`). **Left:** a stranger can renew the lock every hour (per account, public name — option (d) in decision 57 would end that); the page does not tell the household why it is locked; an INSTALLED mealie takes the new setting only when its compose is rendered again (not measured which act does that). | **NARROWED — the lock is 1–2 h; renewal and the page remain; owner: CC** |
|
||||
| **R-748** | **[P3-LOW] The register-shape gate skipped every row whose id has a letter suffix — so R-88a, R-88b and R-209a were never shape-checked, and its count read 3 short.** FOUND 2026-09-30 (late) while counting the register: `register_shape_gate.py` matched `R-\d+` only; the brief's „the reviewer's regex undercounted by 3” is the same three rows. Fixed the same session: `R-\d+[a-z]?`; decoy `suffix-row-eaten-state` (a suffixed row with its state cell eaten) seen passing with the old pattern and convicted with the new. The register is **382** rows by either count now. | **CLOSED 2026-09-30 — `scripts/register_shape_gate.py`** |
|
||||
| **R-749** | **[P3-LOW] `retest-floating.py` could never start on a fresh bench: it checked for `/opt/upg/upgrade-test.py` on the bench BEFORE the step that copies it there.** FOUND 2026-10-01 at the first full monthly run (decision 55): bench 9401 freshly created by the runbook, the run answered „CANNOT START — missing: the bench LXC 9401 on demo-hp with /opt/upg” in one minute. The runbook says the command syncs the bench itself — it does, but only after the check. On 2026-09-30 the bench had been synced by hand earlier, so nobody saw it. **Needs:** the check asks for what the bench must bring (docker, python3), the sync then provides `/opt/upg`. `audits/rulings-2026-10-01/A/` **-- 2026-10-01:** Fixed the same session (catalog `9e53205`): the check asks for docker + python3; after the sync `/opt/upg/upgrade-test.py` is required. The re-run started at once and finished both apps. | **CLOSED 2026-10-01 — catalog 9e53205** |
|
||||
| **R-750** | **[P3-LOW] The registry no longer holds controller releases older than 0.213.0 (2026-08-12) — something removed them, and nothing records what.** MEASURED 2026-10-01 (anonymous registry API, `audits/rulings-2026-10-01/B/`): `felhom-controller` has 91 tags, the oldest release 0.213.0; `0.201.0` answers 404; Gitea's package list starts 2026-08-12. No runbook, row or memory names a clean-up. Today nothing needs those versions: a box runs a newer one, a whole-guest restore brings the guest's own Docker store back (mp0 `backup=1`), and decision 56 deletes only on the box. **But** a box or a backup that names a removed version cannot pull it again (R-698's shape, for the controller). **Needs:** find what removed them (a Gitea clean-up rule?), and record the rule — or say it was a one-time act. Read-only on DooPlex. | **OPEN — rank P3-LOW; owner: operator (Gitea settings), CC measures** |
|
||||
|
||||
Reference in New Issue
Block a user