v0.5.0: slice 5 Phase B — the host-root surface (mounts + SMART + grow + destructive gate)
The privileged write surface, isolated behind a narrow, arg-validated, adversarially- tested seam (HostOps), the same discipline as the slice-4 gate. Completes slice 5. - internal/storage: HostOps seam + SudoHostOps (systemd .mount units by fs-UUID, detach, SMART, lvs) via sudoers allowlist + fixed arg vectors, no shell; NoopHostOps fallback. - validate.go: strict UUID/mount-path/device/LVM validators + in-process systemd-escape. Headline test: adversarial matrix (metacharacters/traversal/malformed) refused with zero exec. - smart.go: smartctl SATA + NVMe parse, UNKNOWN-degrade; lvs thin-pool metadata fill. - observer enrichment (Observe only): fills smart + thin-pool metadata. - watchdog: benign re-mount response off the poll path (DevicePresent probe, rate-limited). - reconcile: ActionResize (benign, grow-only) + proxmox.ResizeLXC; destructive storage ops (ClassStorageWipe/Decommission) through the slice-4 gate, target-scoped; built+tested, inert live. - --selftest=storage [-watch] live harness; configs/felhom-agent.sudoers; privileged.* knobs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,11 @@ const (
|
||||
ClassStart OpClass = "start"
|
||||
ClassStop OpClass = "stop"
|
||||
ClassSetConfig OpClass = "set_config" // benign sizing/description changes only
|
||||
ClassResize OpClass = "resize" // GROW-only rootfs/volume resize (slice 5 Phase B)
|
||||
|
||||
// Benign storage attach — re-mount-by-UUID of a known target whose device returned
|
||||
// (slice 5 Phase B). Additive (no data loss), so benign by construction.
|
||||
ClassStorageMount OpClass = "storage_mount"
|
||||
|
||||
// Benign by construction — classified now, executors land in later slices.
|
||||
ClassCreate OpClass = "create" // provision a NEW guest (restore-to-new, slice 7)
|
||||
@@ -76,7 +81,7 @@ func (p Provenance) internalEvidence() bool {
|
||||
// - an UNKNOWN class fails safe → Destructive (require a signature).
|
||||
func Classify(class OpClass, prov Provenance) Disposition {
|
||||
switch class {
|
||||
case ClassStart, ClassStop, ClassSetConfig, ClassCreate, ClassRestart:
|
||||
case ClassStart, ClassStop, ClassSetConfig, ClassResize, ClassStorageMount, ClassCreate, ClassRestart:
|
||||
return Benign
|
||||
case ClassGuestDestroy, ClassStorageWipe, ClassRestoreOverwrite, ClassDecommission:
|
||||
if prov.internalEvidence() {
|
||||
@@ -100,6 +105,8 @@ func classOfAction(k ActionKind) OpClass {
|
||||
return ClassStop
|
||||
case ActionSetConfig:
|
||||
return ClassSetConfig
|
||||
case ActionResize:
|
||||
return ClassResize
|
||||
default:
|
||||
return OpClass(k)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user