package security import ( "strings" "testing" ) func TestSecurityValidator(t *testing.T) { validator := NewSecurityValidator() // Test IP validation t.Run("IP Validation", func(t *testing.T) { validIPs := []string{"192.168.1.1", "127.0.0.1", "::1", "2001:db8::1"} for _, ip := range validIPs { if err := validator.ValidateIP(ip); err != nil { t.Errorf("Valid IP %s rejected: %v", ip, err) } } invalidIPs := []string{ "", // empty "999.999.999.999", // invalid range "192.168.1.1; rm -rf /", // command injection "192.168.1.1`whoami`", // command substitution "192.168.1.1$(id)", // command substitution "192.168.1.1\ncat /etc/passwd", // newline injection } for _, ip := range invalidIPs { if err := validator.ValidateIP(ip); err == nil { t.Errorf("Invalid IP %s was accepted", ip) } } }) // Test username validation t.Run("Username Validation", func(t *testing.T) { validUsernames := []string{"ubuntu", "user123", "_system", "test-user"} for _, username := range validUsernames { if err := validator.ValidateUsername(username); err != nil { t.Errorf("Valid username %s rejected: %v", username, err) } } invalidUsernames := []string{ "", // empty "user; rm -rf /", // command injection "user`id`", // command substitution "user$(whoami)", // command substitution "user\ncat /etc/passwd", // newline injection "user name", // space "user'test", // single quote "user\"test", // double quote "123user", // starts with number } for _, username := range invalidUsernames { if err := validator.ValidateUsername(username); err == nil { t.Errorf("Invalid username %s was accepted", username) } } }) // Test password validation t.Run("Password Validation", func(t *testing.T) { validPasswords := []string{ "", // empty is allowed "simplepassword", "complex@password#123", "unicode-пароль", } for _, password := range validPasswords { if err := validator.ValidatePassword(password); err != nil { t.Errorf("Valid password rejected: %v", err) } } invalidPasswords := []string{ "password`whoami`", // command substitution "password$(id)", // command substitution "password\necho malicious", // newline injection "password'break", // single quote injection "password$USER", // variable expansion } for _, password := range invalidPasswords { if err := validator.ValidatePassword(password); err == nil { t.Errorf("Invalid password was accepted") } } }) // Test SSH key validation t.Run("SSH Key Validation", func(t *testing.T) { validKeys := []string{ "", // empty is allowed "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----", "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjE...\n-----END OPENSSH PRIVATE KEY-----", } for _, key := range validKeys { if err := validator.ValidateSSHKey(key); err != nil { t.Errorf("Valid SSH key rejected: %v", err) } } invalidKeys := []string{ "ssh-rsa AAAAB3NzaC1yc2E...", // public key where private expected "invalid-key-format", "-----BEGIN RSA PRIVATE KEY-----\ntruncated", // malformed } for _, key := range invalidKeys { if err := validator.ValidateSSHKey(key); err == nil { t.Errorf("Invalid SSH key was accepted") } } }) // Test command sanitization t.Run("Command Sanitization", func(t *testing.T) { testCases := []struct { input string expected string safe bool }{ {"ls -la", "ls -la", true}, {"systemctl status nginx", "systemctl status nginx", true}, {"echo `whoami`", "echo whoami", false}, // backticks removed {"rm -rf /; echo done", "rm -rf / echo done", false}, // semicolon removed {"ls | grep test", "ls grep test", false}, // pipe removed {"echo $USER", "echo USER", false}, // dollar removed } for _, tc := range testCases { result := validator.SanitizeForCommand(tc.input) if result != tc.expected { t.Errorf("Command sanitization failed: input=%s, expected=%s, got=%s", tc.input, tc.expected, result) } isSafe := (result == tc.input) if isSafe != tc.safe { t.Errorf("Safety expectation failed for input=%s: expected safe=%v, got safe=%v", tc.input, tc.safe, isSafe) } } }) // Test port validation t.Run("Port Validation", func(t *testing.T) { validPorts := []int{22, 80, 443, 8080, 3000} for _, port := range validPorts { if err := validator.ValidatePort(port); err != nil { t.Errorf("Valid port %d rejected: %v", port, err) } } invalidPorts := []int{0, -1, 65536, 99999} for _, port := range invalidPorts { if err := validator.ValidatePort(port); err == nil { t.Errorf("Invalid port %d was accepted", port) } } }) // Test cluster secret validation t.Run("Cluster Secret Validation", func(t *testing.T) { validSecrets := []string{ "abcdef1234567890abcdef1234567890", // 32 char hex "a1b2c3d4e5f6789012345678901234567890abcd", // longer hex "alphanumericSecr3t123456789012345678", // alphanumeric, 38 chars } for _, secret := range validSecrets { if err := validator.ValidateClusterSecret(secret); err != nil { t.Errorf("Valid secret rejected: %v", err) } } invalidSecrets := []string{ "", // empty "short", // too short strings.Repeat("a", 200), // too long } for _, secret := range invalidSecrets { if err := validator.ValidateClusterSecret(secret); err == nil { t.Errorf("Invalid secret was accepted") } } }) } func TestValidateSSHConnectionRequest(t *testing.T) { validator := NewSecurityValidator() // Test valid request err := validator.ValidateSSHConnectionRequest("192.168.1.1", "ubuntu", "password123", "", 22) if err != nil { t.Errorf("Valid SSH connection request rejected: %v", err) } // Test with SSH key instead of password err = validator.ValidateSSHConnectionRequest("192.168.1.1", "ubuntu", "", "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----", 22) if err != nil { t.Errorf("Valid SSH key request rejected: %v", err) } // Test missing both password and key err = validator.ValidateSSHConnectionRequest("192.168.1.1", "ubuntu", "", "", 22) if err == nil { t.Error("Request with no auth method was accepted") } // Test command injection in IP err = validator.ValidateSSHConnectionRequest("192.168.1.1; rm -rf /", "ubuntu", "password", "", 22) if err == nil { t.Error("Command injection in IP was accepted") } // Test command injection in username err = validator.ValidateSSHConnectionRequest("192.168.1.1", "ubuntu`whoami`", "password", "", 22) if err == nil { t.Error("Command injection in username was accepted") } }