A root-only link inside /var/lib/mesh pointing out of it would have made a directory outside the tree, owned by the engine's account, the mesh's to give away: the fault of issue 1873 again. The path and the tree's root are now both resolved, links followed, and the directory is the tree's only when the resolved path lies below the resolved root as well.
101 lines
4.0 KiB
Go
101 lines
4.0 KiB
Go
//go:build linux
|
|
|
|
package apply
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/declaration"
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// novox/hq issue 1873: a module's directory in the mesh's own tree (<data root>/mesh/<module>, place "mesh") that is
|
|
// there before its declaration, owned by the engine's own account, was made by the mesh on the way to something below
|
|
// it: it is the mesh's, given its declared mode and owner, never used as found. Only the engine's account makes a
|
|
// directory in a tree that is the engine's (0755, root); on ace and novox /var/lib/mesh/postgres was there as
|
|
// root:root 0700 before postgres's data directory was applied, and the engine left it to root, so the postgres
|
|
// provider, running as the operator's account, could not reach its own files.
|
|
func TestADirectoryInTheMeshsOwnTreeMadeByTheEngineIsTheMeshs(t *testing.T) {
|
|
root := t.TempDir()
|
|
before := meshDataRoot
|
|
meshDataRoot = filepath.Join(root, "mesh")
|
|
t.Cleanup(func() { meshDataRoot = before })
|
|
made := filepath.Join(meshDataRoot, "postgres")
|
|
if err := os.MkdirAll(made, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Chmod(made, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
decl := `{"id":"postgres.data","type":"directory","path":"` + made + `","mode":"0750"}`
|
|
var said []string
|
|
_, state, err := Apply(context.Background(), archHost(t), declare(t, decl), store.State{}, store.OriginDeclared,
|
|
noServices, func(line string) { said = append(said, line) }, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Contains(strings.Join(said, "\n"), "WARNING postgres.data") {
|
|
t.Errorf("a directory the engine's account made in the mesh's tree was used as found: %q", said)
|
|
}
|
|
if a, _ := state.Find("postgres.data"); a.AsFound {
|
|
t.Error("it is recorded as found")
|
|
}
|
|
if info, _ := os.Stat(made); info.Mode().Perm() != 0o750 {
|
|
t.Errorf("it was not given its declared mode: %04o", info.Mode().Perm())
|
|
}
|
|
|
|
// Outside the mesh's tree the rule of issue 339 stands: found, used as found.
|
|
other := filepath.Join(root, "var-lib", "notes")
|
|
if err := os.MkdirAll(other, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
said = nil
|
|
decl = `{"id":"notes.data","type":"directory","path":"` + other + `","mode":"0750"}`
|
|
if _, _, err := Apply(context.Background(), archHost(t), declare(t, decl), store.State{}, store.OriginDeclared,
|
|
noServices, func(line string) { said = append(said, line) }, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(strings.Join(said, "\n"), "WARNING notes.data") {
|
|
t.Errorf("a directory found outside the mesh's tree was not used as found: %q", said)
|
|
}
|
|
}
|
|
|
|
// Review of issue 1873's fix: the tree is judged by where the path leads, not by its text. A root-only link inside the
|
|
// mesh's tree pointing out of it (to /var/lib/systemd, say) would otherwise make a directory outside the tree, owned by
|
|
// the engine's account, the mesh's to chown: issue 1873's fault again. It is used as found.
|
|
func TestALinkInTheMeshsTreeLeadingOutOfItIsNotTheTree(t *testing.T) {
|
|
rootAlone(t, "")
|
|
root := t.TempDir()
|
|
before := meshDataRoot
|
|
meshDataRoot = filepath.Join(root, "mesh")
|
|
t.Cleanup(func() { meshDataRoot = before })
|
|
outside := filepath.Join(root, "var-lib", "systemd")
|
|
if err := os.MkdirAll(filepath.Join(outside, "data"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Chmod(filepath.Join(outside, "data"), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.MkdirAll(meshDataRoot, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(outside, filepath.Join(meshDataRoot, "postgres")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r := &declaration.Directory{ID: "postgres.data", Path: filepath.Join(meshDataRoot, "postgres", "data"), Mode: "0750"}
|
|
out, err := applyDirectory(r, store.Applied{}, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !out.asFound {
|
|
t.Errorf("a directory reached through a link out of the mesh's tree was taken as the mesh's: %+v", out)
|
|
}
|
|
if got := permOf(t, filepath.Join(outside, "data")); got != 0o700 {
|
|
t.Errorf("the directory outside the tree was given mode %o (was 700)", got)
|
|
}
|
|
}
|