package apply import ( "os" "path/filepath" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/declaration" ) // A module that declares its own system account and a .ssh in that account's home is placed (novox/hq issue 1542): // the account is not in the user database yet when the declaration is judged, and its home is under /var/lib. func declaredHomeFixture(t *testing.T) (home string, user *declaration.User) { t.Helper() dir := t.TempDir() passwd := filepath.Join(dir, "passwd") if err := os.WriteFile(passwd, []byte("root:x:0:0::/root:/bin/sh\n"), 0o644); err != nil { t.Fatal(err) } before := passwdFile passwdFile = passwd t.Cleanup(func() { passwdFile = before }) home = filepath.Join(dir, "lib", "mesh-build-go") return home, &declaration.User{ID: "mesh-build-go.account", Type: declaration.TypeUser, Name: "mesh-build-go", Shell: "/usr/bin/nologin", Home: home} } // 1542/AC1: the .ssh of a declared account, owned by it, is refused by nothing. func TestIssue1542ADeclaredAccountsSSHIsPlaced(t *testing.T) { home, user := declaredHomeFixture(t) ssh := &declaration.Directory{ID: "mesh-build-go.ssh-dir", Type: declaration.TypeDirectory, Path: home + "/.ssh", Mode: "0700", Owner: "mesh-build-go"} refused := refusedPlaces([]declaration.Resource{user, ssh}) if len(refused) != 0 { t.Fatalf("a declared account's own .ssh was refused: %v", refused) } if err := (inputs{refused: refused}).refused[filepath.Clean(ssh.Path)]; err != nil { t.Fatalf("the apply-time check refuses it: %v", err) } if line := JudgeDirectories(&declaration.Declaration{Resources: []declaration.Resource{user, ssh}}); strings.Contains(line, "refused already by the placement guard: ") { t.Fatalf("the read-only judgement refuses it: %s", line) } } // 1542/AC2: another account's directory below the declared home is refused as below any home, and a .ssh below // no home of the machine or the declaration is refused with today's words. func TestIssue1542OnlyTheDeclaredAccountsOwnIsPlaced(t *testing.T) { home, user := declaredHomeFixture(t) other := &declaration.Directory{ID: "notes.ssh-dir", Type: declaration.TypeDirectory, Path: home + "/.ssh", Mode: "0700", Owner: "intruder"} refused := refusedPlaces([]declaration.Resource{user, other}) err := refused[filepath.Clean(other.Path)] if err == nil || !strings.Contains(err.Error(), "below mesh-build-go's home and declared intruder's") { t.Fatalf("another account's directory below a declared home: %v", err) } stray := &declaration.Directory{ID: "mesh-build-go.ssh-dir", Type: declaration.TypeDirectory, Path: filepath.Join(filepath.Dir(home), "elsewhere", ".ssh"), Mode: "0700", Owner: "mesh-build-go"} refused = refusedPlaces([]declaration.Resource{user, stray}) err = refused[filepath.Clean(stray.Path)] if err == nil || !strings.Contains(err.Error(), "a .ssh directory is placed only below its account's home, as that account's") { t.Fatalf("a .ssh below no home: %v", err) } // Not a .ssh: a root-owned directory below the declared home is placed exactly as on main. data := &declaration.Directory{ID: "mesh-build-go.data", Type: declaration.TypeDirectory, Path: home + "/data", Mode: "0755", Owner: "root"} if refused := refusedPlaces([]declaration.Resource{user, data}); len(refused) != 0 { t.Fatalf("a root-owned directory below a declared home, not a .ssh, was refused: %v", refused) } // And without the account declared, the same .ssh is refused as it was. own := &declaration.Directory{ID: "mesh-build-go.ssh-dir", Type: declaration.TypeDirectory, Path: home + "/.ssh", Mode: "0700", Owner: "mesh-build-go"} if refusedPlaces([]declaration.Resource{own})[filepath.Clean(own.Path)] == nil { t.Fatal("a .ssh below an account nobody makes was placed") } } // 1542/AC3: a declared account is no home to anyone but the directory placement guard. func TestIssue1542DeclaredAccountsAreNotHomesToTheOtherGuards(t *testing.T) { home, user := declaredHomeFixture(t) _ = refusedPlaces([]declaration.Resource{user}) if _, ok := accountsOfHomes()[home]; ok { t.Fatal("a declared account became a home of the machine") } if homeAbove(home+"/.ssh") != "" { t.Fatal("a declared account became a home for the links and the move-out") } }