From a7383510fb05abc98b992240cb76ad4b6c598956 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 4 Oct 2026 01:05:10 +0900 Subject: test/sandbox: migrate tests This significantly improves performance, removing overhead of nix, python, and virtualisation. Running this in an unprivileged container required patching the kernel, but since special runner setup was already needed, that was an acceptable tradeoff. Signed-off-by: Ophestra --- test/sandbox/testdata/testdata.go | 125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 test/sandbox/testdata/testdata.go (limited to 'test/sandbox/testdata/testdata.go') diff --git a/test/sandbox/testdata/testdata.go b/test/sandbox/testdata/testdata.go new file mode 100644 index 00000000..3418d8ae --- /dev/null +++ b/test/sandbox/testdata/testdata.go @@ -0,0 +1,125 @@ +//go:build testsuite || tester + +// Package testdata holds sandbox inspection test cases. +package testdata + +import ( + "crypto/sha512" + "iter" + "log" + "strconv" + "syscall" + + "hakurei.app/check" + "hakurei.app/fhs" + "hakurei.app/hst" + "hakurei.app/test/internal/mountinfo" + "hakurei.app/test/internal/testsuite" +) + +// A TestCase represents a named test case that may be requested by the caller. +type TestCase struct { + // Configuration of the inspected container. + Hakurei hst.Config + // Checksum of expected seccomp filter program. + Sum [sha512.Size]byte + + // Expected environment. Skipped if nil. + Env []string `json:"env,omitempty"` + // Expected root filesystem. Skipped if nil. + FS *testsuite.FS `json:"fs,omitempty"` + // Expected mountinfo records. Skipped if nil. + Mount []*mountinfo.Entry `json:"mount,omitempty"` + // Whether to run seccomp checks. + Seccomp bool `json:"seccomp,omitempty"` + + // Name of pathname and abstract sockets to attempt. + TrySocket string `json:"try_socket,omitempty"` + // Errno to expect attempting to reach the abstract socket. + ErrnoAbstract syscall.Errno `json:"errno_abstract,omitempty"` + // Errno to expect attempting to reach the pathname socket. + ErrnoPathname syscall.Errno `json:"errno_pathname,omitempty"` +} + +// testCases hold all named test cases. +var testCases map[string]TestCase + +// fc returns c wrapped in its JSON adapter. +func fc(c hst.FilesystemConfig) hst.FilesystemConfigJSON { + return hst.FilesystemConfigJSON{ + FilesystemConfig: c, + } +} + +// ignore is the magic string for a mountinfo field to be ignored. +const ignore = "//ignore" + +type dir = map[string]*testsuite.FS + +// r returns the address of a [mountinfo.Entry]. +func r( + root, target, vfsOptstr string, + fsType, source, fsOptstr string, +) *mountinfo.Entry { + return &mountinfo.Entry{ + ID: -1, + Parent: -1, + Root: root, + Target: target, + VfsOptstr: vfsOptstr, + FsType: fsType, + Source: source, + FsOptstr: fsOptstr, + } +} + +var ( + // fcLinker is the dynamic linker symlink. + fcLinker = fc(&hst.FSLink{ + Target: fhs.AbsRoot.Append("lib64", "ld-linux-x86-64.so.2"), + Linkname: "../lib/x86_64-linux-gnu/ld-linux-x86-64.so.2", + }) + // fcLib is the dynamic library bind mount. + fcLib = fc(&hst.FSBind{Source: fhs.AbsRoot.Append("lib")}) + + // absTestHelper is the absolute pathname of the test helper program. + absTestHelper = hst.AbsPrivateTmp.Append("test-helper") + // fcTestHelper is the test helper bind mount. + fcTestHelper = fc(&hst.FSBind{ + Target: absTestHelper, + Source: check.MustAbs("/opt/test-helper/bin/tester"), + }) +) + +// register adds a test case to testCases. +func (c TestCase) register(name string) (_ struct{}) { + if testCases == nil { + testCases = make(map[string]TestCase) + } + + if _, ok := testCases[name]; ok { + panic("attempting to register " + strconv.Quote(name) + " twice") + } + testCases[name] = c + return +} + +// Get returns the named test case, or terminates the program if name is invalid. +func Get(name string) TestCase { + tc, ok := testCases[name] + if !ok { + log.Fatalf("invalid test case %q", name) + } + return tc +} + +// All returns an iterator over all named test cases. +func All() iter.Seq2[string, TestCase] { + return func(yield func(string, TestCase) bool) { + for name, tc := range testCases { + if !yield(name, tc) { + return + } + } + } +} -- cgit v1.3.1