docs: v0.107.0 README (key-auth-first + wipe) + REPORT (deployed, one-off cleanup done)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -1,44 +1,43 @@
|
|||||||
# REPORT — controller v0.106.1 + offsite provisioning LIVE end-to-end validation — **PASS**
|
# REPORT — controller v0.107.0: offsite hardening (key-auth-first + staged-secret wipe) — DEPLOYED
|
||||||
|
|
||||||
**Date:** 2026-07-09 · **Class:** operational validation (supervised runbook) + hotfix. Baseline v0.106.0 →
|
**Date:** 2026-07-09 · **Class:** implementation. Baseline v0.106.1 → **v0.107.0** (live on guest 9201,
|
||||||
**v0.106.1** (live on guest 9201). Pairs with hub v0.38.1. **Full record:**
|
`Up (healthy)`, clean logs). Part of the offsite hardening bundle: pairs with **hub v0.39.0** (F4 re-issue +
|
||||||
`felhom.eu/documentation/audits/VALIDATION-offsite-provisioning-e2e-2026-07-09.md`.
|
F2 scan retry + F5 save UX) and **agent v0.78.0** (`DELETE /escrow/stage-secret`) — both also deployed live.
|
||||||
|
|
||||||
## What happened
|
## What shipped (controller)
|
||||||
First live run of the SLICE 2 apply-bridge, driven end-to-end through the real pipeline (no hand-set state):
|
- **Key-auth-first bridge** (`internal/offsiteapply`): new `KeyAuthProber` seam + `SFTPKeyAuthProber` (probes
|
||||||
hub provisioned sub-account 269008 (`u629488-sub1`) on the new dedicated-project pool box (611714) →
|
the already-installed key against the descriptor target, pinned to the freshly-scanned known_hosts,
|
||||||
descriptor v6 + one-time password → controller `config-refresh` (15-min report ACK) → self-restart →
|
BatchMode + 20s budget). On a descriptor change where the key still authenticates: re-pin + reconfigure
|
||||||
**bridge applied cleanly**: scan + fingerprint verify (BEFORE consume) → keypair → consume-once →
|
+ marker — **no consume, no install**. Kills the stale-descriptor consume-404 loop (seen twice in the live
|
||||||
`sshpass -e ssh-copy-id -s -f` with the **pinned known_hosts (`StrictHostKeyChecking=yes`)** → SFTP key-auth
|
e2e) and shrinks the F4 blast radius to genuinely-fresh guests. The probe NEVER weakens identity: scan +
|
||||||
verify → offbox configured → `EscrowState="pending"` → marker persisted.
|
fingerprint verify still precede it, and a mismatch refuses before any probe (test-asserted with a
|
||||||
|
panicking prober). Fresh guests fall through to the unchanged full path.
|
||||||
|
- **Staged-secret wipe:** `agentapi.WipeStagedEscrowSecret` (DELETE, agent ≥ v0.78.0); the confirm-escrow
|
||||||
|
handler wipes the agent-staged repo password on every flip to `escrowed` — best-effort (failure logs a
|
||||||
|
loud "NOT wiped" ERROR, never fails the confirm; re-confirm retries). Seam-injectable (`wipeStagedEscrowFn`).
|
||||||
|
|
||||||
## v0.106.1 — the one live bug (F3)
|
## Tests + companion red-proofs (ALL-GREEN, both red-proofs fired)
|
||||||
`ssh-copy-id -s` (SFTP mode) mktemp's its batch file under `~/.ssh`; the container image ships without
|
- `TestBridge_KeyAuthFirstSkipsConsume` — probe-success: consumer PANICS if called; enabler gets the
|
||||||
`/root/.ssh` → the install died **locally** after the password was consumed. Fail-safe held exactly as
|
EXISTING key + fresh pin; marker updated. **Red-proof:** deleted the key-auth-first block → the panicking
|
||||||
designed (loud "password is spent" log, no marker, no offbox config; the password never left the box).
|
consumer fired → FAIL. Reverted.
|
||||||
Fix: `SSHCopyIDInstaller` ensures `~/.ssh` (0700) exists. Container probes (throwaway key + wrong password,
|
- `TestBridge_FreshGuestFallsThroughToFullPath` — probe-fail: consume+install exactly once with the
|
||||||
no secrets) isolated the bug AND proved the pin chain sound: pinned single-line known_hosts verifies cleanly;
|
GENERATED key. **Red-proof:** made probe-fail return early → `cons=0 inst=0` → FAIL. Reverted.
|
||||||
wrong password fails as `Permission denied` (sshpass exit 5).
|
- `TestBridge_HostKeyMismatchRefuses` — now also proves the probe never runs on a failed identity check.
|
||||||
|
- `TestOffboxWeb_ConfirmWipesStagedSecret` — confirm wipes exactly once; a failing wipe still confirms +
|
||||||
|
logs "NOT wiped".
|
||||||
|
|
||||||
## Live proofs (all green)
|
## Live validation (this deploy)
|
||||||
- **Consume-once:** hub `one_time_secrets.consumed_at` set, single row (read-only DB check).
|
- v0.107.0 on 9201 healthy; the bridge no-ops on the unchanged descriptor (marker match — no probe needed).
|
||||||
- **Fail-safe, twice:** the stale-v4 descriptor run hit consume→404 → clean abort + retry note; the F3 run
|
- **One-off cleanup executed via the NEW endpoint:** the staged file left behind by the e2e's Option-A
|
||||||
hit install-fail → "password is spent — reset on the hub", no marker, no half-configured offbox.
|
confirm (`/var/lib/felhom-agent/escrow-stage/restic_repo_password`) was wiped through the controller
|
||||||
- **fork-4 run gate:** manual `POST /backup/offbox/run` while pending → refused
|
container → agent `DELETE /escrow/stage-secret` → `{"removed":true}`; the file is GONE on felhom-pve, and
|
||||||
("A NAS-mentés a kulcs letétbe helyezésére vár."). No ciphertext before escrow.
|
an idempotent re-wipe returned `{"removed":false}`. Token handled in a shell var only.
|
||||||
- **Restart idempotency:** bootstrap restart → zero bridge activity (marker no-op), no re-consume.
|
|
||||||
- **Closing the loop (Option A, Viktor-approved):** the repo password was already escrowed (preserved by
|
|
||||||
`WriteOffboxSecrets` — the DR-inject seam), so confirm-escrow was truthful without a new ceremony →
|
|
||||||
`escrowed` → first run: **restic repo initialized, 2 apps (audiobookshelf, immich), 2 snapshots, 34s** —
|
|
||||||
independently verified by SFTP-listing the repo objects with the bridge-installed key + pinned host key.
|
|
||||||
|
|
||||||
## Standing state
|
## NOT exercised live
|
||||||
Demo offbox targets the NEW box (`u629488-sub1…:/home/felhom-repo`), `escrowed`, un-paused, daily schedule.
|
Hub F4 re-issue (would reset a real credential — the demo's working offsite must not be touched; a live
|
||||||
Old-box offsite (`u629193-sub1`) untouched — frozen archive until a NEW-box restore round-trip is verified.
|
exercise needs a throwaway customer under supervision). Unit-tested with the exactly-1-scope red-proof.
|
||||||
|
F5 (submit-disable JS) ships in the hub template — visible on the next operator save.
|
||||||
|
|
||||||
## Open follow-ups (controller-relevant)
|
## NEXT
|
||||||
- F2 (hub): fresh-subaccount DNS lag → first-save scan 502; retry-with-backoff in `ProvisionOffsite`.
|
SLICE 3 (escrow auto-confirm — inherits the wipe-on-escrowed), SLICE 4 (soft-quota), NEW-box restore
|
||||||
- F4 (hub): no password-reset path — the recovery the controller's "reset on the hub" message references
|
round-trip → retire the old-box archive, Peti onboarding runbook.
|
||||||
doesn't exist yet; today's recovery is delete-subaccount + re-save.
|
|
||||||
- SLICE 3 (escrow auto-confirm — replaces the manual confirm exercised here), SLICE 4 (soft-quota).
|
|
||||||
- NEW-box restore round-trip, then retire the old sub-account.
|
|
||||||
|
|||||||
@@ -750,6 +750,13 @@ not just those with HDD data. Non-HDD apps can configure destination, method, an
|
|||||||
> nothing persisted, retried on the next config refresh/restart; a consumed-but-failed install logs a loud
|
> nothing persisted, retried on the next config refresh/restart; a consumed-but-failed install logs a loud
|
||||||
> "password is spent — reset on the hub"). The 15-min hub-report → config-refresh cycle is the trigger, so
|
> "password is spent — reset on the hub"). The 15-min hub-report → config-refresh cycle is the trigger, so
|
||||||
> descriptor-to-applied latency is ≤ ~15 min.
|
> descriptor-to-applied latency is ≤ ~15 min.
|
||||||
|
> - **Key-auth-first (v0.107.0):** on a descriptor change, if the ALREADY-INSTALLED key still authenticates
|
||||||
|
> (`SFTPKeyAuthProber`, pinned to the freshly-verified host key — the probe never bypasses the fingerprint
|
||||||
|
> verify), the bridge re-pins + reconfigures WITHOUT consuming a one-time password. Fresh guests fall
|
||||||
|
> through to the full consume+install path. The hub's "Re-issue offsite credentials" (v0.39.0) is the
|
||||||
|
> recovery for a genuinely-spent password on a fresh guest.
|
||||||
|
> - **Staged-secret wipe (v0.107.0):** confirm-escrow calls the agent's `DELETE /escrow/stage-secret`
|
||||||
|
> (agent ≥ v0.78.0) whenever `EscrowState` flips to `escrowed` — best-effort, loud-logged on failure.
|
||||||
|
|
||||||
> **NAS network storage (v0.92.0, Part A2; pairs with agent v0.50.0).** A customer NAS share (NFS or SMB)
|
> **NAS network storage (v0.92.0, Part A2; pairs with agent v0.50.0).** A customer NAS share (NFS or SMB)
|
||||||
> is a **distinct storage KIND** from a physical drive (`StoragePath.Kind == "network"`), for **bulk media**.
|
> is a **distinct storage KIND** from a physical drive (`StoragePath.Kind == "network"`), for **bulk media**.
|
||||||
|
|||||||
Reference in New Issue
Block a user