Files
privatae-bastion/client-go/scripts_isolation_test.go
T
Privatae 48899b41a9
ci / personal-data (push) Successful in 4s
ci / test (push) Successful in 4m58s
ci / fuzz (push) Successful in 3m33s
bastion 0.63.1
2026-11-03 22:56:18 +00:00

82 lines
3.0 KiB
Go

package main
import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)
// Every script in scripts/ that starts a bastion in namespaces of its own
// hides ALL of /run and /tmp, never a chosen subdirectory of them, and refuses
// to go on while it can still see the machine's own bastion. A run that put a
// tmpfs over /run/privatae but not /run/privatae-bastion replaced a live
// bastion's ask.sock and context.sock on the machine running the tests.
//
// MUTATION: the e2e script's /run mount back to /run/privatae alone. RESULT: red.
// MUTATION: drop its guard for /run/privatae-bastion. RESULT: red.
// MUTATION: move the guard after the first start of the bastion. RESULT: red.
// MUTATION: drop the PID 1 check before the first mount. RESULT: red.
func TestNamespaceScriptsHideAllOfRunAndTmpAndRefuseToSeeTheLiveBastion(t *testing.T) {
paths, err := filepath.Glob(filepath.Join("..", "scripts", "*.sh"))
if err != nil {
t.Fatal(err)
}
n := 0
for _, p := range paths {
raw, err := os.ReadFile(p)
if err != nil {
t.Fatal(err)
}
s := string(raw)
if !strings.Contains(s, "unshare") {
continue
}
n++
name := filepath.Base(p)
lines := strings.Split(s, "\n")
at := func(re string) int {
r := regexp.MustCompile(re)
for i, l := range lines {
if strings.HasPrefix(strings.TrimSpace(l), "#") {
continue
}
if r.MatchString(l) {
return i
}
}
return -1
}
runAt := at(`mount -t tmpfs tmpfs /run\s*$`)
tmpAt := at(`mount -t tmpfs tmpfs /tmp\s*$`)
if runAt < 0 || tmpAt < 0 {
t.Errorf("%s: no tmpfs over all of /run (%d) and /tmp (%d)", name, runAt, tmpAt)
}
if i := at(`mount -t tmpfs tmpfs /(run|tmp)/`); i >= 0 && (runAt < 0 || i < runAt) {
t.Errorf("%s:%d hides a subdirectory of /run or /tmp instead of all of it: %s", name, i+1, lines[i])
}
guard := at(`/run/privatae-bastion`)
if guard < 0 || guard < runAt || guard < tmpAt {
t.Errorf("%s: no guard, after hiding /run and /tmp, that refuses to run while /run/privatae-bastion is visible", name)
}
if i := at(`"\$B"|privatae-bastion" (run|pair)|\$BAST`); i >= 0 && guard > i {
t.Errorf("%s:%d starts a bastion before the guard", name, i+1)
}
if at(`unshare .*--pid`) < 0 || at(`unshare .*--mount`) < 0 || at(`unshare .*--net`) < 0 {
t.Errorf("%s: a bastion runs in private PID, mount and network namespaces", name)
}
// The re-exec into the namespaces is chosen by an environment variable
// (E2E_INNER): one set by the caller skips the unshare, and every mount
// below then lands on this machine's own /run. So before any mount the
// script proves it is PID 1 of a namespace of its own.
pid1 := at(`\[ "?\$\$"? (=|-eq) "?1"? \]`)
if m := at(`^\s*(mount|mkdir -p [^;&]*&& mount) `); pid1 < 0 || (m >= 0 && pid1 > m) {
t.Errorf("%s: no check, before its first mount (line %d), that it runs as PID 1 of its own namespace (line %d)", name, m+1, pid1+1)
}
}
if n == 0 {
t.Fatal("no namespace script found: the glob is wrong")
}
}