package apply import ( "context" "os" "path/filepath" "strings" "testing" "github.com/novox/mesh-host/internal/store" ) // Where the node-engine places nothing and mounts nothing, whoever asks (novox/hq issue 339). A module's // `places` setting moved a directory anywhere, with an owner it named, and the engine — root — made it so: a // directory at /etc owned by a caller's account handed it /etc. Each test here is a declaration the controller // might send; the engine refuses it whatever the controller decided. func applyOnce(t *testing.T, resources string, run Runner, state store.State) (Report, store.State, error) { t.Helper() if run == nil { run = noServices } return Apply(context.Background(), archHost(t), declare(t, resources), state, store.OriginDeclared, run, nil, nil) } func refusedFor339(t *testing.T, what string, err error) { t.Helper() if err == nil || !strings.Contains(err.Error(), "issue 339") || !strings.Contains(err.Error(), "nothing was touched") { t.Fatalf("%s was not refused as the machine's own: %v", what, err) } } func TestNoDirectoryIsPlacedAtTheMachinesOwn(t *testing.T) { for _, path := range []string{"/", "/etc", "/etc/", "/usr", "/var", "/var/lib", "/home", "/run", "/boot", "/root", "/var/lib/mesh-host", "/var/lib/mesh-host/identity", "/proc/1/task", "/sys/kernel", "/dev/shm", "/root/.ssh", "/srv/../etc"} { _, _, err := applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+path+`","mode":"0755"}`, nil, store.State{}) refusedFor339(t, path, err) } // Below /etc, /usr or /run, a directory is root's: the machine's configuration is read as root's word. _, _, err := applyOnce(t, `{"id":"notes.data","type":"directory","path":"/etc/sudoers.d","owner":"1001:1001"}`, nil, store.State{}) refusedFor339(t, "/etc/sudoers.d owned by another account", err) _, _, err = applyOnce(t, `{"id":"notes.data","type":"directory","path":"/etc/systemd/system/getty@.service.d",`+ `"owner":"1001:1001"}`, nil, store.State{}) refusedFor339(t, "a drop-in directory owned by another account", err) } func TestNoAccessIsAtTheMachinesOwn(t *testing.T) { for _, path := range []string{"/", "/etc", "/etc/ssl", "/usr", "/var/lib", "/home", "/root", "/proc", "/var/lib/mesh-host", "/run/docker"} { _, _, err := applyOnce(t, `{"id":"notes.media","type":"access","path":"`+path+`"}`, nil, store.State{}) refusedFor339(t, "an access at "+path, err) } } // A container is never handed the machine's own as a mount, nor a directory or access the engine refused. func TestNoContainerMountsTheMachinesOwn(t *testing.T) { ran := false run := func(ctx context.Context, name string, args ...string) (string, error) { args = oldShape(name, args) switch { case args[0] == "info": return "27.0\n", nil case args[0] == "container": return "", os.ErrNotExist case args[0] == "run": ran = true return "deadbeef\n", nil } return "", nil } for _, mount := range []string{"/:/host", "/etc:/host-etc", "/var/lib:/data", "/home:/homes:ro", "/var/lib/mesh-host:/state", "/proc:/p", "/dev:/d", "/root/.ssh:/keys", "/boot/efi:/efi"} { ran = false _, _, err := Apply(context.Background(), archHost(t), parseTrusted(t, `{"declaration":1,"resources":[ {"id":"notes.server","type":"container","name":"notes","image":"`+pinned+`","volumes":["`+mount+`"]} ]}`), store.State{}, store.OriginCarried, run, nil, nil) refusedFor339(t, "a container mounting "+mount, err) if ran { t.Fatalf("a container mounting %s was run", mount) } } } // The path is not followed: a link where a directory is declared, or a link on the way to it, is judged where // it leads. func TestALinkIsNotFollowedToTheMachinesOwn(t *testing.T) { dir := t.TempDir() target := filepath.Join(dir, "target") if err := os.Mkdir(target, 0o700); err != nil { t.Fatal(err) } link := filepath.Join(dir, "link") if err := os.Symlink(target, link); err != nil { t.Fatal(err) } _, _, err := applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+link+`","mode":"0755"}`, nil, store.State{}) refusedFor339(t, "a directory that is a link", err) if info, _ := os.Stat(target); info.Mode().Perm() != 0o700 { t.Fatalf("the link's target was changed to %o", info.Mode().Perm()) } // A link on the way: /via → /usr, so /via/share is /usr/share. via := filepath.Join(dir, "via") if err := os.Symlink("/usr", via); err != nil { t.Fatal(err) } _, _, err = applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+via+`/share"}`, nil, store.State{}) refusedFor339(t, "a directory reached through a link to /usr", err) _, _, err = applyOnce(t, `{"id":"notes.media","type":"access","path":"`+via+`"}`, nil, store.State{}) refusedFor339(t, "an access reached through a link to /usr", err) } // A directory found here, that the mesh did not make, keeps its owner and mode; one the mesh made keeps the // declared mode, as before. func TestAFoundDirectoryIsUsedAsFound(t *testing.T) { dir := t.TempDir() found := filepath.Join(dir, "found") if err := os.Mkdir(found, 0o700); err != nil { t.Fatal(err) } report, state, err := applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+found+`","mode":"0755"}`, nil, store.State{}) if err != nil { t.Fatal(err) } if info, _ := os.Stat(found); info.Mode().Perm() != 0o700 { t.Fatalf("a directory the mesh did not make was chmodded to %o", info.Mode().Perm()) } if len(report.Outcomes) != 1 || !strings.Contains(report.Outcomes[0].Detail, "used as found") { t.Fatalf("the report does not say it was used as found: %+v", report.Outcomes) } if a, _ := state.Find("notes.data"); !a.AsFound { t.Fatal("the record does not say the directory was found") } // Still found at the next apply, and never removed: undeclared, it is forgotten and left. if _, state, err = applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+found+`","mode":"0755"}`, nil, state); err != nil { t.Fatal(err) } if info, _ := os.Stat(found); info.Mode().Perm() != 0o700 { t.Fatalf("a found directory was chmodded at the next apply to %o", info.Mode().Perm()) } if _, _, err = applyOnce(t, `{"id":"notes.other","type":"directory","path":"`+filepath.Join(dir, "other")+`"}`, nil, state); err != nil { t.Fatal(err) } if _, err := os.Stat(found); err != nil { t.Fatalf("a found directory was removed: %v", err) } // The mesh's own: made by it, its mode is maintained. made := filepath.Join(dir, "made") _, state, err = applyOnce(t, `{"id":"notes.made","type":"directory","path":"`+made+`","mode":"0755"}`, nil, store.State{}) if err != nil { t.Fatal(err) } if err := os.Chmod(made, 0o700); err != nil { t.Fatal(err) } if _, state, err = applyOnce(t, `{"id":"notes.made","type":"directory","path":"`+made+`","mode":"0755"}`, nil, state); err != nil { t.Fatal(err) } if info, _ := os.Stat(made); info.Mode().Perm() != 0o755 { t.Fatalf("the mesh's own directory was not given its mode back: %o", info.Mode().Perm()) } // Moved — a placement changed — onto a directory that was already there: that one is found, not the mesh's. if _, _, err = applyOnce(t, `{"id":"notes.made","type":"directory","path":"`+found+`","mode":"0755"}`, nil, state); err != nil { t.Fatal(err) } if info, _ := os.Stat(found); info.Mode().Perm() != 0o700 { t.Fatalf("a placement moved onto a found directory chmodded it to %o", info.Mode().Perm()) } } // The module's own directories keep being placed: below /var/lib, below /etc as root's, a container's mount of // the machine's docker socket. func TestAModulesOwnPlacesAreStillPlaced(t *testing.T) { for _, path := range []string{"/var/lib/notes/data", "/etc/systemd/logind.conf.d", "/var/run/fail2ban", "/srv/notes", "/mnt/plex/config", "/storage/media", "/var/lib/mesh/registry"} { if err := refusePath(path, placingDirectory, "notes", ""); err != nil { t.Errorf("%s: %v", path, err) } } for _, path := range []string{"/var/lib/minio-store", "/var/run/docker.sock", "/services/ollama", "/storage/media", "/etc/localtime", "/proc/cpuinfo", "/dev/null", "/dev/dri"} { if err := refusePath(path, placingMount, "notes", ""); err != nil { t.Errorf("a mount of %s: %v", path, err) } } if err := refusePath("/var/lib/notes/data", placingDirectory, "notes", "1001:2000"); err != nil { t.Errorf("an owner below /var/lib: %v", err) } }