package namespace import ( "os" "testing" "time" ) type mockFileInfo struct { name string } func (m *mockFileInfo) Name() string { return m.name } func (m *mockFileInfo) Size() int64 { return 0 } func (m *mockFileInfo) Mode() os.FileMode { return 0 } func (m *mockFileInfo) ModTime() time.Time { return time.Now() } func (m *mockFileInfo) IsDir() bool { return false } func (m *mockFileInfo) Sys() any { return nil } type mockFS struct { files map[string][]byte canOpen map[string]bool } func (m *mockFS) Stat(name string) (os.FileInfo, error) { if _, ok := m.files[name]; ok { return &mockFileInfo{name: name}, nil } return nil, os.ErrNotExist } func (m *mockFS) MkdirAll(path string, perm os.FileMode) error { return nil } func (m *mockFS) CreateTemp(dir, pattern string) (*os.File, error) { return nil, nil } func (m *mockFS) MkdirTemp(dir, pattern string) (string, error) { return "", nil } func (m *mockFS) Remove(name string) error { return nil } func (m *mockFS) ReadFile(name string) ([]byte, error) { if data, ok := m.files[name]; ok { return data, nil } return nil, os.ErrNotExist } func (m *mockFS) Open(name string) (*os.File, error) { if m.canOpen[name] { f, _ := os.CreateTemp("", "mock-file") return f, nil } return nil, os.ErrPermission } func TestCheckSystemRequirements(t *testing.T) { tests := []struct { name string files map[string][]byte canOpen map[string]bool wantErr bool }{ { name: "all requirements met", files: map[string][]byte{ "/dev/net/tun": {}, }, canOpen: map[string]bool{ "/dev/net/tun": true, }, wantErr: false, }, { name: "tun device missing", files: map[string][]byte{}, canOpen: map[string]bool{}, wantErr: true, }, { name: "tun device not accessible", files: map[string][]byte{ "/dev/net/tun": {}, }, canOpen: map[string]bool{ "/dev/net/tun": false, }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fs := &mockFS{files: tt.files, canOpen: tt.canOpen} p := NewPreflight(fs) err := p.CheckSystemRequirements() if (err != nil) != tt.wantErr { t.Errorf("CheckSystemRequirements() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestRunHealthCheck(t *testing.T) { tests := []struct { name string files map[string][]byte canOpen map[string]bool uid int username string wantPass map[string]bool }{ { name: "healthy non-root user on Debian", files: map[string][]byte{ "/dev/net/tun": {}, "/proc/sys/kernel/unprivileged_userns_clone": []byte("1"), "/proc/sys/user/max_user_namespaces": []byte("1024"), "/etc/subuid": []byte("james:100000:60000"), }, canOpen: map[string]bool{ "/dev/net/tun": true, }, uid: 1000, username: "james", wantPass: map[string]bool{ "TUN Device Accessibility": true, "Unprivileged User Namespaces (Debian/Ubuntu)": true, "User Namespace Limit": true, "SubUID/SubGID Mappings": true, }, }, { name: "healthy root user", files: map[string][]byte{ "/dev/net/tun": {}, }, canOpen: map[string]bool{ "/dev/net/tun": true, }, uid: 0, username: "root", wantPass: map[string]bool{ "TUN Device Accessibility": true, "SubUID/SubGID Mappings": true, // Should be bypassed }, }, { name: "broken config", files: map[string][]byte{ "/dev/net/tun": {}, "/proc/sys/kernel/unprivileged_userns_clone": []byte("0"), "/proc/sys/user/max_user_namespaces": []byte("0"), "/etc/subuid": []byte("someone-else:100000:60000"), }, canOpen: map[string]bool{ "/dev/net/tun": true, }, uid: 1000, username: "james", wantPass: map[string]bool{ "TUN Device Accessibility": true, "Unprivileged User Namespaces (Debian/Ubuntu)": false, "User Namespace Limit": false, "SubUID/SubGID Mappings": false, }, }, { name: "non-debian healthy", files: map[string][]byte{ "/dev/net/tun": {}, "/proc/sys/user/max_user_namespaces": []byte("1024"), "/etc/subuid": []byte("james:100000:60000"), }, canOpen: map[string]bool{ "/dev/net/tun": true, }, uid: 1000, username: "james", wantPass: map[string]bool{ "TUN Device Accessibility": true, "Unprivileged User Namespaces (Debian/Ubuntu)": true, // Not applicable is considered passed "User Namespace Limit": true, "SubUID/SubGID Mappings": true, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fs := &mockFS{files: tt.files, canOpen: tt.canOpen} p := NewPreflight(fs) results := p.RunHealthCheck(tt.uid, tt.username) for _, res := range results { if pass, ok := tt.wantPass[res.Name]; ok { if res.Passed != pass { t.Errorf("Requirement %s: passed = %v, want %v (Msg: %s)", res.Name, res.Passed, pass, res.Message) } } } }) } }