doc 03 §6/§4/§9 + doc 02: slice 8C implemented — controller de-privileged, slice 8 CLOSED (2026-06-10)
§6: disk-management endpoints + reframed principle (non-data-destructive self-serve; data-destructive stays operator-signed; classifier = agent-internal device inspection). §4: data-bearing-ness is agent-internal, never caller-claimed. §9: 8C implemented, slice 8 CLOSED. doc 02: EXECUTED banner. Validated live (data-bearing format refused; de-privileged controller). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,49 +4,42 @@
|
||||
|
||||
---
|
||||
|
||||
# REPORT — Slice 8 Phase A spike: agent↔controller channel + controller deploy plumbing (2026-06-10)
|
||||
# REPORT — Slice 8C docs: controller de-privileging + disk classifier (slice 8 CLOSED) (2026-06-10)
|
||||
|
||||
## Type
|
||||
|
||||
**SPIKE** (CC-executed on the demo). Doc-only deliverable — **no hub/code change, no version bump,
|
||||
no deploy**. Probes the two unvalidated foundations of slice 8 *before* speccing the local API
|
||||
(doc §6) and the provisioning back-half. Findings:
|
||||
[documentation/tests/slice8a-channel-deploy-spike-findings.md](documentation/tests/slice8a-channel-deploy-spike-findings.md).
|
||||
Documentation update for **slice 8C** (the implementation is in `felhom-agent` v0.12.0 +
|
||||
`felhom-controller` v0.37.0; no hub change). Slice 8 is now **CLOSED**.
|
||||
|
||||
## What was proven on `demo-felhom`
|
||||
## What changed (doc 03 — host-agent)
|
||||
|
||||
Spike guest **8200** was produced by the **real slice-7 bring-up job** (`felhom-agent v0.9.0`,
|
||||
`-mode provision`) from the golden archive — a golden, link-up, Docker-29.5.3 guest in 8s, fresh MAC.
|
||||
Torn down at the end; demo left as found (only pre-existing 9001/9999 remain; golden archive intact).
|
||||
- **§6** — added the disk-management endpoints (`GET /disks`, `POST /disks/{assign,eject,format}`)
|
||||
and **reframed the principle**: a controller may do *non-data-destructive* storage setup self-serve
|
||||
(list / assign / eject / format-blank); **anything that can lose customer data stays
|
||||
operator-signed (§4)**, with the **classifier (agent-internal device inspection)** as the enforcer.
|
||||
The 8C invariant: the agent decides data-bearing-ness by inspecting the device itself, never the
|
||||
caller's claim; a data-bearing format → `ClassStorageWipe` → gate → `pending_signature` (signed
|
||||
completion is slice 10). Marked **implemented**.
|
||||
- **§4** — added: data-bearing-ness is **agent-internal evidence, never the caller's claim**
|
||||
(mirrors the agent-internal scratch-provenance rule); destructive completion → slice 10.
|
||||
- **§9 slice table** — **8C implemented → slice 8 CLOSED**: agent v0.12.0 (`/disks` + classifier
|
||||
gate + `mkfs`); controller v0.37.0 (~12.3k LOC disk-execution retired, `backup.Manager` split to
|
||||
app-data, disk mgmt rewired to the agent, container de-privileged). §13 + doc changelog updated.
|
||||
|
||||
### 1. The channel (guest → host HTTPS over `vmbr0`, fingerprint-pinned) — **PASS**
|
||||
A throwaway self-signed HTTPS stub on `192.168.0.162:8443`, hit from **inside guest 8200**:
|
||||
- correct pin + guest-8200 token → **200**; no token → **401**; **other-guest** token → **403**
|
||||
(self-scoping holds); **wrong pin → hard TLS failure** (curl exit 90 — the pin gates the handshake).
|
||||
- **No firewall rule needed** (PVE firewall off; guest and host share the `vmbr0` /24, direct route).
|
||||
- Security note: the local-API binds the host **LAN IP** → reachable by anything on the LAN; **auth
|
||||
is the only gate** (it held). Both pin forms captured (SPKI + leaf-cert SHA-256) for the 8A choice.
|
||||
## What changed (doc 02 — controller module map)
|
||||
|
||||
### 2. The deploy plumbing (no `pct exec` — config mount + golden-baked unit) — **PASS**
|
||||
The F3 principle end-to-end: agent stays host-side, populates a **read-only config mount**
|
||||
(`/etc/felhom-bootstrap`, bind-mount hotplugged live); a **golden-baked oneshot** reads it →
|
||||
`docker login` (token via `--password-stdin`) → `docker pull …/felhom-controller:v0.34.0` →
|
||||
`docker run`. The controller came up **Up (healthy)**; an in-guest process read the bootstrap token
|
||||
from the mount and reached the host `/storage` → **200**. **No `pct exec` used.**
|
||||
- Added an **EXECUTED** banner: the map's target state is realized — the disk subsystem is deleted,
|
||||
`backup.Manager` split, disk mgmt rewired to the agent, the container de-privileged. The in-guest
|
||||
controller is now Docker-only with no disk/Proxmox privileges.
|
||||
|
||||
## Gotchas carried into 8A / the back-half
|
||||
1. **Unprivileged-LXC uid mapping** — the agent must `chown 100000:100000` files it writes into the
|
||||
mount (else the guest reads them as `nobody`; the secret config is inaccessible).
|
||||
2. **Registry-cred scope** — the bootstrap currently carries the shared `admin` pull token; production
|
||||
wants a narrow, read-only, ideally per-guest/short-lived registry token (mount is the right channel).
|
||||
3. **Controller config contract** — `bootstrap.json` ≠ the controller's `controller.yaml`; the
|
||||
controller boots to *setup mode* until 8A emits the real config format/path (or the unit translates).
|
||||
4. **Pin form** (SPKI vs leaf-cert SHA-256) and **LAN exposure** narrowing — 8A/back-half decisions.
|
||||
## Live validation (cross-repo, on the demo)
|
||||
|
||||
## Verdict — **GO** to spec 8A (local-API server + the 7 §6 endpoints) and the provisioning back-half.
|
||||
A provisioned **de-privileged** controller v0.37.0 (`Privileged=false`; mounts only bootstrap + data
|
||||
+ docker.sock) drove the agent disk API: `GET /disks` returned data-bearing flags, and a
|
||||
**data-bearing format was refused** (`pending_signature`, nothing formatted) — the security
|
||||
centerpiece, proven live. See the agent + controller REPORTs.
|
||||
|
||||
## Secret handling (held)
|
||||
Test local-API tokens + the registry pull cred kept in `0600` host files, referenced by location,
|
||||
never logged/committed; the stub never logged the `Authorization` header; `docker login` via
|
||||
`--password-stdin`. No real per-guest token or registry cred in git. All scratch shredded on teardown.
|
||||
No throwaway registry token was minted (the existing `gitea-creds` admin cred was used by reference).
|
||||
## Deferred
|
||||
|
||||
The operator-signed completion of a data-bearing wipe/format → **slice 10**. No hub change → no
|
||||
deploy. No secrets committed.
|
||||
|
||||
Reference in New Issue
Block a user