Files
felhom.eu/REPORT-debian13-restic-2026-10-16.md
T
admin 96e15c15ba
gates / gates (push) Successful in 6m38s
debian13-restic report: CI result
2026-10-16 21:44:31 +02:00

127 lines
10 KiB
Markdown

# 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)
1. **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) or
`sshpass` (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.
2. **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 `restic` build stage downloads the official release file; restic's `SHA256SUMS` signature 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-data` clean, 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
1. 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_TheForgetPlanOnlyEverKeepsMore` and written into `07` §6.8.
2. A reinstalled database app restored from the off-site copy is unusable (old volume, new password). FILED: R-1106
3. The official restic 0.18.1 binary adds 50 fixable scanner findings. FILED: R-1107
4. A share added before the first household password is not exported. FILED: R-1108
5. A remove „with drive data" keeps `userdata/media/grimmory`. NOT-A-FINDING: by design (`07` §6.5, decision 67 — the household's folders stay).
6. 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.
7. The `-clear-restore-hold` tool'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.
8. A plain `restic restore` writes a lock (both versions); an old code comment said it did not. NOT-A-FINDING: the comment is corrected; the nightly proof uses `--no-lock` and was never affected.
9. `build.sh --push` also pushes `:latest` for 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_set` stay, 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).