From 66d84627b89d5aba233dd5224c40d2e1b98efab8 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Tue, 23 Jun 2026 12:05:29 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20v0.77.0=20open=5Fpath=20=E2=80=94=20REP?= =?UTF-8?q?ORT=20+=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- REPORT.md | 75 ++++++++++++++++++-------------------------- controller/README.md | 2 ++ 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/REPORT.md b/REPORT.md index a23c005..3438d7b 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,49 +1,36 @@ -# REPORT — controller v0.76.0: campaign-#3 hardening (3 fixes) +# REPORT — controller v0.77.0: per-app `open_path` for the "Megnyitás" link -## Baseline → target -`felhom-controller` `main` v0.75.0 → **v0.76.0**. Controller-only; agent/hub untouched. +## Problem +The dashboard / deploy / app-info **"Megnyitás"** (open app) button was hardcoded to the bare subdomain +root `https://{subdomain}.{domain}` for every app. Apps whose useful UI isn't at `/` opened to the wrong +place — e.g. Gokapi's `/` redirects away (its admin is `/admin`), Ghost's `/` is the public blog (admin +is `/ghost/`). -## What changed (commit `b0dd131`) -Three findings from chaos campaign #3, severity-ordered: +## Change (commit `904e787`) +- `internal/stacks/metadata.go`: new optional `Metadata.OpenPath` (`open_path` in `.felhom.yml`), + appended to the open-app URL. Empty = bare root (unchanged behaviour for all other apps). +- Wired into all three link sites via `.Meta.OpenPath` — **no handler changes** (all three templates + already carry `.Meta`): + - `dashboard.html:173` (range over stacks → `.Meta.OpenPath`) + - `deploy.html:18` (`.Meta` from the deploy handler) + - `app_info.html:13` (`.Meta` from the app-info handler) -- **S1 [MEDIUM] — corrupt `settings.json` no longer crash-loops the controller.** - `internal/settings/settings.go`: `save()` writes a last-known-good `.bak` **after** the primary - rename succeeds (best-effort). `Load()` on a parse error recovers from `.bak` (re-promotes to primary), - else preserves the corrupt file as `*.corrupt-` and starts on safe defaults — never returns the - error that drove `main.go`'s `Fatalf`/crash-loop. New `Settings.LoadWarning` → dashboard banner - (`handlers.go` + `dashboard.html`). `main.go` `Fatalf` retained (now only the IO-unreadable path). -- **F2 [MEDIUM, defense-in-depth] — `stack_name` validated against path traversal.** - `internal/web/validate.go` `validStackName` (single segment; rejects `/ \ .. NUL`), gated in - `backupRestoreHandler` (`handlers.go`) and `apiExportStart` (`handler_export.go`) before any - restore/export work. -- **S3 [LOW] — corrupt quiesce marker quarantined, not silently dropped.** - `internal/quiesce/quiesce.go` `readMarker` logs a `[WARN]` + renames a bad-JSON marker to - `*.corrupt-` (still returns "no marker" → no recovery, the correct contract). +## Catalog (app-catalog-felhom.eu, commits `6a71c5a`) +Audited all 53 templates (subagent + cross-check). No Traefik `PathPrefix` anywhere; the only apps whose +bare `/` is not a usable landing: +- `gokapi` → `open_path: "/admin"` (file-share index redirects away) +- `ghost` → `open_path: "/ghost/"` (bare `/` is the public blog; admin/setup at `/ghost/`) +All other 51 serve or redirect usefully at `/` (e.g. plex `/`→`/web/`, radarr/sonarr/gitea/vaultwarden +`/`→`/login`). `onlyoffice` is API-only (status page at `/`) — left at root. -## Tests (green; all red-proofed) -`go build ./... && go vet ./... && go test ./...` — green. -- T-S1a recover-from-bak, T-S1b unrecoverable→safe-defaults+preserve, T-S1c save-writes-bak, T-S1d happy. - Red-proof: revert `Load` to error-on-parse → T-S1a/b FAIL. -- T-F2a `validStackName` (pure), T-F2b restore handler rejects traversal (no nil-deref), T-F2c export - handler → 400. Red-proof: drop the restore gate → traversal falls through to the nil-backupMgr - redirect → T-F2b FAIL. -- T-S3a quarantine+log, T-S3b happy. Red-proof: revert `readMarker` to silent → T-S3a FAIL. +## Validation (live, guest 9201, v0.77.0 healthy) +- Rendered `Megnyitás` href on the gokapi **Beállítások** page: `https://share.demo-felhom.eu/admin` ✓ +- Dashboard hrefs: `share.demo-felhom.eu/admin` for gokapi; **all other apps unchanged** at bare root + (arcade, audiobooks, books, budget, komga, media, paperless, paste, photos, radarr, recipes, status, + tasks) — no regression ✓ +- (Earlier, same session: gokapi's index `RedirectUrl` was also repointed `/`→`/admin` so direct-URL + visitors to the bare root reach the login too.) -## Deploy -Built+pushed `:0.76.0` on 192.168.0.180 (build-server `git pull` done first), deployed to 9201 via -bootstrap. `docker inspect`: `image=:0.76.0 running healthy`. - -## LIVE re-test — the three campaign-#3 scenarios, now fixed -1. **S1:** ensured `.bak`, truncated `settings.json` → restart → `status=running RestartCount=0` - (no crash-loop), logs `[ERROR] primary settings corrupt … — attempting recovery from .bak` → - `[WARN] recovered settings from .bak; re-promoting to primary`; config intact (3 storage_paths), 25/0. -2. **F2:** `POST /backup/restore stack_name=../../../etc` → `flash_error=Érvénytelen alkalmazásnév`, - log `[WARN] restore rejected: invalid stack_name "../../../etc"`, **no "Starting app-data restore"** - (gate fired before the restore logic); `/etc/passwd` intact (24 lines). -3. **S3:** planted a corrupt `quiesce-state.json` → restart → `[WARN] [quiesce] marker … is corrupt … - — quarantining; stacks not auto-recovered`, original renamed to `*.corrupt-`, `RestartCount=0`, - 25/0 (stacks not stranded). - -## Still-open campaign-#3 deferrals (NOT in this task) -Time-chaos on a dedicated VM / injectable clock; host-reboot (supervised); `.fab` import -compose-fuzzing. Agent/hub untouched. +## Notes +- `open_path` must start with `/`. It's purely cosmetic (the open link); routing is unchanged. +- Build/deploy: build-server `git pull` first (build.sh doesn't pull), `:0.77.0` via bootstrap. diff --git a/controller/README.md b/controller/README.md index 603b1fd..f58df6a 100644 --- a/controller/README.md +++ b/controller/README.md @@ -199,6 +199,8 @@ When a user visits a stopped or undeployed app's subdomain (e.g., `travel.demo-f Running apps on the Vezérlőpult now show a "Megnyitás ↗" button that opens the app's subdomain in a new tab. The `Subdomains` map is built in `dashboardHandler` from `app.yaml` env or metadata fallback. +The optional `.felhom.yml` **`open_path`** field (`Metadata.OpenPath`) is appended to that URL for apps whose UI isn't at `/` — e.g. `gokapi` → `/admin`, `ghost` → `/ghost/`. Empty = bare root. Rendered via `.Meta.OpenPath` in `dashboard.html`, `deploy.html`, and `app_info.html` (the same field flows through all three open-link sites; no handler change needed). Must start with `/`; cosmetic only (does not affect routing). + #### App Info Pages Each app can define rich metadata in `.felhom.yml`: