A file or archive placed under a fresh account's home with an owner left the parents it created, such as ~/.config or ~/.local/share, owned by root, so the person's own programs could not write there. Parents that already existed, and any outside the owner's home, are left as before.
127 lines
4.4 KiB
Go
127 lines
4.4 KiB
Go
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))
|
|
}
|
|
}
|