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: