Restore-holes run (2026-10-24 night): D43 = A recorded; 07/05/03/11 carry the R-1251, R-1252, R-1254 and D43 rules; register 207 -> 208 (R-1268 opened; R-1251/1252/1253/1257 VERIFY, R-1254 NARROWED); STATUS Monday list + D44/D45 picks; evidence (Tester 1, 9202)
gates / gates (push) Successful in 13m4s
gates / gates (push) Successful in 13m4s
This commit is contained in:
1 parent
dcf4f84cb7
commit
3add386aa9
60 files changed
+2082
-16
No files matched your search
@@ -130,6 +130,13 @@ the one trust root; the agent's API token is untouched; a box gets the new rule
|
||||
0.146.0 cannot update itself on that box).
|
||||
|
||||
**[DESIGN, ruled 2026-10-22 15:47 (D4, R-982) — SHIPPED in agent v0.163.0 (`1109092`) and installer-v1.36.0 (`manifests/webpage.yaml:347`); corrected 2026-10-24] Root SSH from the LAN by key only; the console password stays.** The config bundle gains one fixed file, `/etc/ssh/sshd_config.d/10-felhom-root-key-only.conf` (`PermitRootLogin prohibit-password`), checked and reloaded by `felhom-os-apply`; the installer's uninstall removes it. Why a drop-in: Debian's `sshd_config` Includes `sshd_config.d/*` FIRST and sshd keeps the first value it reads, so the drop-in wins over the stock line; the out-of-band operator sshd (`FELHOM_SSHD`, port 8822) has its own config with no Include and is not touched. Proven on a fresh ISO 1.30.0 install: password SSH refused after, key SSH and the PVE web password login (200) and the console login still work (`audits/night-2026-10-22/P2-D4/`). It ships with the next agent release + installer tag.
|
||||
**[DESIGN, operator ruling D43 = A, 2026-10-24 — committed agent `c8d3c17`, unreleased; R-1257]** **Appliances only.** The
|
||||
drop-in's bundle policy is `appliance`: written only when the root-owned install record (`/var/lib/felhom-install/state.json`)
|
||||
says `appliance` (the installer records the mode before it installs the bundle); on a `byo` record nothing is written and
|
||||
a copy WE wrote (this path, beginning with our header line) is removed, then `sshd -t` and a reload; a box with no
|
||||
readable record is left as it is. The „in force" check asks `sshd -T` for each of the host's own global IPv4 addresses
|
||||
(a `Match Address <LAN>` block no longer reads as in force); a failing `sshd -t` puts back ONLY the SSH file and keeps
|
||||
the rest of the bundle (the report says `sshd_step_undone`).
|
||||
|
||||
**[FACT, agent `a0c88e5`, released in v0.163.0 — corrected 2026-10-24] The heartbeat reports a WireGuard handshake from the future (R-1204).** WireGuard refuses an initiation whose TAI64N time is not newer than the last one accepted from that peer, so a box that once ran with its clock ahead is locked out of ep0 until real time passes that moment. The agent used to clamp the negative age to 0 (it looked healthy); `wgtunnel.handshakeFuture` now sets `handshake_future_s` when the handshake is more than 60 s ahead (`TestR1204_AFutureHandshakeIsReported`). The hub alarms on it (`05` §15.4b).
|
||||
|
||||
|
||||
@@ -296,6 +296,12 @@ What remains:
|
||||
PBS repo and namespace in the **DR recipe** (`dr_recipe`, reported every cycle — R-106 fixed it to match the
|
||||
backup); the endpoint's PBS fingerprint in **tenantsync** (`hub/internal/tenantsync`); the wrapped key in
|
||||
**`host_escrow.blob`** (and the identity blob beside it).
|
||||
**[DESIGN] 2026-10-24 (R-1254; committed felhom.eu `dcf4f84c`, hub next v0.170.0 — NOT deployed):** the escrow PUT
|
||||
stores the blob, its sealed-password hash and the identity blob in ONE transaction (`Store.SaveHostEscrowWithIdentity`;
|
||||
the superseded copy is made inside it). A failure leaves all of the old package or all of the new — never the new hash
|
||||
beside the old identity package, which a box would read as „escrowed" while the written code opened nothing. A
|
||||
malformed identity blob is refused before anything is stored. (The agent ceremony's „the previous code still works"
|
||||
after a lost answer, R-1254's other half, stays open.)
|
||||
|
||||
Both existing infra-backup tables retire — `infra_backup_versions` (the current/live one, all readers
|
||||
hit it) **and** `infra_backups` (the deprecated legacy mirror). (The planned slim DR record on `hosts` was never
|
||||
|
||||
@@ -778,6 +778,28 @@ than the unit), the app running, the record reads the D22 sentence. Known limit
|
||||
named volume the unit replaces (none in the catalog today — a drive-file app's unit restore is refused by R-538) is not
|
||||
covered by the volume copy.
|
||||
|
||||
**`[DESIGN]` 2026-10-24 — a pending put-back blocks EVERY start (R-1251; review round 2 HUNT-1 H1, H2, H7; committed in
|
||||
controller `bb2809d` + `062f9b4`, unreleased — rides the next controller release).** For a drive-backed app the copy lives on
|
||||
the app's drive, and at start the drive is often not bound yet. A copy that cannot be reached while its drive is not
|
||||
bound is **waiting, never „gone"**: the crash recovery writes a restore hold (`putback_pending`, the copy's folder
|
||||
in it) and starts nothing. The hold is the one store every start path already honours — the household's
|
||||
Start/Restart/Update, the boot recreate, the drive return, the media restart, the boot sweep, the night chain, the
|
||||
update leg — so no path has its own check. When the drive binds, the put-back runs FIRST (the boot recreate and the
|
||||
drive-return restart; the start and every drive return sweep the waiting holds), the hold is lifted, then the app
|
||||
starts. The household reads „…A visszaállítás előtti adatai egy meghajtón vannak, amely most nem érhető el…" on the
|
||||
app and „Ne indítsd újra a visszaállítást…" in the restore record. A put-back that FAILS (at start or when the drive
|
||||
returns), or a copy gone while its drive is bound, leaves the app **held** with the D20 hold („félúton megszakadt"),
|
||||
the copy kept, and the marker lets go of the app — never stopped-and-unheld (H2). Stop pressed during the restore still
|
||||
gets the put-back; only the start is skipped (H7). A removal clears a waiting put-back; a later restore that completes
|
||||
drops it (the household chose that data). The copy's folders are synced to disk BEFORE the marker names the copy.
|
||||
**`[FACT]` 2026-10-24 night, Tester 1 (VM 341; MeTube on the data drive, 1.5 GB in its volume;
|
||||
`audits/restore-holes-2026-10-24/P1-tester1/`):** a local restore cut by powering the VM off 2.1 s after „the restore
|
||||
copy is recorded", the data disk taken off, the box booted: held as waiting, Start and Update refused (409, the
|
||||
sentence); the disk plugged back: the agent re-mounted it, the boot recreate put the copy back BEFORE the start, the
|
||||
household's newest data („gen2") and its download on the drive were there, and a later controller restart poured
|
||||
nothing. Run 1 of the same proof found the journal left as `undo.json.tmp` (the rename lived only in the page cache) —
|
||||
the app was held for support, never started on the cut data; the folder sync above fixed it, run 2 passed.
|
||||
|
||||
**[DESIGN] 2026-08-22 — the failure ladder of a database restore: replay → rollback → hold.**
|
||||
Recorded here rather than only in a closed register row, because a decision that survives only inside
|
||||
a closed work item is a decision nobody will find.
|
||||
@@ -888,6 +910,8 @@ run makes it longer.
|
||||
|
||||
### 6.5 Kept data — what a removed app leaves on the drive (controller v0.274.0, `09` §3 decision 36)
|
||||
|
||||
*Second-drive copies that are KEPT (D25) and the rule that a rejected backup block never deletes one: §8.2a (R-1252, 2026-10-24).*
|
||||
|
||||
**What it is.** "Remove the app, keep my data" leaves the app's drive folder (`<drive>/appdata/<app>`, or the folder
|
||||
its definition binds through `${HDD_PATH}`) in place. A reinstall over it no longer runs silently into the old files
|
||||
(R-657): the install asks „A megőrzött adataimat használom" / "Use my kept data" (the database from the newest copy of
|
||||
@@ -1597,6 +1621,19 @@ or pattern. **Why:** the data-loss hunt of 2026-10-20 proved two nights that del
|
||||
(R-1175: one share group's reconcile removed the other groups' copies, and a dead drive's copy; R-1181: a missing or
|
||||
emptied folder took its copy within one night). Controller: `internal/backup/tier2_kept.go`.
|
||||
|
||||
**`[DESIGN]` 2026-10-24 — a rejected backup block never deletes a copy (R-1252; review round 2 HUNT-2 H1, H2, H9;
|
||||
committed in controller `518a135`, unreleased).** The night's reconcile (deleting dest dirs the legs no longer name)
|
||||
runs ONLY under a valid classification. An app whose block is rejected (one bad line rejects the whole block) or absent
|
||||
falls back to the legacy legs, and nothing is reconciled that night — every existing copy stays. A REJECTED block puts
|
||||
„Az alkalmazás mentési beállításai most nem olvashatók…" on the app's second-drive status and tells the operator once a
|
||||
day (the operator-only digest `backup_run_failures`, leg `tier2-settings-unreadable`). A kept copy (D25) is always in
|
||||
the keep set, also when its leg later leaves the declared set (H2); Remove with „remove backups" drops the kept-copy
|
||||
records of what it deleted (H9). **`[FACT]` 2026-10-24 night, 9202 (`audits/restore-holes-2026-10-24/P2-9202/`):**
|
||||
audiobookshelf with a household file in `media/audiobooks`; two control runs kept the copy; one bogus path in the
|
||||
block → „the backup block is REJECTED … every existing copy on the second drive is KEPT", the copy there, the status
|
||||
sentence set, the operator digest sent (9202 has no hub: logged as dropped); the review's run on 0.342.0 the same day
|
||||
deleted that copy (`review-round-2-2026-10-24/proofs/H2-bad-backup-block/`).
|
||||
|
||||
### 8.2b The second-drive copy runs in a memory-capped container that never outlives the copy [DESIGN + FACT, R-1214, 2026-10-22/23 nights; rides controller 0.340.0]
|
||||
|
||||
The copy (`rsync -a --delete`) runs in a container of the controller's own image, capped at 512 MB, so its page cache
|
||||
|
||||
@@ -76,6 +76,10 @@ boxes installed. Nobody keeps a hand-written list.
|
||||
- **A BYO host** (the owner brought their own Proxmox). `[FACT]` The installer leaves its repositories
|
||||
alone: *"apt repo alignment skipped (byo — the owner manages repos)"* (`scripts/felhom-host-install.sh`,
|
||||
`align_apt_repos`). `[PROPOSAL]` On a BYO box we update the guest and Docker only, never the host.
|
||||
**[DESIGN, operator ruling D43 = A, 2026-10-24 — committed agent `c8d3c17`, unreleased]** The host's root-key-only sshd
|
||||
drop-in (D4, R-982) is an APPLIANCE-only file of the config bundle: written only when the root-owned install record
|
||||
says `appliance`; on a `byo` record nothing is written and a copy the bundle wrote earlier (this path, our first line)
|
||||
is removed; a box whose record proves nothing is left as it is (R-1257).
|
||||
- **The Proxmox MAJOR upgrade** (PVE 9 → 10). It is a later step of its own, drilled first (R-808 item 5).
|
||||
- **`cloudflared` and the other infrastructure images** (traefik, filebrowser). **[FACT] (C8)** They are containers in
|
||||
the guest, pinned in the controller (`internal/infra/infra.go:26`: `cloudflare/cloudflared:2026.6.0`, since
|
||||
|
||||
Reference in new issue
Block a user