v0.323.0: CHANGELOG live results and scanner; README — the image's pinned restic, Samba 1.2.0, the update path
gates / gates (push) Successful in 49s

This commit is contained in:
2026-10-16 21:22:42 +02:00
parent fbcc3cf042
commit 8587198781
2 changed files with 34 additions and 15 deletions
+14
View File
@@ -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)
+20 -15
View File
@@ -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/<version>/` 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 <HUB_API_KEY>"
```
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)**