v0.61.0: audit fixes B1 (random temp staging) + D1 (mkfs wrapper member/RO re-checks) + D2 (empty-lsblk fail-safe) + D3 (blank-format anti-retarget)

From AUDIT-blast-radius-hostroot-localapi-2026-07-02.md. Each fix ships with a
non-hollow test + a companion red-proof (shown failing on the pre-fix impl).
Sudoers install-source grants became globs — deploy the sudoers drop-in with
the binary. A1 (stale-lock pool-membership) deliberately excluded (spike).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-03 07:25:50 +02:00
parent cc93dae792
commit 3f382bf762
20 changed files with 767 additions and 44 deletions
+30
View File
@@ -64,6 +64,36 @@ func TestClassifyClaim(t *testing.T) {
}
}
// TestClassifyClaim_EmptyNodesRefused is the audit-D2 negative test: a successful-but-EMPTY lsblk
// (`{"blockdevices":[]}` → zero nodes) previously skipped the member/mount loop entirely and returned
// (true,"unclaimed") — the one hole in the "undeterminable ⇒ claimed" fail-safe. It must refuse.
func TestClassifyClaim_EmptyNodesRefused(t *testing.T) {
for _, nodes := range [][]claimNode{nil, {}} {
f := claimFacts{device: "/dev/sdd", wholeDisk: "/dev/sdd", wholeDiskOK: true, nodes: nodes}
unclaimed, reason := classifyClaim(f)
if unclaimed {
t.Fatalf("nodes=%v: empty topology classified UNCLAIMED (reason %q) — fail-safe hole", nodes, reason)
}
if !strings.Contains(reason, "empty block topology") {
t.Errorf("nodes=%v: reason %q missing the empty-topology explanation", nodes, reason)
}
}
}
// TestClassifyClaim_TargetAbsentFromTree (audit D2): lsblk returned SOME tree, but the target
// whole-disk is not in it — the loop inspected the wrong device's signals. Undeterminable → refuse.
func TestClassifyClaim_TargetAbsentFromTree(t *testing.T) {
f := claimFacts{device: "/dev/sdd", wholeDisk: "/dev/sdd", wholeDiskOK: true,
nodes: []claimNode{{name: "sdc"}, {name: "sdc1", fstype: "ntfs"}}} // benign signals, wrong disk
unclaimed, reason := classifyClaim(f)
if unclaimed {
t.Fatalf("target-absent tree classified UNCLAIMED (reason %q)", reason)
}
if !strings.Contains(reason, "absent from block topology") {
t.Errorf("reason %q missing the target-absent explanation", reason)
}
}
func TestParseLsblkNodes(t *testing.T) {
out := []byte(`{"blockdevices":[{"name":"sdd","fstype":null,"mountpoint":null,"children":[{"name":"sdd1","fstype":"ntfs","mountpoint":null}]}]}`)
nodes, err := parseLsblkNodes(out)