# REPORT — Catalog-driven initial-login extraction (show an app's auto-generated password) **Repo:** `felhom-controller` · **Version:** `v0.83.0` → **`v0.84.0`** · **Date:** 2026-06-26 **Commit:** `1705d71` · **Paired catalog commit:** `app-catalog-felhom.eu` `8fd9c00` **Deployed:** guest 9201 (`demo-felhom`) on `felhom-pve`, golden/bootstrap mechanism. ## Problem Some apps generate a random first-login password into a file at first boot instead of taking it from a deploy field — Crafty writes one to `/crafty/app/config/default-creds.txt` (its built-in default is rejected as "too short"). Customers had to read the container logs to find it; the static `app_info.default_creds` hint can't carry a per-install secret. ## Fix — a general, catalog-driven mechanism (Crafty is the first consumer) - **`.felhom.yml`** gains an optional `initial_credentials` block: `{file, format: json|regex|plain, container?, username_key/password_key (json), username_pattern/password_pattern (regex), note}`. - **`internal/stacks/metadata.go`** — new `InitialCredentials` struct + `Metadata.InitialCreds` (deep-copied in `deepCopyStack`). - **`internal/stacks/initialcreds.go`** — `ReadInitialCredentials(stack)` reads the file **live** from the running container (`docker exec cat `; path passed as a single arg, no shell) and parses it via the pure, unit-tested `parseInitialCreds` (json/regex/plain). Container defaults to the stack's main container (`findProbeContainer`). Returns a non-Available result (card hidden) when the container is down / file missing / parse fails. **Never persists the secret** to `app.yaml` — read on demand. - **`internal/web/handlers.go`** — `appDetailHandler` populates `InitialCreds` for deployed apps with a spec; **`app_info.html`** renders a "Kezdeti belépési adatok" card: username + masked password with Megjelenítés/Másolás (value read from a hidden element — never inlined into a JS literal), clearly labelled as the **initial** password (valid only until the customer changes it in-app). - **Tests:** `parseInitialCreds` json (+ default key) / regex (+ missing-pattern) / plain / unknown-format. `go build`, `go vet`, `go test ./internal/stacks/...` all green. ## Catalog (`8fd9c00`) crafty-controller `.felhom.yml` gains the `initial_credentials` block (json, username/password keys, a note) and `first_steps` now points at the app page instead of "find it in the logs". ## Security posture This surfaces a **live working credential** on the app page — same exposure class as the existing post-deploy password reveal and the `default_creds` card, and rendered with the same mask/reveal UX. It relies on the dashboard being **auth-gated in production**; the demo's public-unauth dashboard is a separate, pre-existing tracked issue (not introduced here). The secret is never written to controller state — only read live from the volume where it already lives. ## Verification (live, guest 9201, controller v0.84.0) | Check | Result | |---|---| | Spec synced + parsed | on-disk `.felhom.yml` carries `initial_credentials`; `/api/stacks/crafty-controller` meta shows it | | Card renders | `/apps/crafty-controller` HTML contains the "Kezdeti belépési adatok" card | | Username | `initcred-user` cell renders `admin` | | Password (live-extracted) | hidden value element carries the exact password from the container's `default-creds.txt` (HTML-escaped `&`→`&`, decoded back by JS `textContent`) | | Controls | `Felhasználónév` label + `icRevealPw`/`icCopyPw` reveal/copy wired | **Method:** fetched the exact HTML the browser receives via the in-guest API (Host: felhom.demo-felhom.eu). The reveal/copy is client-side JS — wiring confirmed in markup, not browser-clicked this run. ## Observation (carry, not acted on) The whole-dashboard public-unauth exposure on the demo remains the right place to fix credential visibility broadly — tracked separately; this feature should not be read as endorsing an unauthenticated dashboard.