Test uncovered launch-dir refusals #4

Merged
benvin merged 1 commits from benvin/launch-dir-tests into main 2026-10-25 01:08:03 +11:00
+79
View File
@@ -681,3 +681,82 @@ func TestLaunchMountsResolvedSource(t *testing.T) {
}
}
}
func TestCheckLaunchDirDefaultRootForbidden(t *testing.T) {
t.Setenv("HOME", "/tmp/home")
t.Setenv("XDG_CONFIG_HOME", "/nonexistent/cfg")
t.Setenv("XDG_DATA_HOME", "")
t.Setenv("XDG_RUNTIME_DIR", "/nonexistent/rt")
t.Setenv("PATH", "/usr/bin")
_, err := checkLaunchDir("/tmp/home/proj", "/nonexistent/hosts")
check(t, "forbidden default root", "refusing to mount /tmp/home/proj: it overlaps "+realpath("/tmp"), fmt.Sprint(err))
}
// isolatedHome points every sensitive dir outside a fresh $HOME, leaving only
// the rule under test to refuse.
func isolatedHome(t *testing.T) (work, home string) {
work, _ = filepath.EvalSymlinks(t.TempDir())
elsewhere, _ := filepath.EvalSymlinks(t.TempDir())
home = work + "/home"
for _, d := range []string{".ssh", ".gnupg", ".config", ".local/share/containers"} {
_ = os.MkdirAll(filepath.Join(elsewhere, d), 0o755)
_ = os.MkdirAll(filepath.Dir(filepath.Join(home, d)), 0o755)
_ = os.Symlink(filepath.Join(elsewhere, d), filepath.Join(home, d))
}
t.Setenv("HOME", home)
t.Setenv("XDG_CONFIG_HOME", elsewhere+"/cfg")
t.Setenv("XDG_DATA_HOME", "")
t.Setenv("XDG_RUNTIME_DIR", elsewhere+"/rt")
t.Setenv("PATH", "/usr/bin")
origRoots := forbiddenRoots
forbiddenRoots = []string{"/run"}
t.Cleanup(func() { forbiddenRoots = origRoots })
_ = os.MkdirAll(filepath.Dir(allowedPathsFile()), 0o755)
return work, home
}
func TestCheckLaunchDirResolvedAllowedPathsDir(t *testing.T) {
_, home := isolatedHome(t)
dot := home + "/src/dot"
_ = os.MkdirAll(dot, 0o755)
_ = os.WriteFile(dot+"/allowed-paths", []byte("~/src\n"), 0o644)
_ = os.Symlink(dot+"/allowed-paths", allowedPathsFile())
_ = os.MkdirAll(home+"/src/other", 0o755)
_, err := checkLaunchDir(home+"/src/other", "/nonexistent/hosts")
check(t, "sibling allowed", nil, err)
_, err = checkLaunchDir(dot, "/nonexistent/hosts")
check(t, "resolved allowed-paths dir", "refusing to mount "+dot+": it contains "+dot, fmt.Sprint(err))
}
func TestAllowedRootsRejectsHomeAndDotDirs(t *testing.T) {
work, home := isolatedHome(t)
f := allowedPathsFile()
for _, tc := range []struct{ root, want string }{
{"~/.cache", `"~/.cache" is a dot-directory of $HOME`},
{"~", `"~" is or contains $HOME`},
{home, `"` + home + `" is or contains $HOME`},
{work, `"` + work + `" is or contains $HOME`},
} {
_ = os.WriteFile(f, []byte(tc.root+"\n"), 0o644)
_, _, err := allowedRoots(home)
check(t, tc.root, f+": "+tc.want, fmt.Sprint(err))
}
_ = os.WriteFile(f, []byte("~/src\n"), 0o644)
_, _, err := allowedRoots(home)
check(t, "plain root", nil, err)
}
func TestLaunchRefusesColonInResolvedSource(t *testing.T) {
e := setup(t)
_ = os.Mkdir(e.work+"/home/a:b", 0o755)
_ = os.Symlink(e.work+"/home/a:b", e.work+"/home/link")
stderr, _ := os.CreateTemp(t.TempDir(), "stderr")
orig := os.Stderr
os.Stderr = stderr
code := e.launch(t, e.work+"/home/link", "--exec", "true")
os.Stderr = orig
out, _ := os.ReadFile(stderr.Name())
check(t, "exit", 1, code)
check(t, "stderr", "agent-sandbox: cannot mount a directory containing ':'\n", string(out))
check(t, "podman calls", []string(nil), e.fake.calls)
}