Files
mesh-host/internal/apply/placement_homes_test.go
T
jochen 3a002f6e7b
mesh/merge-gate pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check fail: its merge-check.sh failed: --- FAIL: TestBelowAHomeOnlyThatAccountsDirectoryIsPlaced (0.00s)
mesh/delivery superseded: a newer head of the same pull request
Refuse a placement or mount at the machine's own trees, and use a found directory as found
A module's places setting could point a directory anywhere, with an owner it
named, and the engine chowned and chmodded whatever it was pointed at as root,
through a link too; its accesses setting could mount any path into a container
(hq issue 339). The engine now refuses, as a failed resource with its reason,
a directory, access or mount source that is or holds one of the machine's
roots, anything placed in the kernel's, the boot loader's, root's or the
engine's own trees, a non-root directory below /etc, /usr or /run, an access
there, another account's directory below a home, and a container mounting
anything it refused, judged with every link resolved. A directory whose last
component is a link is refused, and one found here that the mesh did not make
keeps its owner and mode and is never removed.
2026-10-08 23:58:14 +02:00

68 lines
2.5 KiB
Go

package apply
import (
"context"
"fmt"
"os"
"path/filepath"
"strconv"
"testing"
"github.com/novox/mesh-host/internal/store"
)
// Below a person's or an agent's home, a directory is that account's (novox/hq issue 339): root's, or another
// account's, there is one the account does not control in a tree whose every parent it does — and a container
// mounting one the engine refused is refused with it.
func TestBelowAHomeOnlyThatAccountsDirectoryIsPlaced(t *testing.T) {
dir := t.TempDir()
home := filepath.Join(dir, "home", "alice")
if err := os.MkdirAll(home, 0o755); err != nil {
t.Fatal(err)
}
me := os.Getuid()
passwd := filepath.Join(dir, "passwd")
if err := os.WriteFile(passwd, fmt.Appendf(nil, "root:x:0:0::/root:/bin/sh\nalice:x:%d:%d::%s:/bin/sh\n",
me, os.Getgid(), home), 0o644); err != nil {
t.Fatal(err)
}
before := passwdFile
passwdFile = passwd
t.Cleanup(func() { passwdFile = before })
_, _, err := applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+home+`/.config/autostart"}`, nil, store.State{})
refusedFor339(t, "root's directory below alice's home", err)
_, _, err = applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+home+`/.config/autostart",`+
`"owner":"`+strconv.Itoa(me+1)+`"}`, nil, store.State{})
refusedFor339(t, "another account's directory below alice's home", err)
if _, err := os.Stat(filepath.Join(home, ".config")); err == nil {
t.Fatal("a refused directory's parent was made")
}
// Alice's own is placed.
if _, _, err := applyOnce(t, `{"id":"notes.data","type":"directory","path":"`+home+`/.config/notes",`+
`"owner":"`+strconv.Itoa(me)+":"+strconv.Itoa(os.Getgid())+`"}`, nil, store.State{}); err != nil {
t.Fatalf("alice's own directory: %v", err)
}
// A container mounting a refused directory is refused with it, and not run.
ran := false
run := func(ctx context.Context, name string, args ...string) (string, error) {
switch args[0] {
case "info":
return "27.0\n", nil
case "container":
return "", os.ErrNotExist
case "run":
ran = true
}
return "", nil
}
_, _, err = Apply(context.Background(), archHost(t), parseTrusted(t, `{"declaration":1,"resources":[
{"id":"notes.data","type":"directory","path":"`+home+`/.ssh"},
{"id":"notes.server","type":"container","name":"notes","image":"`+pinned+`","volumes":["`+home+`/.ssh:/keys"]}
]}`), store.State{}, store.OriginCarried, run, nil, nil)
refusedFor339(t, "a container mounting a refused directory", err)
if ran {
t.Fatal("a container mounting a refused directory was run")
}
}