Take a root-made directory in the mesh's own tree, and hold a container until the file it mounts exists (issue 1873) #131
@@ -1482,6 +1482,9 @@ func applyDirectory(r *declaration.Directory, previous store.Applied, wasBefore
|
||||
}
|
||||
if existed && wasBefore {
|
||||
ours := previous.Target != "" && filepath.Clean(previous.Target) == filepath.Clean(r.Path) && !previous.AsFound
|
||||
// In the mesh's own tree, a directory the engine's own account owns was made by the mesh, on the way to
|
||||
// something below it or by an earlier apply that did not record it: it is the mesh's (novox/hq issue 1873).
|
||||
ours = ours || madeInTheMeshsTree(r.Path, before)
|
||||
if !ours {
|
||||
owned, err := ownedBy(r.Path, r.Owner)
|
||||
if err != nil {
|
||||
@@ -1557,6 +1560,18 @@ func applyDirectory(r *declaration.Directory, previous store.Applied, wasBefore
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// madeInTheMeshsTree is whether a directory lies in the mesh's own tree (meshDataRoot, below it, never the root
|
||||
// itself) and belongs to the engine's own account: only that account makes a directory there, so it is the mesh's
|
||||
// and not found (novox/hq issue 1873). Anywhere else, or owned by any other account, issue 339's rule stands.
|
||||
func madeInTheMeshsTree(path string, found os.FileInfo) bool {
|
||||
root := filepath.Clean(meshDataRoot)
|
||||
if !strings.HasPrefix(filepath.Clean(path), root+string(filepath.Separator)) {
|
||||
return false
|
||||
}
|
||||
uid, _, ok := ownerOf(found)
|
||||
return ok && uid == os.Geteuid()
|
||||
}
|
||||
|
||||
// applyHandedOver gives a directory the operator handed to the mesh its declared mode and owner (novox/hq issue
|
||||
// 356). **No link, checked again at the moment of use**: the hand-over refused a link when it was recorded, and a
|
||||
// component of the path may have become one since — a parent swapped for a link to /etc would carry root's chmod
|
||||
|
||||
@@ -124,3 +124,8 @@ func JudgeDirectories(d *declaration.Declaration) string {
|
||||
placed+refused+guarded+homed, placed, refused, guarded, homed)
|
||||
return strings.Join(append([]string{head}, lines...), "\n")
|
||||
}
|
||||
|
||||
// meshDataRoot is the mesh's own tree, where a module placed "mesh" keeps its directory (<data root>/mesh/<module>):
|
||||
// the engine's, 0755, so only the engine's account makes a directory in it (novox/hq issue 1873). A variable so a
|
||||
// test can place it.
|
||||
var meshDataRoot = "/var/lib/mesh"
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user