A module's places setting can move a directory anywhere, and the engine chowned whatever it was pointed at as root: a directory at /etc owned by the agent account would hand it /etc (hq ADR 0266). Refuse the machine's roots, the kernel's and the engine's trees, another account's home, and an archive or written-into file below an agent's home; and leave the owner and mode of a directory the mesh did not make.
142 lines
6.7 KiB
Go
142 lines
6.7 KiB
Go
package apply
|
|
|
|
// Defends novox/hq ADR 0266 (the third review): the engine places nothing at one of the machine's own
|
|
// directories, in the kernel's or its own trees, below a home for another account, or — for an archive or a
|
|
// file written into — below an agent's home; and a directory it did not make is used as found.
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/declaration"
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
func withHomes(t *testing.T, homes map[string]homeAccount) {
|
|
t.Helper()
|
|
was := accountsOfHomes
|
|
accountsOfHomes = func() map[string]homeAccount { return homes }
|
|
t.Cleanup(func() { accountsOfHomes = was })
|
|
}
|
|
|
|
func TestAMachinesOwnDirectoryIsNeverPlaced(t *testing.T) {
|
|
withHomes(t, nil)
|
|
for _, path := range []string{"/", "/etc", "/etc/", "/usr", "/var/lib", "/var/lib/mesh", "/home", "/root", "/run"} {
|
|
err := refusePlacement(&declaration.Directory{ID: "m.d", Type: declaration.TypeDirectory, Path: path, Owner: "agent"}, nil)
|
|
var refused *PlacementRefusedError
|
|
if !errors.As(err, &refused) {
|
|
t.Errorf("%s as a directory: refused, got %v", path, err)
|
|
}
|
|
}
|
|
for _, path := range []string{"/etc/sudoers.d/x", "/var/lib/mesh/daemons", "/var/lib/postgres", "/usr/local/bin/claude-agent"} {
|
|
if err := refusePlacement(&declaration.Directory{ID: "m.d", Type: declaration.TypeDirectory, Path: path}, nil); err != nil {
|
|
t.Errorf("%s: a module's own place below a root passes, got %v", path, err)
|
|
}
|
|
}
|
|
for _, path := range []string{"/proc/sys/x", "/sys/x", "/dev/x", "/boot/x", "/var/lib/mesh-host/state.json", "/var/lib/mesh-host"} {
|
|
if err := refusePlacement(&declaration.File{ID: "m.f", Type: declaration.TypeFile, Path: path, Content: "x"}, nil); err == nil {
|
|
t.Errorf("%s: nothing is placed there", path)
|
|
}
|
|
}
|
|
if err := refusePlacement(&declaration.File{ID: "mesh-host.launcher", Type: declaration.TypeFile,
|
|
Path: "/usr/lib/nox-mesh-host/launch", Content: "x"}, nil); err != nil {
|
|
t.Errorf("the engine's own module places its builds: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestBelowAHomeOnlyThatAccountsFilesArePlaced(t *testing.T) {
|
|
withHomes(t, map[string]homeAccount{"/home/operator": {"operator", 1000}, "/home/agent": {"agent", 1001}})
|
|
cases := []struct {
|
|
r declaration.Resource
|
|
ok bool
|
|
}{
|
|
{&declaration.Directory{ID: "a.d", Type: declaration.TypeDirectory, Path: "/home/agent/.claude", Owner: "agent"}, true},
|
|
{&declaration.Directory{ID: "a.d", Type: declaration.TypeDirectory, Path: "/home/agent/.claude", Owner: "1001:1001"}, true},
|
|
{&declaration.Directory{ID: "a.d", Type: declaration.TypeDirectory, Path: "/home/agent/.claude"}, false},
|
|
{&declaration.Directory{ID: "a.d", Type: declaration.TypeDirectory, Path: "/home/agent/.claude", Owner: "operator"}, false},
|
|
{&declaration.Directory{ID: "a.d", Type: declaration.TypeDirectory, Path: "/home/agent", Owner: "agent"}, false},
|
|
{&declaration.File{ID: "a.f", Type: declaration.TypeFile, Path: "/home/operator/.zshrc", Owner: "operator", Content: "x"}, true},
|
|
}
|
|
for _, c := range cases {
|
|
if err := refusePlacement(c.r, nil); (err == nil) != c.ok {
|
|
t.Errorf("%s owned by %q: ok %v, got %v", c.r.Target(), ownerName(c.r), c.ok, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNothingIsUnpackedOrWrittenIntoBelowAnAgentsHome(t *testing.T) {
|
|
withHomes(t, map[string]homeAccount{"/home/agent": {"agent", 1001}})
|
|
agent := []string{"/home/agent"}
|
|
if err := refusePlacement(&declaration.Archive{ID: "a.x", Type: declaration.TypeArchive, Path: "/home/agent/.local/x", Owner: "agent"}, agent); err == nil {
|
|
t.Error("an archive below an agent's home is refused")
|
|
}
|
|
if err := refusePlacement(&declaration.File{ID: "a.f", Type: declaration.TypeFile, Path: "/home/agent/.claude.json", Owner: "agent", Into: "json", Content: "{}"}, agent); err == nil {
|
|
t.Error("a file written into below an agent's home is refused")
|
|
}
|
|
if err := refusePlacement(&declaration.File{ID: "a.f", Type: declaration.TypeFile, Path: "/home/agent/x", Owner: "agent", Content: "x"}, agent); err != nil {
|
|
t.Errorf("a whole file there passes: %v", err)
|
|
}
|
|
d := parse(t, `{"declaration":1,"resources":[{"id":"c.agent","type":"user","name":"agent","root":"never"},`+
|
|
`{"id":"c.op","type":"user","name":"operator"}]}`)
|
|
if got := rootNeverHomes(d); len(got) != 1 || got[0] != "/home/agent" {
|
|
t.Errorf("the agent's home is known by the user database: %v", got)
|
|
}
|
|
}
|
|
|
|
func TestADirectoryAtEtcIsRefusedThroughTheApplyAndNothingIsTouched(t *testing.T) {
|
|
withHomes(t, nil)
|
|
l := &logins{shells: map[string]string{}}
|
|
report, _, err := Apply(context.Background(), archHost(t), parse(t,
|
|
`{"declaration":1,"resources":[{"id":"m.state","type":"directory","path":"/etc","owner":"agent","mode":"0755"}]}`),
|
|
store.State{}, store.OriginDeclared, l.run, nil, nil)
|
|
if err == nil || !strings.Contains(err.Error(), "machine's own directories") {
|
|
t.Fatalf("refused: %v %+v", err, report)
|
|
}
|
|
}
|
|
|
|
func TestADirectoryFoundHereIsUsedAsFound(t *testing.T) {
|
|
dir := filepath.Join(t.TempDir(), "found")
|
|
if err := os.Mkdir(dir, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r := &declaration.Directory{ID: "m.d", Type: declaration.TypeDirectory, Path: dir, Mode: "0755"}
|
|
out, err := applyDirectory(r, store.Applied{}, true)
|
|
if err != nil || !out.asFound || !strings.Contains(out.Detail, "used as found") {
|
|
t.Fatalf("a found directory is used as found: %+v %v", out, err)
|
|
}
|
|
if info, _ := os.Stat(dir); info.Mode().Perm() != 0o700 {
|
|
t.Fatalf("its mode was changed: %o", info.Mode().Perm())
|
|
}
|
|
// Recorded as found, it stays found.
|
|
out, _ = applyDirectory(r, store.Applied{ID: "m.d", Target: dir, AsFound: true}, true)
|
|
if !out.asFound {
|
|
t.Fatal("a directory recorded as found stays found")
|
|
}
|
|
// The mesh's by its record from an earlier apply: converged as before.
|
|
out, err = applyDirectory(r, store.Applied{ID: "m.d", Target: dir}, true)
|
|
if err != nil || out.asFound {
|
|
t.Fatalf("a directory the mesh applied before is converged: %+v %v", out, err)
|
|
}
|
|
if info, _ := os.Stat(dir); info.Mode().Perm() != 0o755 {
|
|
t.Fatalf("not converged: %o", info.Mode().Perm())
|
|
}
|
|
// Already as declared: the mesh's from here on.
|
|
other := filepath.Join(t.TempDir(), "same")
|
|
if err := os.Mkdir(other, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out, _ := applyDirectory(&declaration.Directory{ID: "m.e", Type: declaration.TypeDirectory, Path: other, Mode: "0755"}, store.Applied{}, true); out.asFound {
|
|
t.Fatal("a found directory already as declared is the mesh's")
|
|
}
|
|
if action, _, err := remove(context.Background(), nil, store.Applied{Type: "directory", Target: dir, AsFound: true}, nil, nil); err != nil || action != "forgotten" {
|
|
t.Fatalf("a directory used as found is never removed: %s %v", action, err)
|
|
}
|
|
if _, err := os.Stat(dir); err != nil {
|
|
t.Fatal("it is still there")
|
|
}
|
|
}
|