package apply import ( "context" "os" "path/filepath" "strings" "testing" "time" "github.com/novox/mesh-host/internal/store" ) // A directory used as found is never quiet, and a person at the machine can hand it over (novox/hq issue 339). func TestAFoundDirectoryIsSaidAndCanBeHandedOver(t *testing.T) { dir := t.TempDir() found := filepath.Join(dir, "found") if err := os.Mkdir(found, 0o700); err != nil { t.Fatal(err) } decl := `{"id":"notes.data","type":"directory","path":"` + found + `","mode":"0755"}` var said []string log := func(line string) { said = append(said, line) } _, state, err := Apply(context.Background(), archHost(t), declare(t, decl), store.State{}, store.OriginDeclared, noServices, log, nil) if err != nil { t.Fatal(err) } if !strings.Contains(strings.Join(said, "\n"), "WARNING notes.data") { t.Fatalf("the apply did not warn of a directory used as found: %q", said) } if a, _ := state.Find("notes.data"); !a.AsFound || !strings.Contains(a.Declared, "755") { t.Fatalf("the record does not say what was declared: %+v", a) } // Said again at the next apply: a warning once is a warning missed. said = nil if _, state, err = Apply(context.Background(), archHost(t), declare(t, decl), state, store.OriginDeclared, noServices, log, nil); err != nil { t.Fatal(err) } if !strings.Contains(strings.Join(said, "\n"), "WARNING notes.data") { t.Fatalf("the next apply did not warn again: %q", said) } // Handed over: the next apply gives it the declared mode and it is the mesh's. before := HandedOver HandedOver = func() map[string]bool { return map[string]bool{handOverKey("notes.data", found): true} } t.Cleanup(func() { HandedOver = before }) if _, state, err = Apply(context.Background(), archHost(t), declare(t, decl), state, store.OriginDeclared, noServices, nil, nil); err != nil { t.Fatal(err) } if info, _ := os.Stat(found); info.Mode().Perm() != 0o755 { t.Fatalf("a directory handed over was not given its declared mode: %o", info.Mode().Perm()) } if a, _ := state.Find("notes.data"); a.AsFound { t.Fatal("a directory handed over is still recorded as found") } } // The review's additions to the guard: the spool, /opt, the container runtimes' data wherever the runtime keeps // it, and an account's .ssh as an access or a mount, or as a directory anywhere but its own home. func TestTheRuntimesDataAndAnySSHAreRefused(t *testing.T) { cfg := filepath.Join(t.TempDir(), "daemon.json") if err := os.WriteFile(cfg, []byte(`{"data-root":"/storage/docker"}`), 0o644); err != nil { t.Fatal(err) } before := runtimeConfigs runtimeConfigs = runtimeFiles{daemonJSON: cfg} t.Cleanup(func() { runtimeConfigs = before }) for _, kind := range []placing{placingDirectory, placingAccess, placingMount} { for _, path := range []string{"/var/spool/cron", "/opt/app", "/var/lib/docker/volumes/x", "/var/lib/containers/storage", "/storage/docker", "/storage/docker/overlay2"} { if err := refusePath(path, kind, "notes", ""); err == nil { t.Errorf("%v at %s was taken", kind, path) } } } for _, path := range []string{"/srv/backup/.ssh", "/srv/backup/.ssh/keys"} { for _, kind := range []placing{placingDirectory, placingAccess, placingMount} { if err := refusePath(path, kind, "notes", ""); err == nil { t.Errorf("%v at %s was taken", kind, path) } } } if err := refusePath("/storage/dockerish", placingAccess, "notes", ""); err != nil { t.Errorf("a path beside the data root: %v", err) } } // When a directory was found is kept from the first apply that found it (novox/hq issue 339): the controller // tells a directory a send found from one found before it by that time, so it must not move with every apply. func TestWhenADirectoryWasFoundIsKept(t *testing.T) { dir := t.TempDir() found := filepath.Join(dir, "found") if err := os.Mkdir(found, 0o700); err != nil { t.Fatal(err) } decl := `{"id":"notes.data","type":"directory","path":"` + found + `","mode":"0755"}` _, state, err := Apply(context.Background(), archHost(t), declare(t, decl), store.State{}, store.OriginDeclared, noServices, nil, nil) if err != nil { t.Fatal(err) } first, _ := state.Find("notes.data") if first.FoundAt.IsZero() { t.Fatal("no time the directory was found") } time.Sleep(10 * time.Millisecond) _, state, err = Apply(context.Background(), archHost(t), declare(t, decl), state, store.OriginDeclared, noServices, nil, nil) if err != nil { t.Fatal(err) } if again, _ := state.Find("notes.data"); !again.FoundAt.Equal(first.FoundAt) { t.Fatalf("found at %v, then %v: the time moved with the apply", first.FoundAt, again.FoundAt) } } // A hand-over is for the resource that was used as found there: another declaration that later points another // resource at the same path is not handed anything (novox/hq issue 339). func TestAHandOverIsForTheResourceThatAskedForIt(t *testing.T) { dir := t.TempDir() found := filepath.Join(dir, "found") if err := os.Mkdir(found, 0o700); err != nil { t.Fatal(err) } before := HandedOver HandedOver = func() map[string]bool { return map[string]bool{handOverKey("notes.data", found): true} } t.Cleanup(func() { HandedOver = before }) other := `{"id":"other.data","type":"directory","path":"` + found + `","mode":"0755"}` if _, _, err := Apply(context.Background(), archHost(t), declare(t, other), store.State{}, store.OriginDeclared, noServices, nil, nil); err != nil { t.Fatal(err) } if info, _ := os.Stat(found); info.Mode().Perm() != 0o700 { t.Fatalf("a hand-over for notes.data gave other.data the directory: mode %o", info.Mode().Perm()) } }