b7f0f7cef5
gates / gates (push) Failing after 14m4s
60 template directories, 58 offered. Records: onboarding/grocy.md and onboarding/lubelogger.md, all 61 checks answered, none open. Evidence: felhom.eu/documentation/audits/new-apps-2026-10-10/. Grocy 4.7.1 from lscr.io/linuxserver/grocy (grocy publishes no image of its own). SQLite in one volume, no HDD, ~30 MiB idle, amd64 + arm64, Hungarian UI 91.6 %. First admin class 3: it starts with its documented admin/admin and after_install replaces that password with a generated one. LubeLogger v1.7.3 from ghcr.io/hargata/lubelogger. LiteDB in one volume, no HDD, ~60 MiB idle, amd64 + arm64. First admin class 1 — and it has to be: the image ships EnableAuth=false, and with that the middleware mints a ticket with the IsRootUser role for every visitor. Measured on a default start: a stranger got 200 on /, on /api/vehicles and on /Home/Settings and CREATED A VEHICLE. The compose entrypoint exports EnableAuth=true and the SHA-256 of a generated name and password, so the app's own login is on before its first byte (at t+1 s nothing listening, at t+2 s /api/vehicles already 401). Two defects found by the walk and fixed before publishing: 1. An after_install command may not contain `$`. The controller runs every element through os.Expand and refuses one naming anything outside env:, so PHP cannot be inlined. On 9202 the first attempt came back `[pw argv dsn db i t e s n q h] not declared in env or has no value — not run` and the app sat behind its install hold with admin/admin in place. The code now lives in a file the compose entrypoint writes. Written into REUSE.md's after_install row as a trap. 2. Grocy's persisted config.php does not follow the image. The image copies config-dist.php only when that file is absent, so a volume written by 4.6.0 and started under 4.7.1 answered HTTP 500 on every page — AUTH_CLASS names a class 4.7 moved — while its log said migrations done. The entrypoint now deletes the file at every start. The 4.6.0 -> 4.7.1 edge failed before this and is proven after it, on both venues. Ladders, written by upgrade-test.py --write-ladder from both verdicts: grocy 4.6.0 -> 4.7.1 bench proven, box proven (guarded Update, 41 s) lubelogger v1.7.2 -> v1.7.3 bench proven, box proven (25.6 s) Checklist 6.3 came from a real failure, not a forced one: before the config.php fix the product undid the same step in 346 s with the data intact. REUSE.md: a fifth healthcheck family (bash /dev/tcp) for an image with no HTTP client at all, measured in both directions. Tool fixes made on the way: check-onboarding.py crashed on a Windows console while printing which ids were open; upgrade-test.py's read_text/write_text used the platform encoding and wrote a cp1250 em dash into a template full of Hungarian.
88 lines
5.9 KiB
Markdown
88 lines
5.9 KiB
Markdown
# REPORT — 2026-10-10: Grocy and LubeLogger published; Monica stopped at the fit check
|
|
|
|
**What runs on a box changed:** two new apps are offered — `kamra.<domain>` (Grocy) and
|
|
`garazs.<domain>` (LubeLogger). Nothing already installed is touched. **60 template directories, 58
|
|
offered.** Records: `onboarding/grocy.md`, `onboarding/lubelogger.md`, every one of the 61 checks
|
|
answered `done` or `n/a`, none `open`. Evidence:
|
|
`felhom.eu/documentation/audits/new-apps-2026-10-10/`.
|
|
|
|
## The three apps
|
|
|
|
| app | result | what decided it |
|
|
|---|---|---|
|
|
| **Grocy** 4.7.1 | **published** | MIT, alive (3 releases in 2026), SQLite in one volume, ~30 MiB idle, Hungarian UI 91.6 % |
|
|
| **LubeLogger** v1.7.3 | **published** | MIT, very alive (17 releases in 2026), LiteDB in one volume, ~60 MiB idle |
|
|
| **Monica** | **stopped — checklist 0.2** | no release of any kind in 17 months, no stable release in 29, the `4.x` branch untouched since 2024-05-04, and an upstream notice that the hosted instance and its data go at the end of December 2026 before a rewrite. **The operator decides** (R-927) |
|
|
|
|
## The two faults the walk found, both fixed before publishing
|
|
|
|
**1. An `after_install` command may not contain `$`.** The controller runs every element of the command
|
|
through Go's `os.Expand` and refuses one that names anything outside `env:`. Grocy's replacement has to
|
|
use grocy's own `password_hash(..., PASSWORD_ARGON2ID)`, and PHP is the only interpreter in its image
|
|
(measured: no python, no perl, no ruby, no node) — so the code can never be an argument. On 9202 the
|
|
first attempt came back
|
|
|
|
after_install: [pw argv dsn db i t e s n q h] not declared in env or has no value — not run
|
|
|
|
and the app sat behind its install hold with `admin`/`admin` still in place. The code now lives in a
|
|
file the compose entrypoint writes and the command passes only `${ADMIN_PASSWORD}`. **Written into
|
|
`REUSE.md`'s `after_install` row as a trap** — mealie and dawarich avoid it only by language.
|
|
|
|
**2. Grocy could not be updated at all.** The image copies `config-dist.php` to
|
|
`/config/data/config.php` *only if that file is absent*, so the file is written once and never follows
|
|
the image. A volume written by 4.6.0 and started under 4.7.1 answered **HTTP 500 on every page** —
|
|
`Configured AUTH_CLASS "Grocy\Middleware\DefaultAuthMiddleware" does not exist` — while its own log said
|
|
the migrations had run and the init was done. The entrypoint now deletes that file at every start, so
|
|
the image re-copies its current defaults; every setting a household needs is a `GROCY_*` environment
|
|
variable and each person's own choices live in the database. **The edge failed before the fix and is
|
|
`proven` after it, on both venues** — and the failure bought something: the product's own guarded Update
|
|
was watched undoing a REAL failure (backing-up → pulling → copying → verifying → **undone** in 346 s,
|
|
the app back on 4.6.0, the data read back), which is checklist 6.3 without manufacturing a fault.
|
|
|
|
## What LubeLogger ships as, and what we ship
|
|
|
|
`Middleware/Authen.cs` reads `EnableAuth` with a default of `false`, and `appsettings.json` ships it
|
|
false. With it false the middleware **mints a ticket with the `IsRootUser` role for every request**.
|
|
Measured on a default start: an anonymous stranger got 200 on `/`, on `/api/vehicles` and on
|
|
`/Home/Settings`, and `POST /Vehicle/SaveVehicle` answered `{"success":true}` — the vehicle came back
|
|
from the API. Our template's entrypoint exports `EnableAuth=true` and the SHA-256 of a generated name
|
|
and password, so the app's own login is on **before its first byte**: measured from the container's
|
|
creation, at t+1 s nothing was listening and at t+2 s `/api/vehicles` was already 401. No install
|
|
window to close. Sign-up is closed by the app itself (`Invalid Token`).
|
|
|
|
## Catalogue conventions added
|
|
|
|
- **`REUSE.md` §2, a fifth healthcheck family** — bash `/dev/tcp`, for an image with no HTTP client at
|
|
all. `ghcr.io/hargata/lubelogger` has no curl, wget, nc, python or node; it has bash. Measured in both
|
|
directions (rc 0 against the app with an HTTP 200 line, rc 1 against a dead port) before it was
|
|
written down, with its traps: it needs **bash**, not `sh`, and the connect must sit outside the
|
|
pipeline or its failure is invisible.
|
|
- **`REUSE.md` `after_install` row** — the `$` trap above, with the way out.
|
|
|
|
## The ladders
|
|
|
|
| app | step | bench | box 9202 |
|
|
|---|---|---|---|
|
|
| grocy | 4.6.0 → 4.7.1 | **proven** — soak 605 s, 10343 requests, peak anon 6.7 % of 384 M, 0 kills | **proven** — the product's guarded Update, done in 41 s |
|
|
| lubelogger | v1.7.2 → v1.7.3 | **proven** — soak 605 s, 11988 requests, peak anon 12.3 % of 512 M, 0 kills | **proven** — done in 25.6 s |
|
|
|
|
Both written by `upgrade-test.py --write-ladder` from the two verdicts, never by hand.
|
|
|
|
## Tool fixes made on the way (no rows — fixed here, per the size rule)
|
|
|
|
- `scripts/check-onboarding.py` crashed with `UnicodeEncodeError` on a Windows console **while printing
|
|
which ids were still open**, so an informative exit 1 arrived as a traceback. Guarded.
|
|
- `scripts/upgrade-test.py` used `Path.read_text()`/`write_text()`, which take the platform encoding; on
|
|
this workstation the ladder writer put a cp1250 em dash into a template full of Hungarian and the file
|
|
stopped being valid UTF-8. All 26 calls now say `encoding="utf-8"`.
|
|
- The same console trap in **nineteen** of `felhom.eu`'s gate scripts and in `repo_gates.py` itself,
|
|
where it **aborted the whole runner at the first gate**. Guarded there too; `reuse-refs` went from a
|
|
traceback to green. Red-proof for the claim that this was not my doing: `test_due_checks_gate.py`
|
|
fails the same 5 of 42 with my change reverted.
|
|
|
|
## Gates
|
|
|
|
`python3 scripts/catalog_gates.py grocy lubelogger` — all twelve green, the two runtime ones included
|
|
(`image-resolvable` and `volume-persistence`, run on bench 9401 where there is Docker):
|
|
`felhom.eu/documentation/audits/new-apps-2026-10-10/box/*/gates.txt`.
|