A mesh directory outside every home was chmodded and chowned by path, so a parent turned into a link between two applies carried root's chmod and chown to the link's target. It is now made and changed through the descriptor of the walk from / that follows a link only root alone could have made. A directory that walk refuses is a refusal like the placement guard's (review 47): judged before anything is applied, and again when the directory is applied, used as found or not; refused at either point it gates its module and refuses what is below it, so no file is written into the link's target and the report does not say everything was attempted.
84 lines
3.0 KiB
Go
84 lines
3.0 KiB
Go
//go:build linux
|
|
|
|
package apply
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/declaration"
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// The replay of novox/hq issue 358, written only with what the node-engine had before its fix, so it can be laid
|
|
// over the commit before (mesh-lab's replays register): a mesh directory outside every home was given its mode
|
|
// and owner by path, so a parent swapped for a link between two applies carried root's chmod to the link's target.
|
|
|
|
// aMeshDirectory applies a directory declared at <base>/parent/state once, as the mesh's own, and answers it
|
|
// with the record a second apply would read.
|
|
func aMeshDirectory(t *testing.T) (base string, r *declaration.Directory, previous store.Applied) {
|
|
t.Helper()
|
|
base = t.TempDir()
|
|
r = &declaration.Directory{ID: "mod.state", Path: filepath.Join(base, "parent", "state"), Mode: "0700"}
|
|
out, err := applyDirectory(r, store.Applied{}, false)
|
|
if err != nil {
|
|
t.Fatalf("the first apply: %v", err)
|
|
}
|
|
if out.Action != "created" {
|
|
t.Fatalf("the first apply said %q, want created", out.Action)
|
|
}
|
|
return base, r, store.Applied{ID: r.ID, Type: "directory", Target: r.Path}
|
|
}
|
|
|
|
// swapParentForLink moves <base>/parent away and puts a link to elsewhere (as written) in its place, where
|
|
// elsewhere holds a directory state of mode 0755: what an account that can write <base> does between two applies.
|
|
func swapParentForLink(t *testing.T, base, to string) (target string) {
|
|
t.Helper()
|
|
elsewhere := filepath.Join(base, "elsewhere")
|
|
target = filepath.Join(elsewhere, "state")
|
|
if err := os.MkdirAll(target, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Chmod(target, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Rename(filepath.Join(base, "parent"), filepath.Join(base, "moved")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(to, filepath.Join(base, "parent")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return target
|
|
}
|
|
|
|
func permOf(t *testing.T, path string) os.FileMode {
|
|
t.Helper()
|
|
info, err := os.Lstat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return info.Mode().Perm()
|
|
}
|
|
|
|
// The acceptance of issue 358: a parent swapped for a link after an apply leaves the link's target untouched, and
|
|
// the refusal names the link and who could have made it.
|
|
func TestAParentSwappedForALinkLeavesItsTargetUntouched(t *testing.T) {
|
|
base, r, previous := aMeshDirectory(t)
|
|
target := swapParentForLink(t, base, filepath.Join(base, "elsewhere"))
|
|
|
|
_, err := applyDirectory(r, previous, true)
|
|
var refusal *PlacementRefusedError
|
|
if !errors.As(err, &refusal) {
|
|
t.Fatalf("the directory reached through a link was not refused: %v", err)
|
|
}
|
|
if !strings.Contains(err.Error(), filepath.Join(base, "parent")) || !strings.Contains(err.Error(), "could replace") {
|
|
t.Errorf("the refusal does not name the link and who could replace it: %v", err)
|
|
}
|
|
if got := permOf(t, target); got != 0o755 {
|
|
t.Errorf("the link's target was given mode %o (was 755): root's chmod followed the link", got)
|
|
}
|
|
}
|