//go:build linux package apply import ( "context" "errors" "os" "path/filepath" "strings" "testing" "golang.org/x/sys/unix" "github.com/novox/mesh-host/internal/declaration" "github.com/novox/mesh-host/internal/store" ) // The engine delivers before the controller half (novox/hq ADR 0325): a controller that does not speak // link.IdentityContract sends no identities, no users and no taken, and every access of its declarations is applied // exactly as before this engine — mounted when present, refused when absent (ADR 0051 §7), nothing kept, nothing // made, no container held, nothing judged. These are origin/main's outcomes, word for word. func TestAnOlderControllersAccessesAreAppliedExactlyAsBefore(t *testing.T) { keeping(t, nil, nil) dir := userDir(t) unwritable := filepath.Join(dir, "library") // its group may not write it empty := filepath.Join(dir, "spool") absent := filepath.Join(dir, "media", "movies") for _, d := range []string{unwritable, empty} { if err := os.Mkdir(d, 0o755); err != nil { t.Fatal(err) } if err := os.Chmod(d, 0o755); err != nil { t.Fatal(err) } } // A root-owned empty folder, read only. rootEmpty := "" for _, c := range []string{"/var/empty", "/srv/http", "/srv/ftp"} { if entries, err := os.ReadDir(c); err == nil && len(entries) == 0 { if uid, _, _ := statOwner(mustLstat(t, c)); uid == 0 { rootEmpty = c break } } } resources := []string{ `{"id":"radarr.library","type":"access","path":"` + unwritable + `","mode":"read-write"}`, `{"id":"sab.spool","type":"access","path":"` + empty + `","mode":"read-write"}`, `{"id":"plex.movies","type":"access","path":"` + absent + `"}`, `{"id":"plex.app","type":"container","name":"plex","image":"` + pinned + `","volumes":["` + absent + `:/movies"]}`, } if rootEmpty != "" { resources = append(resources, `{"id":"web.root","type":"access","path":"`+rootEmpty+`","mode":"read-write"}`) } var started bool run := func(_ context.Context, name string, args ...string) (string, error) { if len(args) > 0 && args[0] == "run" { started = true } if len(args) > 0 && args[0] == "container" { if started { return "true\t" + containerSpec(declare(t, resources[3]).Resources[0].(*declaration.Container), inputs{}), nil } return "", errors.New("no such container") } return "", nil } toUser(t) report, _, err := Apply(context.Background(), archHost(t), declare(t, strings.Join(resources, ",")), store.State{}, store.OriginDeclared, run, nil, nil) if err == nil || !strings.Contains(err.Error(), absent+" is not there, and the mesh does not own it — the operator "+ "must provide it") { t.Fatalf("an absent access is not refused as before: %v", err) } for id, mode := range map[string]string{"radarr.library": "read-write", "sab.spool": "read-write"} { o := outcomeOf(report, id) if o.Action != "unchanged" || o.Detail != "operator-owned; present, "+mode+", nothing managed" { t.Errorf("%s: %+v, and before it was unchanged, %q", id, o, "operator-owned; present, "+mode+", nothing managed") } } if rootEmpty != "" { if o := outcomeOf(report, "web.root"); o.Action != "unchanged" { t.Errorf("a root-owned folder was judged: %+v", o) } } if !started { t.Error("a container mounting an absent access was held, and before it was created") } if _, err := os.Stat(absent); !errors.Is(err, os.ErrNotExist) { t.Error("an absent access was made") } for _, d := range []string{unwritable, empty} { if n, _ := unix.Getxattr(d, aclAccessXattr, nil); n > 0 { t.Errorf("an ACL was set on %s", d) } if info := mustLstat(t, d); info.Mode().Perm() != 0o755 { t.Errorf("%s changed mode: %o", d, info.Mode().Perm()) } } if all, _ := KeptFolders.All(); len(all) != 0 { t.Errorf("folders were recorded as kept: %v", all) } if len(Leftovers()) != 0 || len(WaitingOnAccess(declare(t, strings.Join(resources, ",")))) != 0 { t.Error("something was said or held for an older controller's access") } } func mustLstat(t *testing.T, path string) os.FileInfo { t.Helper() info, err := os.Lstat(path) if err != nil { t.Fatal(err) } return info } // Review (low): a folder no access names, whose filesystem could not be named this look, is not said as its disk // being away. func TestALeftoverSaysWhyItsWalkCouldNotRun(t *testing.T) { uuid, fsid, source := "6f1c0a4e-1b2d-4c3e-8f00-aa11bb22cc33", "0000080100000000", "/dev/sdb1" _, lib, access := poolNamed(t, &uuid, &fsid, &source) takeIt(t, lib, access) other := `{"id":"x.dir","type":"directory","path":"` + filepath.Join(filepath.Dir(filepath.Dir(lib)), "x") + `"}` if _, _, err := applyAccesses(t, store.State{}, other); err != nil { t.Fatal(err) } uuid, fsid, source = "", "0000000000000000", "" // nothing names it now toUser(t) ReconcileKept(context.Background()) left := Leftovers() if len(left) != 1 || strings.Contains(left[0].Why, "disk") || !strings.Contains(left[0].Why, "could not be named") { t.Fatalf("the leftover does not say why its walk could not run: %+v", left) } }