agent v0.86.0: DR-tier-by-default — capability inactive state (GatedBy/GateActive, pbsdr gate via DRConfigured) + F-3 root-run provision parent ownership
Claude-Session: https://claude.ai/code/session_01NptTCFtu7dz2Ru89qHRagN
This commit is contained in:
@@ -1,85 +1,48 @@
|
||||
# REPORT — agent v0.85.0: the boot/recovery plane + appliance self-heal (CAMPAIGN-3 Task A)
|
||||
# REPORT — agent v0.86.0: DR-tier-by-default (capability `inactive` + F-3 parent ownership)
|
||||
|
||||
**Date:** 2026-07-12 · **Baselines:** agent v0.84.0 (`bec4bac`) → **v0.85.0**; felhom.eu post-`f97f7803`.
|
||||
**Source of truth:** `felhom.eu/documentation/audits/CAMPAIGN-3-2026-07-11.md`.
|
||||
**Scope:** F12 (CRITICAL), F11/F10/F9 (HIGH/CRITICAL), F2/F1 (LOW), the guest-hook rc255 belt, and the
|
||||
operator-mandated appliance-mode node self-heal. Controller untouched (MinAgent unchanged). Green gate
|
||||
(`go build ./... && go vet ./... && go test ./...`) PASS on the build server.
|
||||
**Date:** 2026-07-12 · **Baselines:** agent v0.85.0 (`bcb8dad`) → **v0.86.0**.
|
||||
**Source of truth:** the DR-tier-by-default batch spec + `felhom.eu/documentation/audits/DRILL-day0-vm-2026-07-12.md`.
|
||||
**Scope:** agent half of the batch — the capability `inactive` state (disabled ≠ degraded) and the
|
||||
F-3 provision parent-dir ownership fix. No escrow/ceremony changes (decision 4: identity-only
|
||||
escrow is PARKED by policy). Green gate: `go build ./... && go vet ./... && go test ./...` — all
|
||||
26 packages ok.
|
||||
|
||||
## What shipped
|
||||
|
||||
- **F12 (CRITICAL) — boot ordering cycle.** Both rendered units drop `After=/Wants=network-online.target`
|
||||
(`.mount` keeps `_netdev`; `.automount` gets no network relation). `MigrateNetworkUnits` — a general
|
||||
template-drift reconcile (SHA-256 content compare vs a fresh render of the reconstructed spec;
|
||||
rewrite + one batched `daemon-reload`; idempotent) — repairs ALREADY-INSTALLED units at startup and
|
||||
at the head of `EnsureNetworkMount`.
|
||||
- **F11 — read the right unit** (`netReassertClassify`): decision by host `/proc/mounts` fstype only,
|
||||
never the automount's own state. **Matrix-corrected:** a rebooted guest inherits neither an idle
|
||||
trigger NOR an active mount, so the callers re-arm reactively when a running guest is found blind
|
||||
(`RearmNetworkAutomount` after a failed visibility check).
|
||||
- **F10 — re-arm for real:** a failed/start-limited unit is `reset-failed` before `enable --now`
|
||||
(unprivileged `systemctl is-failed` seam + new sudoers verb).
|
||||
- **F9 — say what you did:** enumerate by marker-owned unit files; one INFO verdict per share.
|
||||
- **F2/F1 — zero residue:** `RemoveNetworkMount` (and every verify-fail rollback via it) reset-failed's
|
||||
the pair and `rmdir`s the mountpoint (rmdir-only fail-safe; never `rm -rf`).
|
||||
- **Hook can never take a guest down:** `runHookPhase` — per-phase recover + hard timeout, always
|
||||
returns; the installed wrapper snippet no longer `exec`s (`… || true; exit 0`).
|
||||
- **Appliance self-heal (`internal/selfheal`):** one heal — host networking recovery, gated on
|
||||
`deployment_mode:"appliance"`; byo runs the check + WARNs, remedy unreachable. Config
|
||||
`deployment_mode` (+`FELHOM_AGENT_DEPLOYMENT_MODE`, `IsAppliance()` fail-safe-to-byo).
|
||||
1. **Capability `inactive` state** (`internal/capability/probe.go`, `manifest.go`):
|
||||
- `StatusInactive = "inactive"`, `ReasonInactive = "disabled by configuration"`.
|
||||
- `Capability.GatedBy` + `Prober.GateActive(gate)` — a HEALTHY probe of a gated capability
|
||||
whose gate is off is downgraded ok→inactive. Degraded (binary missing / sudo denied) is
|
||||
NEVER downgraded: an un-migrated pre-v1.15.0 box must not masquerade as deliberately off.
|
||||
- The 3 `pbsdr-*` entries are gated via the stable name prefix in `Manifest()` (a future
|
||||
pbsdr-* op is gated automatically; nothing else ever is — pinned by test).
|
||||
- `Summarize` counts only real degraded; `logCapabilities` logs an inactive count at INFO and
|
||||
now runs AFTER the pbsdr wiring so the startup snapshot equals the first report's.
|
||||
2. **`pbsdr.Manager.DRConfigured()`** (`internal/pbsdr/manager.go`): the gate's answer — live
|
||||
descriptor state (anything but `disabled`), falling back to the persisted converged marker
|
||||
before the first desired-state fetch (an applied box never flaps inactive across a restart).
|
||||
3. **F-3** (`internal/provision/backhalf.go`): a root-run provision chowns `guests/` +
|
||||
`guests/<vmid>/` to the state-dir's owner (`chown --reference`, non-recursive; bootstrap leaf
|
||||
stays guest-root). Non-root (daemon) runs skip it via the `geteuid` seam.
|
||||
|
||||
## Sudoers — three grants added (LOUD, per the no-widening rule)
|
||||
## Tests + red-proofs (all three mutations proven red, then restored)
|
||||
|
||||
Shipped with the binary; capability manifest updated (probed live: 62/62, 0 degraded):
|
||||
1. **`systemctl reset-failed -- mnt-felhom*`** (FELHOM_NETMOUNT) — F10: no platform path could re-arm a
|
||||
start-limited automount. reset-failed only clears a failed latch; it cannot start/stop anything.
|
||||
2. **`rmdir /mnt/felhom-drives/*`** (FELHOM_NETMOUNT) — F1: removed-share mountpoint cleanup. rmdir
|
||||
refuses a non-empty dir (fail-safe; unexpected data is preserved, never `rm -rf`'d).
|
||||
3. **`systemctl start networking.service`** (new FELHOM_SELFHEAL alias) — F12-class appliance self-heal.
|
||||
Fixed unit, no glob; the grant alone cannot harm; the remedy is ALSO code-gated on appliance mode.
|
||||
| Test | Red-proof mutation | Result |
|
||||
|---|---|---|
|
||||
| `TestProbe_GateOffHealthyIsInactive` (+ BinaryMissingStaysDegraded, GateOnOrNilIsOK, ExactlyPBSDRGated) | gate branch in `Probe` disabled (`if false`) | inactive case FAILED; degraded case stayed green ✓ |
|
||||
| `TestDRConfigured_Lifecycle` (unconfigured→applied→restart-marker→disabled) | `DRConfigured` ignores the `disabled` state | disabled case FAILED ✓ |
|
||||
| `TestProvision_RootRunOwnsGuestsParents` (root issues, non-root doesn't, never `-R`) | F-3 chown block removed | root case FAILED ✓ |
|
||||
|
||||
## Tests + red-proofs (all green)
|
||||
## Live state touched
|
||||
|
||||
- Render: no network-online in either unit, `_netdev` present (companion: re-adding the line fails).
|
||||
- Reconcile: drifted (legacy) unit rewritten once + batched daemon-reload; idempotent (0 rewrites 2nd
|
||||
pass); spec round-trip exact; foreign units ignored.
|
||||
- Reassert: fstype table with the automount-state-ignored red-proof; reset-failed+rearm verdict;
|
||||
per-unit verdict count (F9); re-arm-on-guest-blind (F11 matrix-correction); byo-blind non-fatal.
|
||||
- Hook rc-0 under panic + timeout (Part 4); zero-residue (reset-failed + rmdir, never rm -rf).
|
||||
- Self-heal state machine; **byo-never-invokes red-proof** (byo + unhealthy → zero privileged
|
||||
invocations); absent field ⇒ byo.
|
||||
- **felhom-pve latent F-3 state FIXED live** (pre-existing `guests{,/9201}` root:root 0700 →
|
||||
chowned to felhom-agent, bootstrap subtree untouched — the drill's proven fix).
|
||||
- **Peti's host: unreachable** — his F-3 check + agent update stay deferred (publish-train D/E/G).
|
||||
|
||||
## Live MATRIX (demo felhom-pve, agent 0.85.0 + deployment_mode=appliance)
|
||||
## Shipping notes
|
||||
|
||||
Deploy verified: startup migrated the installed nas-media units (0 network-online lines); no interim
|
||||
drop-in existed to remove (the campaign recovery used reset-failed+restart, not a drop-in).
|
||||
|
||||
| # | Row | Result |
|
||||
|---|-----|--------|
|
||||
| 1 | guest reboot × idle share ×2 | **PASS** — zero-touch: reassert re-armed, guest sees NAS, write-through OK, 4 NAS apps auto-started |
|
||||
| 2 | guest reboot × active share | **F13 (new finding)** — active nfs4 under mp8 can fail PVE's rbind (rc255, idmap); NAS-down-at-boot → apps `Created` (deferred fix-3). Independent of the felhom hook (rc0). |
|
||||
| 3 | F10 manufacture → agent restart | **PASS** — sweep `reset-failed` both units (loud WARN) + re-armed (verdict `reset-failed+rearmed`); the campaign's silent no-op is gone |
|
||||
| 4 | F10 state → guest reboot (hook path) | **PASS** — guest STARTS (rc0); F11 matrix-correction healed the blind guest live ("re-arming … visible after re-arm (healed)") |
|
||||
| 5 | 🛑 host reboot ×2 | **PASS** — `grep -c "ordering cycle"` == **0 on BOTH boots**, networking up, automount armed, guest + 8 apps healthy. **F12 coin flip is dead.** |
|
||||
| 6 | 🛑 stop networking (appliance) | **PASS** — watchdog WARNed `active=false`, fired the privileged start, recovered on attempt 1 (~11 s). BYO live variant NOT run (red-proof only). |
|
||||
| 7 | refused add + remove cycles ×3 | **PASS** — zero residue (0 units/dirs/failed/creds; campaign left 10 dirs); registry clean |
|
||||
|
||||
## NOT live-validated / standing items
|
||||
|
||||
- **Row 6 byo variant** — not run live (would leave the box dark); byo is red-proof-tested only.
|
||||
- **F13 (NEW, HIGH)** — active-nfs-under-mp8 rc255 + NAS-down-at-boot apps-`Created`. Deferred (needs a
|
||||
pre-start idle-unmount design for multi-guest hosts, or an idmapped nfs mount + fix-3 alerting).
|
||||
- **Peti** runs agent 0.81 — unaffected by this train until his rollout; if his box has a NAS share he
|
||||
carries the F12 coin flip until then (interim drop-in recipe below).
|
||||
- Task B/C/D findings (F7/F6/F5, F8/F4, ring/alerting) remain queued.
|
||||
- **Publish train:** 0.85 is customer-critical (F12 affects any customer with a NAS share) — prioritize.
|
||||
|
||||
## Box state at wrap
|
||||
|
||||
agent 0.85.0 / deployment_mode=appliance; nas-media clean (no ordering cycle) + active; 0 failed felhom
|
||||
units; 0 leftover mountpoint dirs (19 pre-fix campaign leftovers rmdir'd); guest 9201 + all 10
|
||||
containers healthy with NAS data intact.
|
||||
|
||||
### Interim F12 mitigation for a not-yet-upgraded host
|
||||
A systemd drop-in on each installed `mnt-felhom…-<name>.automount` with empty `After=`/`Wants=`
|
||||
overrides + `daemon-reload` strips the ordering until the 0.85 agent migrates the unit at startup.
|
||||
- `configs/felhom-pbs-apply` was already in this repo; host-install **v1.15.0** (felhom.eu,
|
||||
same-day) now ships it (drill F-7) + `age` (F-10) + `wg_tunnel.enabled: true` (F-9/decision 5).
|
||||
- Hub-side rendering of the `inactive` chip + the per-customer DR flag = hub v0.51.0 (felhom.eu).
|
||||
- Deploy: build+push 0.86.0 on 180, deploy to felhom-pve, publish via `scripts/publish-agent.sh`,
|
||||
hub Day-0 manifest vouch as operator/browser follow-up.
|
||||
|
||||
Reference in New Issue
Block a user