v0.3.2: reversible SetConfig step in --selftest=task (slice-4 pre-check)
Append a reversible SetConfig write+revert to runSelftestTask: read GuestConfig, write a `description` marker, verify it landed, restore the original (or delete if absent), verify the restore. Handles PVE's dual-mode SetConfig return (empty UPID = synchronous; UPID = WaitTask+assert OK). Live self-gate PASSED on demo-felhom / guest 9999. Findings: - LXC `description` write is synchronous (empty UPID) — dual-mode modeling confirmed; empty string is success, not an error. - PVE appends a trailing newline to `description` on read; slice-4 reconcile must normalize description comparisons (hence normDesc helper). First live exercise of the VM.Config.* privilege cluster. Standing operator token rotated during the run; new secret stored out-of-band, not in the repo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,38 @@
|
||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||
change that gets pushed.
|
||||
|
||||
## v0.3.2 — SetConfig selftest extension (slice-4 pre-check) (2026-06-08)
|
||||
|
||||
The gate before slice 4: prove `SetConfig` works live under the scoped token before
|
||||
reconcile is built on it. **Self-gated live run PASSED** on `demo-felhom`/guest 9999.
|
||||
|
||||
### Added
|
||||
- **Reversible `SetConfig` step appended to `--selftest=task`** (`cmd/felhom-agent/main.go`,
|
||||
`selftestSetConfig`): read `GuestConfig` → write a `description` marker
|
||||
(`felhom-selftest <RFC3339>`) → verify it landed → restore the original value (or
|
||||
`delete` the key if it was absent) → verify the restore. Handles PVE's dual-mode
|
||||
`SetConfig` return per the `mutate.go` contract: empty UPID = synchronous success
|
||||
(printed `synchronous`); non-empty UPID = `WaitTask` + assert `exitstatus=OK`.
|
||||
The existing snapshot → rollback → delete-snapshot steps are unchanged. First live
|
||||
exercise of the **`VM.Config.*`** privilege cluster.
|
||||
- **`normDesc` / `extraString` helpers** — `extraString` decodes a string-valued key
|
||||
from `GuestConfig.Extra` (raw JSON); `normDesc` strips the trailing newline PVE
|
||||
appends to `description` on read, so a written value round-trips equal.
|
||||
|
||||
### Finding (live)
|
||||
- The LXC `description` write returned **synchronous (empty UPID)** — PVE applied it
|
||||
inline, no task. The agent's dual-mode `SetConfig` modeling is correct: the
|
||||
empty-string path is real and must not be treated as an error.
|
||||
- PVE **appends a trailing `\n` to `description`** on read (stored URL-encoded as
|
||||
`%0A`). A naive exact-match reconcile would see perpetual drift — slice-4 reconcile
|
||||
must normalize `description` comparisons (hence `normDesc`).
|
||||
|
||||
### Ops
|
||||
- Standing operator token (`felhom-agent@pve!agent`, privsep) **rotated** during this
|
||||
run (the prior secret was not retrievable); role + both user/token ACL rows
|
||||
re-confirmed at `/`. New secret stored out-of-band, **not persisted to the repo**.
|
||||
Guest 9999 left pristine (stopped, no `description`, no leftover snapshot). Version → 0.3.2.
|
||||
|
||||
## Docs + live validation — no version bump (2026-06-08)
|
||||
|
||||
### Changed
|
||||
|
||||
Reference in New Issue
Block a user