# 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: `. 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//` (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 `/tri/apps//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 `/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 `/tri/apps//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).