//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 } } } }