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.
96 lines
3.7 KiB
Go
96 lines
3.7 KiB
Go
//go:build linux
|
|
|
|
package apply
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// Review 47 of novox/hq issue 358: a directory the walk refuses gates its module, and nothing below it is written,
|
|
// whether the link was there when the apply began or appeared while it ran.
|
|
|
|
// aLinkedModule is a module's directory at <base>/parent/state, its parent a link to <base>/elsewhere, and a file of
|
|
// the module below the directory; and another module's file elsewhere.
|
|
func aLinkedModule(t *testing.T) (target, other, decl string) {
|
|
t.Helper()
|
|
base := t.TempDir()
|
|
target = filepath.Join(base, "elsewhere", "state")
|
|
if err := os.MkdirAll(target, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(filepath.Join(base, "elsewhere"), filepath.Join(base, "parent")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir := filepath.Join(base, "parent", "state")
|
|
other = filepath.Join(base, "other.conf")
|
|
decl = `{"id":"mod.state","type":"directory","path":"` + dir + `","mode":"0700"},` +
|
|
`{"id":"mod.conf","type":"file","path":"` + dir + `/settings.conf","content":"a=1\n"},` +
|
|
`{"id":"other.conf","type":"file","path":"` + other + `","content":"kept apart\n"}`
|
|
return target, other, decl
|
|
}
|
|
|
|
func holdsTheGate(t *testing.T, target, other string, report Report, err error) {
|
|
t.Helper()
|
|
var refusal *PlacementRefusedError
|
|
if !errors.As(err, &refusal) {
|
|
t.Fatalf("the directory behind the link was not refused: %v", err)
|
|
}
|
|
if _, statErr := os.Stat(filepath.Join(target, "settings.conf")); statErr == nil {
|
|
t.Error("a file was written into the link's target, below the directory the engine refused")
|
|
}
|
|
if info, _ := os.Stat(target); info.Mode().Perm() != 0o755 {
|
|
t.Errorf("the link's target was given mode %o (was 755)", info.Mode().Perm())
|
|
}
|
|
if o := outcomeOf(report, "mod.conf"); o.Action != "skipped" {
|
|
t.Errorf("the file below the refused directory is not reported skipped: %+v", o)
|
|
}
|
|
if strings.Contains(err.Error(), "everything was attempted") || !strings.Contains(err.Error(), "the rest of mod was not attempted") {
|
|
t.Errorf("the report does not say the module was gated: %v", err)
|
|
}
|
|
if got, readErr := os.ReadFile(other); readErr != nil || string(got) != "kept apart\n" {
|
|
t.Errorf("another module's file was not applied: %q, %v", got, readErr)
|
|
}
|
|
}
|
|
|
|
// The link there when the apply begins: refused by the guard before anything is applied.
|
|
func TestADirectoryBehindALinkGatesItsModuleThroughApply(t *testing.T) {
|
|
target, other, decl := aLinkedModule(t)
|
|
report, _, err := Apply(context.Background(), archHost(t), declare(t, decl), store.State{}, store.OriginDeclared,
|
|
noServices, nil, nil)
|
|
holdsTheGate(t, target, other, report, err)
|
|
}
|
|
|
|
// The link found only at the moment of use: refused by the walk during the apply, and still a refusal that gates its
|
|
// module and what is below it. Simulated by trusting / for the guard's walk (two walks of /: one to the link, one
|
|
// from its target) and not for the apply's.
|
|
func TestADirectoryRefusedDuringTheApplyGatesItsModule(t *testing.T) {
|
|
target, other, decl := aLinkedModule(t)
|
|
wasDirs, wasLinks := couldReplace, linkReplacer
|
|
walksOfRoot := 0
|
|
couldReplace = func(path string, _, _, _ uint32) string {
|
|
if path == "/" {
|
|
walksOfRoot++
|
|
if walksOfRoot > 2 {
|
|
return "every account (a test's /)"
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
linkReplacer = func(string, uint32) string { return "" }
|
|
t.Cleanup(func() { couldReplace, linkReplacer = wasDirs, wasLinks })
|
|
|
|
report, _, err := Apply(context.Background(), archHost(t), declare(t, decl), store.State{}, store.OriginDeclared,
|
|
noServices, nil, nil)
|
|
if walksOfRoot < 3 {
|
|
t.Fatalf("the apply did not walk again at the moment of use (%d walks)", walksOfRoot)
|
|
}
|
|
holdsTheGate(t, target, other, report, err)
|
|
}
|