package apply import ( "context" "os" osuser "os/user" "path/filepath" "sort" "strings" "testing" "github.com/novox/mesh-host/internal/store" ) // Defends novox/hq ADR 0182 and to-be 41: a parent the host makes inside an owner's home is the // owner's, one that was there is held as found, and one outside the home is made as before. // aHome gives the account running the test a home in a directory the test owns, and writes down // every directory the host gives to whom. The account's own name, so what the host chowns resolves // without being root; the record, so what was given is told apart from what was merely made. func aHome(t *testing.T) (home, owner string, given map[string]string) { t.Helper() me, err := osuser.Current() if err != nil { t.Skip("no current user to own anything") } home = t.TempDir() given = map[string]string{} wasHome, wasOwn := homeOf, ownMade homeOf = func(name string) (string, error) { if name == me.Username { return home, nil } return wasHome(name) } ownMade = func(path, owner string) error { given[path] = owner return wasOwn(path, owner) } t.Cleanup(func() { homeOf, ownMade = wasHome, wasOwn }) return home, me.Username, given } func givenPaths(given map[string]string) []string { var paths []string for p := range given { paths = append(paths, p) } sort.Strings(paths) return paths } func TestAFileUnderAHomeGivesTheParentsItMadeToItsOwner(t *testing.T) { home, owner, given := aHome(t) target := filepath.Join(home, ".config", "mesh", "environment.sh") d := parse(t, `{"declaration":1,"resources":[{"id":"shell.env","type":"file","path":"`+target+ `","content":"export A=1\n","owner":"`+owner+`"}]}`) if _, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil); err != nil { t.Fatal(err) } want := []string{filepath.Join(home, ".config"), filepath.Join(home, ".config", "mesh")} if got := givenPaths(given); strings.Join(got, ",") != strings.Join(want, ",") { t.Errorf("given to the owner: %v, want %v", got, want) } for _, p := range want { if given[p] != owner { t.Errorf("%s given to %q", p, given[p]) } } } func TestAnArchiveUnderAHomeGivesTheParentsItMadeToItsOwner(t *testing.T) { home, owner, given := aHome(t) body, digest := anArchive(t, map[string]string{"p10k.zsh": "theme"}) target := filepath.Join(home, ".local", "share", "powerlevel10k") d := declare(t, `{"id":"shell.theme","type":"archive","source":"`+serving(t, body)+ `","digest":"`+digest+`","path":"`+target+`","owner":"`+owner+`"}`) if _, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil); err != nil { t.Fatal(err) } for _, p := range []string{filepath.Join(home, ".local"), filepath.Join(home, ".local", "share")} { if given[p] != owner { t.Errorf("%s, made by the host, was not given to the owner: %v", p, givenPaths(given)) } } } func TestAParentThatWasThereIsHeldAsFound(t *testing.T) { home, owner, given := aHome(t) config := filepath.Join(home, ".config") if err := os.Mkdir(config, 0o700); err != nil { t.Fatal(err) } target := filepath.Join(config, "mesh", "environment.sh") d := parse(t, `{"declaration":1,"resources":[{"id":"shell.env","type":"file","path":"`+target+ `","content":"export A=1\n","owner":"`+owner+`"}]}`) if _, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil); err != nil { t.Fatal(err) } if _, touched := given[config]; touched { t.Error("a parent that was already there was given to the owner") } if info, _ := os.Stat(config); info.Mode().Perm() != 0o700 { t.Errorf("a parent that was already there changed mode: %o", info.Mode().Perm()) } if given[filepath.Join(config, "mesh")] != owner { t.Errorf("the parent the host made was not given to the owner: %v", givenPaths(given)) } } func TestAParentOutsideTheHomeIsMadeAsBefore(t *testing.T) { _, owner, given := aHome(t) target := filepath.Join(t.TempDir(), "var", "lib", "module", "settings.conf") d := parse(t, `{"declaration":1,"resources":[{"id":"module.conf","type":"file","path":"`+target+ `","content":"a=1\n","owner":"`+owner+`"}]}`) if _, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginDeclared, noServices, nil, nil); err != nil { t.Fatal(err) } if len(given) != 0 { t.Errorf("parents outside the owner's home were given to it: %v", givenPaths(given)) } }