Commit Graph

612 Commits

Author SHA1 Message Date
admin 3c1e91b5f0 v0.85.0: self-update reworked — in-guest pull + agent swap (Phase 1)
Replaces the dead in-container docker-compose self-update (composePath doesn't
exist in the LXC guest). The controller now docker-logins+pulls the target image
in-guest (shared socket, its registry token), then delegates the container swap to
the host agent (agentapi.SwapController -> POST /controller/swap), which owns the
restart + health-verify + rollback. Removed performUpdate compose flow /
updateComposeFile / composePath. NewUpdater takes an AgentSwapper. DryRun reports
agent_reachable + pull_capable. UI button + poll unchanged; latest-only.

Tests: up-to-date no-op / pull-fail agent-not-called / happy pull-then-swap /
no-agent unavailable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
2026-06-26 21:26:14 +02:00
admin e0cf78bb90 docs: v0.84.0 REPORT/CONTEXT/README — catalog-driven initial-login extraction 2026-06-26 11:03:56 +02:00
admin 1705d71dd5 v0.84.0: catalog-driven initial_credentials — read an app's auto-generated first-login from a file and show it on the app page 2026-06-26 11:00:06 +02:00
admin 49f6dbf847 docs: v0.83.0 REPORT/CONTEXT/README — scoped Traefik serversTransport for self-signed HTTPS backends 2026-06-26 10:33:16 +02:00
admin 2d6df0f6d5 v0.83.0: Traefik scoped insecure-skip-verify serversTransport for self-signed HTTPS backends (fixes crafty 502) 2026-06-26 10:28:58 +02:00
admin 5c08dcfc35 REPORT: live verification of v0.82.0 on guest 9201 (F2 no-op + change paths, F1 NO-RESTIC)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpBYrZCt9sFDqLgbG5GRGD
2026-06-24 11:06:44 +02:00
admin 9cd566ded7 v0.82.0: gate FileBrowser recreate on actual change (F2); drop unused restic binary (F1)
syncFileBrowserMounts no longer force-recreates FileBrowser unconditionally:
captures config.yaml+compose before writes, re-reads final content after, and
recreates only when they actually changed (new pure helper fbNeedsRecreate).
Controller restarts / no-op storage syncs now issue a plain up -d and do NOT
bounce the customer's file UI. Restore-mode DB reset still forces a recreate.

Dockerfile: removed the unused restic apt package (disk-tier restic moved to the
host agent; no controller code execs the binary). ResticSchedule/migrateResticToRsync
config+settings paths untouched (still live in the dashboard).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpBYrZCt9sFDqLgbG5GRGD
2026-06-24 11:01:18 +02:00
admin 036a6078bb docs: REPORT.md — v0.81.0 deployed to guest 9201 + live-verified
Banner gone, "Kiszolgáló újraindítása" card present + ordered after the
controller-restart card, /api/server/reboot -> 202, /api/storage/activate -> 404,
/api/selfrestart regression OK. Live end-to-end reboot of guest 9201 confirmed
via agent logs (guest back up, drives re-bound, controller recovered healthy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 18:54:09 +02:00
admin 7109e88e07 docs: REPORT.md for v0.81.0 (server-reboot button / banner retirement)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 18:47:28 +02:00
admin 242b835a19 v0.81.0: retire drive-activation banner; add standalone "Kiszolgáló újraindítása" button
In the intermediary-mount model an enrolled drive binds live into the running
guest (no reboot), so the "… meghajtó aktiválásra vár / Újraindítás most" banner
was an obsolete relic — also dead since v0.78 (pendingActivationDrives keyed on
the raw MountPath vs the now-stable sp.Path). Removed the banner block +
activatePendingDrives JS (settings.html), the PendingDrives feed (handlers.go),
and the dead pendingActivationDrives helper + its unused internal/system import.

Renamed handleStorageActivate -> HandleServerReboot (split out a testable
serverReboot core), removed the /api/storage/activate case, and mounted the
handler at the new non-storage route /api/server/reboot (RequireAuth+CsrfProtect).
The agent GuestReboot primitive is reused unchanged.

Added the standalone "Kiszolgáló újraindítása" settings card (sibling to the
controller-only "Vezérlő újraindítása"), reusing the pollRestart() loop.

Test: TestHandleServerReboot_CallsGuestReboot (fake diskAgent asserts GuestReboot
invoked once + 202). diskAgent/mockAgent gained GuestReboot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 18:46:31 +02:00
admin 7cce19797e REPORT: v0.80.0 deployed + verified — disk card shows/acts on the stable path
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:57:25 +02:00
admin fc94d91d15 v0.80.0: disk card shows + acts on the stable path, not the raw host mount
The storage card displayed each external drive's raw host PVE mount (/mnt/<name>,
which doesn't exist in the guest) instead of the stable in-guest path
(/mnt/felhom-drives/<name> = guest_path) the registry/HDD_PATH/FileBrowser use.
The eject/wipe buttons also posted the raw path, so they would unmount the drive
but leave the stable registry entry orphaned, and the impact warning found no apps.

Fix: card sub-line + eject/wipe buttons use the stable path (regKey); type-to-confirm
name uses the basename; register keeps the raw path. handleStorageWipe maps to raw
via agentWhere() for the agent eject (matching handleStorageEject). Agent ops
unchanged (same raw paths); display + registry bookkeeping corrected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:54:21 +02:00
admin 9596c8e563 REPORT: v0.79.0 deployed + verified — disk view keys registered on stable path (badge/button now correct)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:45:05 +02:00
admin a9f0de4c63 v0.79.0: disk view keys the "registered" check on the stable path
Follow-up to v0.78.0. The disk-view JS (settings.html regBadge/actions) checked
registration by the raw mount_path, but the registry stores the stable path since
v0.78.0 — so enrolled drives showed a spurious "Nem regisztrált" badge + Register
button. Fix: regKey(d) = d.guest_path || d.mount_path (agent reports the stable
guest_path per disk); registerDrive still posts the raw path. Display-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:42:37 +02:00
admin 081c1cd77f REPORT: v0.78.0 deployed to 9201 + registry remediated — drives now register at the stable path, 2 connected, badge+banner gone
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:37:12 +02:00
admin 68e7e07838 v0.78.0: storage register uses the STABLE intermediary path, not the raw path
handleStorageRegister (the "Regisztrálás" action for an already-mounted,
unregistered drive) registered the raw /mnt/<name> path verbatim, unlike
runStorageInit/runStorageAttach which map to the stable /mnt/felhom-drives/<name>
path the agent actually binds the drive at. The controller then watched an empty
placeholder dir on the guest rootfs → "Rendszermeghajtón" + stuck "activation
pending" banner after a re-provision.

Fix: register stablePathForName(path.Base(req.Where)); attachIntoGuest still uses
the raw path (the agent operates on raw). Test + red-proof added.

Diagnosis: felhom.eu/documentation/audits/DIAGNOSE-drive-bind-after-reprovision-2026-06-23.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:28:07 +02:00
admin 66d84627b8 docs: v0.77.0 open_path — REPORT + README 2026-06-23 12:05:29 +02:00
admin 904e787dda v0.77.0: per-app open_path for the Megnyitás link
Optional .felhom.yml open_path appended to the open-app URL in dashboard/deploy/app-info
(via .Meta.OpenPath). Empty=bare root. Fixes apps whose UI isn't at / (gokapi /admin, ghost /ghost/).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 12:01:12 +02:00
admin 0b7163e5af docs: v0.76.0 REPORT/CONTEXT — campaign-#3 hardening fixes + live re-test evidence
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:39:20 +02:00
admin b0dd13154b v0.76.0: campaign-#3 hardening (settings .bak recovery, restore stack_name validation, quiesce marker quarantine)
S1: corrupt settings.json recovers from .bak / safe-defaults+preserve, no crash-loop.
F2: validStackName gates restore + export handlers (reject /,\,..,NUL traversal).
S3: corrupt quiesce marker logged + quarantined, not silently dropped.
Tests T-S1/F2/S3 + red-proofs. Agent/hub untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 23:34:33 +02:00
admin 141d51bf19 test campaign #3: Phase 7 brutal recovery (B1-B3 PASS, B4 skip) + final findings/cleanup
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 22:04:55 +02:00
admin eb5cd8375e test campaign #3: Phase 6 security fuzzing (F1-F4; no tree escape; restore stack_name validation gap finding)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:51:46 +02:00
admin f40fedfbfc test campaign #3: Phase 5 network partitions (N1 tunnel block, N2 PBS block mid-backup — fail-safe + unquiesce, both PASS)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:40:11 +02:00
admin 7187ef6b62 test campaign #3: Phase 4 time chaos SKIP (unprivileged guest shares host clock; host jump risks certs/DooPlex)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:31:33 +02:00
admin 8845496c0e test campaign #3: Phase 3 concurrency storms (C1 mutex, C2 flap+gate, C3 agent-kill unquiesce — all PASS)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:30:08 +02:00
admin 850f0d4568 test campaign #3: Phase 2 state corruption (S1 settings crash-loop FINDING; S2/S3/S4 pass; symlink no-exfil)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:23:05 +02:00
admin 192bb30a4b test campaign #3: Phase 1 resource starvation (R1-R4 fail-safe held)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:16:45 +02:00
admin ee014b3005 test campaign #3: Phase 0 floor (baseline + verified PBS backup, gate open)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:05:26 +02:00
admin 8b4b9011dd docs: v0.75.0 REPORT/CONTEXT — userdata mountpoint gate + boot-ordering design note + live C6 proof
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:55:08 +02:00
admin 0b2605c5a8 v0.75.0: gate userdata MkdirAll on a live mountpoint (no writes into an absent drive)
Belt (ensureUserdataMounts) + FileBrowser sync skip ensure/mount when an external
drive root is not a live mountpoint -> no 'mkdir userdata: permission denied' + no
rootfs-shadow during a drive-absent window. System/local path never gated. Reuses
system.IsMountPoint; matches planDriveGates external-only rule. T1-T4 + red-proofs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:47:08 +02:00
admin 9d47232d7f test campaign #2: Phase 5 skip (host reboot) + final matrix/findings/cleanup
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:09:57 +02:00
admin 608cd02dd4 test campaign #2: Phase 4 (concurrent-restore mutex + stopped-stack backup PASS; snapshots-404 + additive-restore gaps re-confirmed)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:07:51 +02:00
admin 61b2dc02a4 test campaign #2: Phase 3 C7-C8 (quiesce crash-safety + reboot-during-op PASS); phase complete
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:04:08 +02:00
admin dce2362245 test campaign #2: Phase 3 C4-C6 (C5 app.yaml graceful, C6 drive-eject recover + recreate-noise finding, C4 skip)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:50:38 +02:00
admin 3ee26c575f test campaign #2: Phase 3 C1-C3 (kill app/controller/agent — chaos; docker restart-policy not honored finding)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:44:04 +02:00
admin d07848a786 test campaign #2: Phase 2 (storage lifecycle unblocked — disconnect/reconnect + decommission/re-enroll PASS; loopback blocked by agent whitelist)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:34:15 +02:00
admin d3f1b9d323 test campaign #2: Phase 1 (app sweep + edge cases — navidrome HDD-bound, redeploy race PASS)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:22:42 +02:00
admin 1190e56a2c test campaign #2: Phase 0 (baseline + safety net + leak-fix gate PASS)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:18:49 +02:00
admin c208ddf308 docs: v0.74.0 REPORT/CONTEXT/README — agent connection-leak fix + live proof
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:52:12 +02:00
admin 2a5b88fbf9 v0.74.0: fix controller->agent connection leak (reuse one agentapi client)
agentClient() built a new agentapi.Client (new bare http.Transport, IdleConnTimeout:0)
per call and discarded it without closing idle conns -> one leaked idle ESTABLISHED
socket per call to the agent :8443, exhausting the ephemeral port range after ~5 days
(EADDRNOTAVAIL). Memoize one shared client via sync.Once; harden Transport
(MaxIdleConns/PerHost + IdleConnTimeout 90s). Agent/firewall untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:19:24 +02:00
admin 0bfb481c2a test campaign: Phase 7 (guest reboot PASS) + final feature matrix, findings, cleanup, after-state
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:15:37 +02:00
admin 258d13ede4 test campaign: Phase 6 results (monitoring/alerts/notification email/settings/hub DR-recipe-pbs-coord verified)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:05:22 +02:00
admin b9b233e537 test campaign: Phase 5 results (storage observe PASS; UI mgmt blocked by controller->agent 8443 defect)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:55:37 +02:00
admin d1d5ff4964 test campaign: Phase 4 results (DR rebuild verified via restore-test + deep 9300 restore, collision-safe)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:49:31 +02:00
admin 7b906cfe3f test campaign: Phase 3 results (backup DB-dump + Tier-2 + restore verified; 2 findings)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:36:08 +02:00
admin 3b0bacab9b test campaign: Phase 2 results (deploy sweep; gitea HC fix + glance defect logged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:25:51 +02:00
admin e6577c53da test campaign: Phase 0 + Phase 1 results (baseline, PBS backup, komga HC fix verified)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:12:45 +02:00
admin f3146ac7bf controller v0.73.0: DR recipe — emit secret-free customer+apps half in hub report
DR recipe slice (controller half), grounded in SPIKE-dr-recipe-2026-06-16. The
controller emitter is the BOUNDARY enforcement point: v1 ships an explicit
allowlist {catalog_ref, enabled, storage_bindings} and reads NOTHING from
AppConfig.Env, so no ENC:/token/password can leak. storage_bindings parsed from
the compose (${HDD_PATH}/${USERDATA_PATH} volume binds -> {container_path,
drive, subpath}).

Load-bearing tests: TestBuildAppRecipe_NoSecrets (synthetic-secret app -> none
leak) + TestBuildAppRecipe_AllowlistIsLoadBearing (red-proof companion) +
TestAppStorageBindings + TestBuildDRRecipeAppHalf. Red-proofed live: forcing the
emitter to dump Env makes the boundary test fail. recipe_version=1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 18:38:59 +02:00
admin 0d159d7e34 docs: REPORT/CHANGELOG/README — v0.72.0 FileBrowser boot-recreate convergence + live x2 reboot acceptance
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 18:09:58 +02:00
admin 6ea25388d7 controller v0.72.0: FileBrowser converges on boot-recreate
processGuestBootChange recreated the drive-backed app stacks but never re-synced
FileBrowser (base-infra, no HDD_PATH), so its drive mounts went stale after a
reboot. Now, AFTER pollLiveBinds confirms the live binds and the apps are
recreated, trigger go s.SyncFileBrowserMounts() so FileBrowser converges against
the now-live drives. Refactored into pure recreateDriveBackedApps(stacks, present,
recreate, syncFB). Tests: FB sync runs once after recreate (red-proofed companion);
runs even when nothing recreated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:37:12 +02:00