10 KiB
REPORT — the controller on Debian 13 with a pinned restic, re-proven; the Samba image rebuilt (2026-10-16)
Written in ASD-STE100 Simplified Technical English. Operator brief „the controller on Debian 13 with a pinned restic,
re-proven; the Samba image rebuilt". Design read first: architecture/07-backup-architecture.md (Tier 3, §6.3, §6.7 the
failure classifier, §3 the restore table; now §6.8), 06-offsite-connectivity.md, 03-host-agent.md (escrow),
_recovery-inventory-2026-07-28.md. Evidence: documentation/audits/debian13-restic-2026-10-16/.
0. Decisions I took (inside the brief; reversible)
- I removed seven packages, not two. The brief named the two database clients. I read every program call in the
controller: it never runs
sqlite3,fdisk,e2fsprogs,parted(disk work is the agent's since v0.37.0) orsshpass(its key install was replaced by the hub's registrar in v0.289.0) either. On demo-hp every kept tool works, every removed one is gone, and the log has no „executable not found". To undo: put the names back in the apt list. - I kept restic 0.18.1, as the brief says, although it adds scanner findings (§4). The choice of 0.19.x is yours (R-1107).
1. The assumption table (Part 1) and each row on restic 0.18.1
Measured on scratch stores with both official binaries side by side (part1/), then pinned as test fixtures of REAL
outputs (felhom-controller internal/backup/testdata/restic/, TestR1105_*, red-proved by six mutations).
| restic call · where | What the code assumes | 0.18.1 |
|---|---|---|
backup (+ missing path) · offbox.go, offbox_capture.go |
a missing source path: a warning, exit 0; an unreadable file: exit 3 | same |
backup --json · offbox_progress.go |
status lines: percent_done, totals, current_files |
same names (live bar moved on demo-hp) |
snapshots --json, snapshots latest --tag · offbox.go, offbox_inventory.go, offbox_restore.go, offbox_window.go |
one JSON array, nothing else in the combined output (also with an empty cache) | same (new fields only) |
stats <id>, stats --mode raw-data · offbox_restore.go, offbox.go |
total_size |
same |
forget … --dry-run --json · offbox_window.go |
the plan of the 7/4/6 policy, --group-by host,tags |
CHANGED, safe direction: 0.17+ also keeps each group's oldest snapshot while monthly slots are unused — fewer removals, never more (41-day set 60 vs 62; 230-day set identical, both time zones). The guard's verdict holds. Pinned. No code change needed. |
restore … --include <unit> --no-lock · offbox_proof.go |
writes nothing to the store | same (restores from a read-only store) |
restore (plain) · offbox_restore.go, offbox.go, shares_restore.go |
the layout under the target | same. The old comment „restore takes no lock" was wrong for both versions; corrected |
cat config, init · offbox.go probe |
„wrong password…" = orphaned; „unable to open config file" = no repo; „already exists" = init race is success | same |
unlock, unlock --remove-all · resticStep |
lock text „repository is already locked"; stale-only unlock keeps a foreign lock | same (both lock forms) |
check · offbox_integrity.go |
a damaged pack reads as damage, a healthy run does not | same verdict (other wording) |
| the §6.7 classifier | refused port, refused key, unreachable host, dead rclone ssh → transport |
same |
| agent: escrow, recovery, DR recipe | — | the agent runs no restic; it only stores and returns the password |
Exit codes changed (10, 11, 12); the controller reads none.
2. The version and the pin
- restic 0.18.1 (newest 0.18 patch). The hosts run no restic (demo-hp, demo-felhom, Tester 1: not installed); every guest ran Debian's 0.14.0. So „one version for guest and host" means the guest only.
- The pin: a
resticbuild stage downloads the official release file; restic'sSHA256SUMSsignature is checked with the vendored release key (fingerprint CF8F 18F2 8445 7597 3F79 D4E1 91A6 868B D3F7 A907, cross-checked against restic's own install doc); the file must match the published sum AND the sum pinned in the Dockerfile. A wrong sum fails the build (proved).TestR1105_ResticIsPinnedOutsideTheOS, red-proved by four mutations.
3. Both directions and the drill (demo-hp 9201, rc.1, the dashboard's own posts)
- 0.18.1 restores a 0.14.0 snapshot: the product's off-site restore of bookstack → a tree byte-identical to a 0.14.0 restore of the same snapshot. 0.14.0 restores a 0.18.1 snapshot: byte-identical too. Both on demo-hp's REAL store.
- 0.14.0 after a 0.18.1 prune: proven on a scratch store (502 snapshots;
check --read-dataclean, both restores). On the real store it waits for demo-hp's next weekly clean-up window (due after 2026-10-18 14:16 UTC). In STATUS. - The drill: Rallly (database) and Grimmory (books folder): a marker row and a marker file; the off-site run (dumps + push, 3m33s, 186 → 202 snapshots); removed with data and backups; reinstalled (nothing there — the negative control); full restore from the off-site copy. The row and the file came back (file sha256 identical). But both apps were then unusable — not because of restic: the restore puts back the OLD database volume with the old password, and the reinstall made a new one. Rallly crash-looped on auth while the restore said done; Grimmory was held stopped. Filed R-1106 (R-127's class, on the reinstall path).
4. Debian 13 and the scanner
Kept: git, rsync, util-linux, openssh-client, curl, ca-certificates, gnupg, docker CLI + compose plugin. Removed: the seven in §0. trivy 0.74.0 (critical / high, fixable in brackets):
| image | critical | high |
|---|---|---|
| controller 0.322.0 (Debian 12) | 4 (0) | 140 (4) |
| controller 0.323.0 (Debian 13) | 3 (2) | 122 (52) |
| — of which the OS | 1 (0) | 70 (0) |
| — of which restic 0.18.1 (Go 1.25.1, old modules) | 2 (2) | 48 (48) |
| felhom-samba 1.1.0 | 0 | 48 (48) |
| felhom-samba 1.2.0 | 0 | 0 |
The OS part fell by half. The official restic file is built with an old Go, so the fixable count rose. restic 0.19.1's official file: 0 / 19. R-1107.
5. Samba (R-972)
felhom-samba 1.2.0: Alpine 3.24.2 (digest-pinned), same packages, Samba 4.23.8. build-samba-image.sh now refuses a tag
already in the registry, a registry it cannot ask, and a dirty or unpushed tree (6 cases; 4 fail on the old script).
Checked on demo-hp first on 1.1.0, then after the switch to 1.2.0, with the SAME household password (the passdb volume
survived): smbclient from DooPlex wrote, listed and read back a file; a wrong password was refused; nmbd answered the
name; mDNS answered FELHOMHP.local; WS-Discovery answered; smbd, nmbd, wsdd, avahi, dbus under tini; testparm clean.
Found on the way: a share added before the first password is not exported (R-1108, pre-existing, narrow).
6. Release
Built 0.323.0 from 8587198 (code identical to rc.1 fbcc3cf; only CHANGELOG and README differ), MinAgent 0.158.1.
Per-box floors at 19:23:46 UTC (303 → floor_set, all three); Tester 1, demo-hp and demo-felhom on 0.323.0 at
19:25 UTC, each through the normal update path (Post-update startup: update successful). Box walk: no container
unhealthy, restarting, exited or created (24 / 9 / 17); restic 0.18.1 and Debian 13 in each controller; the three
dashboards 200; https-only 35 names OK with both controls (release/).
The global floor is NOT raised tonight (the brief). It waits until each test box has made one real night's off-site
backup on 0.323.0 (they run at about 02:15 UTC). The exact check and the floor command are in STATUS.md („What we
work on"). The real-store check „0.14.0 reads after a 0.18.1 prune" waits for demo-hp's clean-up window (after
2026-10-18 14:16 UTC).
CI: green by job for every commit of this task — controller fbcc3cf (1963), 8587198 (1965), 00a0d91 (1967); felhom.eu e713f6ae (1964), babf596c (1966).
7. Rows
Before 174, after 177. Opened 3 (R-1106, R-1107, R-1108). Closed 0. R-1105 and R-972 NARROWED (R-1105 waits
on the night check; R-972's Samba part is done and rides the floor). unproven.py: NOT WALKED 35 of 55, unchanged.
8. Observations
- The forget plan of restic 0.17+ keeps each group's oldest snapshot while monthly slots are unused. NOT-A-FINDING: it only ever keeps more, the guard's verdict holds; pinned by
TestR1105_TheForgetPlanOnlyEverKeepsMoreand written into07§6.8. - A reinstalled database app restored from the off-site copy is unusable (old volume, new password). FILED: R-1106
- The official restic 0.18.1 binary adds 50 fixable scanner findings. FILED: R-1107
- A share added before the first household password is not exported. FILED: R-1108
- A remove „with drive data" keeps
userdata/media/grimmory. NOT-A-FINDING: by design (07§6.5, decision 67 — the household's folders stay). - A restore hold outlives the remove and a fresh install. NOT-A-FINDING: by design (R-379 — only the operator clears it;
ClearUpdateHold's comment). The fresh install over it runs; the hold sentence stays on its page until cleared — part of R-1106's chain. - The
-clear-restore-holdtool's change is overwritten if the controller is not restarted at once. NOT-A-FINDING: the tool prints „NOW RESTART THE CONTROLLER"; done that way it worked. - A plain
restic restorewrites a lock (both versions); an old code comment said it did not. NOT-A-FINDING: the comment is corrected; the nightly proof uses--no-lockand was never affected. build.sh --pushalso pushes:latestfor an rc tag. NOT-A-FINDING: nothing pulls:latest(the update button reads X.Y.Z tags; boxes run a named tag).
9. Teardown (three layers)
- Machine (demo-hp 9201): Rallly and Grimmory removed through the product (no container, volume, unit or folder
left; the Grimmory restore hold cleared with the operator tool and a restart). The check copies are gone. Sharing
turned off, both test shares deleted, their empty folders removed; the passdb volume and
user_setstay, as the product leaves them. The helper scripts and scratch restores in the guest removed. 9201 runs 0.323.0. - Host: nothing.
- Hub: per-box floors (see §6).