v0.54.0: format-safety foundation — unclaimed-disk guard + guarded-mkfs wrapper

Impl-1. Format now runs a mandatory unclaimed-disk guard (internal/storage/claim.go:
SystemDisks + lsblk member-FSTYPE + foreign-mount + RO + pvs/zpool; fail-safe →
CLAIMED) before any mkfs — refuses the OS disk / LVM PV / ZFS-mdraid member /
foreign-mounted device even when non-data-bearing (guard sits in Format, not the
handler). Below the agent, mkfs goes ONLY through configs/felhom-mkfs-guarded.sh
(sudoers no longer allowlists raw mkfs.*), which re-checks the catastrophic cases
as root. Read-only pvs/zpool added to FELHOM_DISK. Tests + red-proof; capability
manifest updated. go build/vet/test clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 16:52:31 +02:00
parent 05f22a9ab4
commit 52098302ab
10 changed files with 600 additions and 32 deletions
+28 -8
View File
@@ -156,26 +156,46 @@ func TestInspect_RejectsBadDevice(t *testing.T) {
// ---- Format (mkfs) ----------------------------------------------------------------------
// Format now (Impl-1) runs the unclaimed guard then execs the guarded wrapper (<device> <fstype>),
// not raw mkfs. These use the stubbed guard (unclaimed /dev/sdb; system disk = /dev/sda).
func TestFormat_Ext4(t *testing.T) {
r := &scriptedRunner{}
if err := newSudo(r).Format(context.Background(), "/dev/sdb", "ext4"); err != nil {
defer stubRO(false)()
sr := &scriptRunner{out: map[string][]byte{
"/usr/bin/lsblk": []byte(`{"blockdevices":[{"name":"sdb"}]}`),
}}
ops := newGuardOps(sr, []Mount{{Device: "/dev/sda2", MountPoint: "/"}})
if err := ops.Format(context.Background(), "/dev/sdb", "ext4"); err != nil {
t.Fatal(err)
}
if !r.ran("mkfs.ext4 -F /dev/sdb") {
t.Fatalf("mkfs.ext4 not invoked correctly: %v", r.calls)
if !srRan(sr, "/usr/local/sbin/felhom-mkfs-guarded /dev/sdb ext4") {
t.Fatalf("guarded wrapper not invoked correctly: %v", sr.calls)
}
}
func TestFormat_Xfs(t *testing.T) {
r := &scriptedRunner{}
if err := newSudo(r).Format(context.Background(), "/dev/nvme0n1p1", "xfs"); err != nil {
defer stubRO(false)()
sr := &scriptRunner{out: map[string][]byte{
"/usr/bin/lsblk": []byte(`{"blockdevices":[{"name":"nvme0n1","children":[{"name":"nvme0n1p1"}]}]}`),
}}
ops := newGuardOps(sr, []Mount{{Device: "/dev/sda2", MountPoint: "/"}})
if err := ops.Format(context.Background(), "/dev/nvme0n1p1", "xfs"); err != nil {
t.Fatal(err)
}
if !r.ran("mkfs.xfs -f /dev/nvme0n1p1") {
t.Fatalf("mkfs.xfs not invoked correctly: %v", r.calls)
if !srRan(sr, "/usr/local/sbin/felhom-mkfs-guarded /dev/nvme0n1p1 xfs") {
t.Fatalf("guarded wrapper not invoked correctly: %v", sr.calls)
}
}
// srRan reports whether the scriptRunner recorded a call whose joined form contains substr.
func srRan(sr *scriptRunner, substr string) bool {
for _, c := range sr.calls {
if strings.Contains(strings.Join(c, " "), substr) {
return true
}
}
return false
}
func TestFormat_RejectsBadArgs(t *testing.T) {
r := &scriptedRunner{}
if err := newSudo(r).Format(context.Background(), "/dev/disk/by-uuid/x", "ext4"); err == nil {