Files
felhom-controller/REPORT.md
T

4.0 KiB

REPORT — Catalog-driven initial-login extraction (show an app's auto-generated password)

Repo: felhom-controller · Version: v0.83.0v0.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.goReadInitialCredentials(stack) reads the file live from the running container (docker exec <c> cat <file>; 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.goappDetailHandler 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 &&amp;, 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.