Compare commits

..

2 Commits

Author SHA1 Message Date
admin 383522450a REPORT + CONTEXT: v0.158.1 build B, vouched; R-1093 filed
gates / gates (push) Successful in 32s
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-16 10:10:21 +02:00
admin 1a8bed11e7 CHANGELOG: v0.158.1 (security review of 0.158.0; 0.158.0 superseded, do not vouch)
gates / gates (push) Successful in 25s
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-16 04:02:17 +02:00
3 changed files with 52 additions and 31 deletions
+20 -4
View File
@@ -1,3 +1,19 @@
## v0.158.1 — security review of v0.158.0: the mkfs wrapper trusts no sibling claim; the internal-place helper fails closed (2026-10-16)
**v0.158.0 is superseded — do not vouch it.** A security review of `912f7c1` found two defects; both fixed here, each test
seen failing against the 0.158.0 script:
- **`felhom-mkfs-guarded`**: 0.158.0 let a format through when a SIBLING part was mounted at /mnt/<name> AND under
/mnt/felhom-drives („Felhom's own drive"). That corroboration is a mount the agent can make itself, so a compromised agent
could unlock a host owner's disk — the exact case this root wrapper exists for. Removed: any mount of any node outside
/mnt/felhom-drives refuses again (now read from the kernel's mount table for every node; an unlistable disk refuses).
Consequence: the free part next to an in-use Felhom drive cannot be formatted — `CandidatePartition.Formattable` is false
for every part of a disk with a mounted node, and the controller does not offer it (a part with a filesystem can still be
USED). Pinned by configs/test_felhom_mkfs_guarded.py + partitions_test.go.
- **`felhom-internal-place`**: a failed `lvs` listing read as „nothing promised" (a too-large place) and a `blkid` error read
as „no signature" (the only gate before mkfs). Now: a failed listing, a listing without the pool, or any blkid exit other
than 0/2 REFUSES. Three new tests, all failing against 0.158.0.
- Released: tag `v0.158.1` (code `98f3cdd`), sha256 `20264df6…84b76a1`, bundle `c23c3d35…cb1c41b`. **Not vouched.**
## v0.158.0 — the internal data place; partitions as places; add_internal_place (2026-10-16)
Design: felhom.eu `architecture/16-storage-physical-identity.md` §5, §6, §7, §9 (operator rulings D3–D5; the D3 sizes
@@ -17,12 +33,12 @@ ruled 2026-10-16 after the space check, felhom.eu `audits/storage-identity-build
- **Partitions as places** (`internal/storage/partitions.go`): `GET /disks/candidates` lists each partition of a free
disk as empty / filesystem / in_use. A data-bearing part's wipe id binds disk id + part number + fs-UUID
(`byid:<…-partN>+fsuuid:<uuid>`); both must name the same device at format time.
- **`felhom-mkfs-guarded`**: a SIBLING part that is Felhom's own drive (mounted raw at /mnt/<name> AND under
/mnt/felhom-drives) no longer blocks formatting the free part next to it; every other mount still refuses; an
unlistable disk now refuses (it passed before). First tests of the wrapper: `configs/test_felhom_mkfs_guarded.py`.
- **`felhom-mkfs-guarded`** (REVERTED in v0.158.1): a SIBLING part that is Felhom's own drive no longer blocked formatting
the free part next to it. First tests of the wrapper: `configs/test_felhom_mkfs_guarded.py`.
- `configs/` changed (sudoers `FELHOM_INTERNALPLACE`, the helper, the wrapper, the bundle list) — **a config-bundle job
is needed** with the agent update. **Not vouched** (the operator's act).
- Released: tag `v0.158.0` (code `912f7c1`), sha256 `a3589d1d…2caba`, bundle `17066273…fb5c76`.
- Released: tag `v0.158.0` (code `912f7c1`), sha256 `a3589d1d…2caba`, bundle `17066273…fb5c76`. **Superseded by v0.158.1 —
do not vouch** (its mkfs wrapper trusted a sibling claim the agent can fake; its helper failed open).
## v0.157.0 — every storage place knows its physical disk(s); POST /disks/same-disk (2026-10-15)
+6
View File
@@ -1,5 +1,11 @@
# CONTEXT — felhom-agent working state
> **2026-10-16 — v0.158.1 RELEASED and VOUCHED (storage identity build B; 0.158.0 superseded, do not vouch).** The internal
> data place (root helper `felhom-internal-place`, the record in the state dir, mounted at /mnt/belso like a drive), the
> signed `add_internal_place`, partitions in `/disks/candidates` (`formattable` only while nothing on the disk is mounted),
> the partition wipe id `byid:<…-partN>+fsuuid:<uuid>`, the strict mkfs wrapper. Delivered through step bundle
> `0.158.1-step1` (a bundle that adds a path, R16). Next: R-1093 (an empty part's probe reads the parent's partition table).
> **2026-10-15 (night) — v0.157.0 RELEASED, NOT VOUCHED (storage identity build A, felhom.eu `16` §13).** Every storage
> place carries `kind`, `physical_disks`, `identity` (+ reason) in `GET /disks` and the hub report; `POST /disks/same-disk`
> answers the controller (v0.317.0, MinAgent 0.157.0). Computed on every read, never cached. Delivered by signed jobs to
+26 -27
View File
@@ -1,43 +1,42 @@
# REPORT — v0.157.0: every storage place knows its physical disk(s); POST /disks/same-disk (2026-10-15)
# REPORT — v0.158.1: the internal data place, partitions as places, add_internal_place (2026-10-16)
Written in ASD-STE100 Simplified Technical English. Design read first: felhom.eu `architecture/16-storage-physical-identity.md`
(§3, §4, §8, §10; ACCEPTED 2026-10-15, §13 = what was built), `03-host-agent.md`. Task: storage identity build A (operator
rulings D1–D6). Controller counterpart: felhom-controller v0.317.0 (MinAgent 0.157.0); hub v0.154.0 shows the fields.
(§5–§7, §9, §13), `03-host-agent.md`. Task: storage identity build B. v0.158.0 is superseded (security review) — do not vouch it.
## What changed
- `internal/storage/identity.go`: the physical disk(s) under a place, from `/sys`, `/run/udev/data`, `/proc/mounts` only
(no block I/O). `proven`, or `unknown` with `vm` / `network` / `usb_bridge` / `weak_wwn` / `no_serial`.
- `GET /disks` rows and the hub report's `storage_targets` gain `kind`, `physical_disks`, `identity`, `identity_reason`.
- `POST /disks/same-disk` `{a, b}` → `{different, proven, reason, a, b}`; scoped like every `/disks` call; a path the agent
did not mount itself is `unmapped`.
- `configs/` unchanged.
- `configs/felhom-internal-place` (bundle): the ruled size rule, the only lvcreate/mkfs of a system-disk volume; fails closed
on any failed read. Run by the installer (1.33.0 step 5b) and by the new signed op.
- `internal/localapi/internalplace.go`: the record → mount at `/mnt/belso` by fs-UUID like a drive, kind `internal`; never takes a
household drive's `/mnt/belso`; eject/decommission/format refused.
- `internal/signedjobs/internalplace.go`: `add_internal_place` (operator key, no parameters).
- `internal/storage/partitions.go`: each part of a free disk listed (empty / filesystem / in_use, `formattable`); a data-bearing
part's wipe id binds disk id + part number + fs-UUID (`durable_device.go`).
- `configs/felhom-mkfs-guarded.sh`: every mount of every node outside /mnt/felhom-drives refuses (kernel mount table); an
unlistable disk refuses; NO exemption for a sibling claiming to be Felhom's own (0.158.0 had one — removed).
- Sudoers `FELHOM_INTERNALPLACE` (`^(plan|create) 0$`); capability manifest + injection cases.
## Tests and red-proofs
Fixture `/sys` + udev trees for every spike case and five same-disk handler tests. Seen failing first: the LVM thin
„diamond" (tmeta/tdata under one pool) read as a failure — fixed by counting a seen node once. Broken on purpose and seen
failing: the VM rule, the vendor-less WWN rule, the own-mount rule (an absent drive), the `sys_drive` mapping.
`python3 scripts/agent_gates.py`: all OK.
configs/test_felhom_internal_place.py (13), configs/test_felhom_mkfs_guarded.py (8 — first tests of the wrapper; the 0.158.0
wrapper and the old one measured against them), internalplace_test.go (9), internalplace (signedjobs, 4), partitions_test.go
(3), partition_durable_test.go (4), the sudo rule widened → caught. Every new test seen failing first. `agent_gates.py`: green.
## Release and delivery
- `scripts/release-agent.sh 0.157.0`: tag `v0.157.0`, sha256 `addd4041…0aef`, bundle `0604bc60…397a`.
- Delivered by signed `agent_update` jobs to Tester 1, demo-hp and the N100 (the three test boxes). **NOT VOUCHED** — the
operator's act. Until the vouch, the global floor cannot declare MinAgent 0.157.0.
`release-agent.sh 0.158.1`: sha256 `20264df6…84b76a1`, bundle `c23c3d35…cb1c41b`. The bundle ADDS a path, so boxes on an older
wrapper refuse it (R16): a step bundle `0.158.1-step1` (sha `fd968ee1…5c2eb9`, the 0.156.1 bundle with only `felhom-os-apply`
replaced) was published, then per box: agent_update 0.158.1 → step bundle → bundle 0.158.1. Done on Tester 1, demo-hp, the N100.
**Vouched by the operator** (with golden 0.318.0).
## Live proof (method: the agent's local API on each PVE host, with the guest's own token)
## Live proof
| Box | `GET /disks` | same-disk: drive vs system data |
|---|---|---|
| demo-hp | `local`/`local-lvm` proven (SATA SSD), NVMe drive proven (`eui:`), PBS `network` | different, proven |
| N100 | system proven (SATA SSD serial), USB drive proven (the bridge passes the real serial) | different, proven |
| Tester 1 (VM) | every place `unknown/vm` | not proven (`vm`) |
On all three: system data vs `/var/lib/docker` → same disk, proven; a drive name that is not mounted → `unmapped`. The hub
stored the same fields (read from its database with the WAL). Evidence: felhom.eu `audits/storage-identity-buildA-2026-10-15/`.
A fresh one-disk install (512 GB VM, installer 1.33.0): the place made (213 GiB), mounted by the agent, registered by the
controller; nothing of it in a whole-box copy; same-disk internal vs sys_drive: same disk, proven; partitions listed, formatted,
used. Evidence: felhom.eu `audits/storage-identity-buildB-2026-10-15/live/`.
## Observations
1. FILED: R-1083 — scratch box 9202 has no `local_api` in its `bootstrap.json`, so it cannot use any agent call.
2. NOT-A-FINDING: `usb_bridge` is built from the design's rule and was not seen on a real enclosure; that is R-1077, already open.
1. FILED: R-1093 — an empty part asks for the typed confirmation: the probe reads the PTTYPE a partition inherits from its disk.
2. NOT-A-FINDING: the step bundle was needed and is the documented route (R-880); the first 0.158.0 bundle jobs were refused by
R16 as designed, nothing changed on the boxes.