diff --git a/CHANGELOG.md b/CHANGELOG.md index a76e2f6..d1c4bd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,20 @@ - **R-972 — felhom-samba 1.2.0:** Alpine 3.21 → 3.24.2 (digest-pinned), same packages (Samba 4.23.8). `SambaImage` bumped. `build-samba-image.sh` now refuses a tag already in the registry, a registry it cannot ask, and a dirty or unpushed tree — like `build.sh`; `scripts/test_samba_build_push_once.sh` (6 cases, 4 fail on the old script). +- **Live on demo-hp 9201 (rc.1, through the dashboard's own posts):** 0.18.1 restored a snapshot 0.14.0 made, byte-identical + to a 0.14.0 restore of it; the off-site run (dumps + push, live progress bar) 186 → 202 snapshots in 3m33s; a DB app + (Rallly) and a drive-folder app (Grimmory) seeded, pushed, removed with data and backups, reinstalled (negative + control: nothing there), restored from the off-site copy — the row and the file (sha256) came back. The full restore + then left both apps unusable for a reason that is NOT restic: the old database volume keeps the old install's + password, the reinstall made a new one (Rallly crash-loops on auth, Grimmory held stopped) — FILED R-1106 (R-127's + class). Samba: on 1.1.0 then on 1.2.0 with the same household password — smbclient write/read from DooPlex, wrong + password refused, nmbd, mDNS, WS-Discovery all answer; `testparm` clean on Samba 4.23.8. Every kept tool runs, every + removed one is gone, no „executable not found" in the log. +- **Scanner (trivy 0.74.0, critical/high, fixable in brackets):** controller 0.322.0 4 (0) / 140 (4) → 0.323.0-rc.1 + **3 (2) / 122 (52)**: the OS part fell from 4 / 136 to 1 / 70 (none fixable), but the official restic 0.18.1 binary is + built with Go 1.25.1 and adds 2 / 48, all fixable (25 Go standard library, 25 restic's own modules); docker-compose + 4 high unchanged. felhom-samba 1.1.0 0 / 48 (48) → **1.2.0 0 / 0**. restic 0.19.1's official binary would carry 0 / 19 + — the next step is the operator's choice (R-1107). ## v0.322.0 — the hub key opens no route on the box; Go 1.27.2; two Data tab leftovers; the install form's dead branches (2026-10-16) diff --git a/controller/README.md b/controller/README.md index 6612a61..195c637 100644 --- a/controller/README.md +++ b/controller/README.md @@ -920,7 +920,7 @@ Each app can define rich metadata in `.felhom.yml`: + `offbox_capture.go` + `offbox_restore.go`. Each toggled app's push is ONE multi-path restic snapshot = recovery unit + its `TierOffsite` mandatory set (`offboxCaptureSet`); legacy/undeployed stay unit-only. Skipped/missing mandatory paths are loud gaps (English log + Hungarian - `LastWarning`) because restic 0.14.0 silently skips a missing source path (SP-3.4). Quota reads + `LastWarning`) because restic silently skips a missing source path (SP-3.4; re-measured on 0.18.1, R-1105). Quota reads `stats --mode raw-data` (real repo bytes, SP-1); a pre-push gate blocks an ENLARGEMENT that would cross the soft quota (unit-only push continues; `OffboxTarget.EnlargedBlocked`; edge-triggered notify). Retention `forget --group-by host,tags` (SP-2). Restore (`RestoreOffboxScratch`) scratches @@ -2250,7 +2250,8 @@ that folder is never a dead end, and an install never runs into it silently (R-6 > **`host_fingerprint`**) and `internal/offsiteapply.Bridge` reconciles it at startup: scan + **verify the > box host key against `host_fingerprint` (no blind TOFU)** → generate an ed25519 keypair → **consume the > hub's one-time transient password** (`POST /api/v1/offsite/consume-password/{id}`, single-use) → install -> the pubkey (`sshpass -e ssh-copy-id -p 23 -s -f`, **pinned known_hosts, `StrictHostKeyChecking=yes`**; +> the pubkey (`sshpass -e ssh-copy-id -p 23 -s -f` — *superseded in v0.289.0 by the hub's key registrar; `sshpass` left +> the image in v0.323.0*; **pinned known_hosts, `StrictHostKeyChecking=yes`**; > the installer ensures `~/.ssh` exists — ssh-copy-id's SFTP mode needs it) → verify key-only auth → > configure the offbox target → `EscrowState="pending"` (the fork-4 gate above still holds) → persist a > descriptor-hash marker LAST. **Idempotent** (marker → no re-consume) and **fail-safe** (any failure → @@ -3920,9 +3921,10 @@ multicast that WSD/mDNS discovery needs), its configuration is a dynamic share l `smb.conf` (not env vars), and its share roots must ride the backup classification. It is therefore the **fourth protected infra stack**: traefik / cloudflared / filebrowser / **samba**. -#### The image (`controller/infra-images/samba/`, `felhom-samba:1.1.0`) +#### The image (`controller/infra-images/samba/`, `felhom-samba:1.2.0`) -Our own pinned image (alpine 3.21 by digest) running **four** daemons (v1.1.0) — `smbd` (445), **`nmbd`** +Our own pinned image (alpine 3.24.2 by digest since 1.2.0, R-972; `build-samba-image.sh` refuses a tag already in the +registry and a dirty or unpushed tree) running **four** daemons (v1.1.0) — `smbd` (445), **`nmbd`** (NetBIOS flat-name resolution), `wsdd` (WS-Discovery), under `tini`. nmbd is not optional: the R-6 spike proved wsdd alone makes the box *visible* in Explorer while the double-click still fails `0x80070035`, because WSD supplies an icon, not a name→IP mapping. The image is deliberately dumb — @@ -4086,7 +4088,7 @@ under `progress`. - Restic's status object is only partly usable in practice, and the fallbacks matter more than the percentage: on an **incremental** run restic transfers no bytes (`bytes_done` is `omitempty`, so - absent) and `percent_done` stays 0 for the whole run; and because restic 0.14 counts a file only + absent) and `percent_done` stays 0 for the whole run; and because restic (0.14.0 and 0.18.1 alike) counts a file only when it **completes**, an app dominated by one large archive freezes the file counters too. The card therefore degrades: bytes -> files -> current file + elapsed seconds. - A run is **not** only the per-app loop. `Phase` (`shares`, `retention`) names the post-app stages @@ -4643,18 +4645,21 @@ git -C ~/git/felhom-controller pull ./build.sh v0.20.0 --push ``` +### The image (v0.323.0, R-1105) + +Runtime `debian:13.x-slim`, pinned by version and digest; the Docker CLI's apt repo codename is read from the image's +`/etc/os-release`. **restic is NOT an apt package:** the `restic` build stage downloads the official release binary of +the version in `ARG RESTIC_VERSION`, checks restic's signed `SHA256SUMS` with the vendored release key +(`third_party/restic/`), the published sum, and the per-architecture sum pinned in the Dockerfile — any mismatch fails +the build. Moving restic is a decision with a re-proof: `internal/backup/testdata/restic//` holds REAL outputs +of each version the off-site code was checked against, and `TestR1105_*` assert every parsed shape and failure class +for each (`felhom.eu/documentation/architecture/07-backup-architecture.md` §6.8). The runtime installs only what the +binary runs: git, rsync, util-linux, openssh-client, curl, ca-certificates, gnupg, docker CLI + compose plugin. + ### Deploy on customer node -**Option A: Self-Update API (v0.16.0+)** - -After building and pushing the new image, trigger the controller's self-update endpoint: - -```bash -curl -s -X POST https://felhom.demo-felhom.eu/api/selfupdate/update \ - -H "Authorization: Bearer " -``` - -The controller pulls the new image, updates its own compose file, and runs `docker compose up -d` to replace itself. The Settings page also has a "Frissítés telepítése" button for manual triggering. +**Option A: the update path (the normal one).** A box takes a new release through its own update button or the hub's +floor. The self-update route takes a dashboard session only since v0.322.0 (R-970) — no hub-key `curl` reaches it. **Option B: Manual SSH (pre-v0.16.0 or fallback)**