Files
app-catalog-felhom.eu/REPORT.md
T
admin b7f0f7cef5
gates / gates (push) Failing after 14m4s
Grocy and LubeLogger: two new apps, each with its complete record
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.
2026-10-10 12:31:34 +02:00

5.9 KiB

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.