Files
felhom.eu/documentation/audits/security-app-updates-2026-10-27/triage-notes/_HELPER-BRIEF.md
T

5.4 KiB

Triage brief for a helper (read-only)

Fences — the brief's own, in full (you need almost none of them, but you carry them all)

  • Forbidden: any ep0 change; any DooPlex change except the catalog push after its STOP (you make NO push and NO commit); a household box by hand; a security_fix step for a major version jump; turning off a check to make a test pass.
  • No test traffic on demo-hp (its host or any guest: 9202, the bench 9401, Tester 1) until the line test has finished. YOU touch no machine at all: no ssh, no pct, no docker, no curl/POST to any box, hub, Gitea or registry write.
  • Rules: secrets never printed or committed; no ep0 change; no branches; no commits; every finding a row, a fix or NOT-A-FINDING: <reason>. Never docker system prune or any Docker cleanup. Stay inside /mnt/5_hdd/felhom.eu/ and the scratchpad. Reading the web (GitHub pages, release notes, vendor docs) is allowed.
  • Your job is READ and WRITE NOTES ONLY, into the scratchpad paths named below. Do not edit any repo file.

Context

Felhom is a managed home server. Each catalog app runs from app-catalog-felhom.eu/templates/<app>/ (docker-compose.yml

  • .felhom.yml). Last night a security watch listed upstream security notices for our pinned versions. You sort them. Per app the data is in <scratchpad>/tri/apps/<app>/data.json: our pins, every GHSA notice in full (description, vulnerable ranges in vulns, severity), and up to 60 recent GitHub releases (tag, date, body). Also <scratchpad>/tri/items.json (the watch's own view, one item per pin, field advisories, including release-note hits whose id starts release:).

Exposure on a Felhom box: EVERY app gets a public HTTPS subdomain through a Cloudflare tunnel, so it is reachable from the internet. Three template fields narrow that (read them in .felhom.yml):

  • family_gate: true — a permanent door: only a household member signed in to the household gate reaches the app at all.
  • setup_gate: true — closed to strangers ONLY until the first admin is created; after that the app is public behind its own login.
  • signup_block: — traefik refuses the app's public sign-up path (strangers cannot create an account). No gate field = the app's own login is the only door (or none). Some apps also have optional features off by default (SSO, federation, mail import...): read the compose env to see whether a vulnerable feature is on in OUR template.

"Main version" = the FIRST number of the version (project rule; 0.20 -> 0.21 is the same main version 0). A step inside the main version may go by the quick "security fix" lane ONLY if the release notes between our pin and the target show no data conversion / migration of files, no removed config, no breaking change. Database schema migrations that the app runs itself on start are normal and fine; a FILE layout change, a required manual step, a changed env var name, a new required service, or a database ENGINE major change (postgres 15 -> 16 etc.) is NOT fine for the quick lane.

What to decide per app

  1. Each notice: REAL (it affects our pinned version, per its ranges or by reading) or NOT-A-FINDING + one-line reason (e.g. "affects only the desktop client we do not ship", "range ends below our pin", "it is about the project's own CI workflow, not the product", "a release-note hit that only mentions the word security"). For release: hits read the release body itself: is it a real security fix of the app (or of its runtime, e.g. Node.js security release bundled in the image)? Say which.
  2. For each REAL notice: severity; needs a login? (none / any user / admin); reachable on a Felhom box with OUR template (consider the gates above and whether the vulnerable feature is enabled in our compose).
  3. The fix: the SMALLEST released version that fixes every real notice; and the recommended TARGET = the newest stable release in the same main version that is >= that fix (stable only, no rc/beta). Give the exact image tag as it would appear in our compose (match our tag style: v prefix or not — check the registry tag naming from our current pin). If the app has TWO+ images (e.g. web + db, server + ml), give each one's target.
  4. Main version same? yes/no. Breaking changes / migrations between our pin and the target, read from the release notes (list them, or "none found" with how many releases you read).
  5. Lane: SECURITY_FIX (same main version, nothing breaking) / BIG_STEP (new main version, or breaking changes) / NO_FIX (a real notice with no fixed release) / NOT_A_FINDING (nothing real). An app can have both (e.g. SECURITY_FIX for some notices + NO_FIX for one) — say so.
  6. A note for the watch's classifier if it flagged something it should not (one line, concrete), else "none".
  7. For NO_FIX notices: what in our template would block it (gate, feature off), and 2 options for the operator with the cost and "if you do nothing".

Output

Write <scratchpad>/tri/apps/<app>/triage.md per app (plain, compact; cite the release tags and GHSA ids you read). Then reply with ONE markdown table, one row per app, columns: | app | our pin(s) | real / total notices | worst real severity | login needed | reachable on a box | smallest fix | TARGET tag(s) | same main | breaking changes | lane | classifier note | Keep the reply under 900 words. Be exact; when unsure, say "unsure: " — never guess a version tag (check the release list / registry tag pages).