98f3cdd76a
gates / gates (push) Successful in 25s
- felhom-mkfs-guarded: the 0.158.0 exemption for a sibling part mounted at /mnt/<name> + under /mnt/felhom-drives is removed — the agent can make that corroborating mount itself. Every mount of every node outside /mnt/felhom-drives refuses (kernel mount table); an unlistable disk refuses. CandidatePartition.Formattable is false for every part of a disk with a mounted node, so it is never offered for formatting (attach still is). - felhom-internal-place: a failed lvs listing, a listing without the pool, or a blkid exit other than 0/2 refuses (they read as "nothing promised" / "no signature" before). Every new test was seen failing against the 0.158.0 versions. Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
92 lines
4.0 KiB
Go
92 lines
4.0 KiB
Go
package storage
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Partitions as places (felhom.eu architecture/16 §6, agent v0.158.0): every partition of a free disk with its own
|
|
// state; Felhom's own drive shown but never offered; anything foreign, layered or a member never listed.
|
|
|
|
const partTree = `{"blockdevices":[
|
|
{"name":"sdb","fstype":null,"mountpoint":null,"children":[
|
|
{"name":"sdb1","fstype":"ext4","mountpoint":"/mnt/felhom-drives/hdd_1"},
|
|
{"name":"sdb2","fstype":null,"mountpoint":null},
|
|
{"name":"sdb3","fstype":"ntfs","mountpoint":null},
|
|
{"name":"sdb4","fstype":"xfs","mountpoint":null},
|
|
{"name":"sdb5","fstype":"ext4","mountpoint":"/mnt/films"},
|
|
{"name":"sdb6","fstype":"ext4","mountpoint":"/srv/data"},
|
|
{"name":"sdb7","fstype":"LVM2_member","mountpoint":null,"children":[{"name":"vg-lv","fstype":"ext4","mountpoint":null}]},
|
|
{"name":"sdb8","fstype":"crypto_LUKS","mountpoint":null}
|
|
]},
|
|
{"name":"sdc","fstype":null,"mountpoint":null,"children":[{"name":"sdc1","fstype":null,"mountpoint":null}]}
|
|
]}`
|
|
|
|
func listParts(owned map[string]bool) map[string]CandidatePartition {
|
|
got := candidatePartitions([]byte(partTree), "sdb",
|
|
func(n string) int64 { return int64(len(n)) << 30 },
|
|
func(n string) int { return int(n[len(n)-1] - '0') },
|
|
func(dev string) (string, bool) { return "uuid-of-" + strings.TrimPrefix(dev, "/dev/"), true },
|
|
owned)
|
|
m := map[string]CandidatePartition{}
|
|
for _, p := range got {
|
|
m[p.Device] = p
|
|
}
|
|
return m
|
|
}
|
|
|
|
func TestPartitions_StatesPerPartition(t *testing.T) {
|
|
m := listParts(map[string]bool{"/mnt/films": true})
|
|
want := map[string]string{"/dev/sdb1": PartInUse, "/dev/sdb2": PartEmpty, "/dev/sdb3": PartFilesystem,
|
|
"/dev/sdb4": PartFilesystem, "/dev/sdb5": PartInUse}
|
|
if len(m) != len(want) {
|
|
t.Fatalf("want exactly %d listed partitions, got %+v", len(want), m)
|
|
}
|
|
for dev, st := range want {
|
|
if m[dev].State != st {
|
|
t.Fatalf("%s: want %s, got %+v", dev, st, m[dev])
|
|
}
|
|
}
|
|
if m["/dev/sdb2"].DurableID != "" || m["/dev/sdb2"].Mountable {
|
|
t.Fatalf("an empty part has no attach key: %+v", m["/dev/sdb2"])
|
|
}
|
|
if !m["/dev/sdb4"].Mountable || m["/dev/sdb4"].DurableID != "uuid:uuid-of-sdb4" || m["/dev/sdb4"].Number != 4 {
|
|
t.Fatalf("an xfs part is usable by its fs-UUID: %+v", m["/dev/sdb4"])
|
|
}
|
|
if m["/dev/sdb3"].Mountable {
|
|
t.Fatalf("ntfs is a filesystem the agent does not mount as-is: %+v", m["/dev/sdb3"])
|
|
}
|
|
}
|
|
|
|
// A raw /mnt/<name> mount counts as Felhom's own ONLY when corroborated (felhomOwnedMounts); else it is foreign and
|
|
// the part is not listed. Positive control: TestPartitions_StatesPerPartition (the same mount, corroborated).
|
|
func TestPartitions_UncorroboratedMountIsNotOffered(t *testing.T) {
|
|
m := listParts(nil)
|
|
if _, ok := m["/dev/sdb5"]; ok {
|
|
t.Fatalf("an uncorroborated /mnt/films mount must not be listed, got %+v", m["/dev/sdb5"])
|
|
}
|
|
for _, dev := range []string{"/dev/sdb6", "/dev/sdb7", "/dev/sdb8", "/dev/sdc1"} {
|
|
if _, ok := m[dev]; ok {
|
|
t.Fatalf("%s must never be listed (foreign mount, LVM, LUKS, another disk)", dev)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The root wrapper refuses any format on a disk with a mounted node (and trusts no „it is Felhom's own" claim), so a
|
|
// part next to a mounted one is never offered for formatting — only for use. Positive control: an unmounted disk.
|
|
func TestPartitions_FormattableOnlyWhenNothingOnTheDiskIsMounted(t *testing.T) {
|
|
m := listParts(map[string]bool{"/mnt/films": true})
|
|
for dev, p := range m {
|
|
if p.Formattable {
|
|
t.Fatalf("%s: a part of a disk with a mounted part must not be formattable: %+v", dev, p)
|
|
}
|
|
}
|
|
free := `{"blockdevices":[{"name":"sdc","fstype":null,"mountpoint":null,"children":[
|
|
{"name":"sdc1","fstype":null,"mountpoint":null},{"name":"sdc2","fstype":"ext4","mountpoint":null}]}]}`
|
|
got := candidatePartitions([]byte(free), "sdc", func(string) int64 { return 1 << 30 }, func(string) int { return 1 },
|
|
func(string) (string, bool) { return "u", true }, nil)
|
|
if len(got) != 2 || !got[0].Formattable || !got[1].Formattable {
|
|
t.Fatalf("parts of an unmounted disk are formattable, got %+v", got)
|
|
}
|
|
}
|