🎭 CHORUS now contains full BZZZ functionality adapted for containers Core systems ported: - P2P networking (libp2p with DHT and PubSub) - Task coordination (COOEE protocol) - HMMM collaborative reasoning - SHHH encryption and security - SLURP admin election system - UCXL content addressing - UCXI server integration - Hypercore logging system - Health monitoring and graceful shutdown - License validation with KACHING Container adaptations: - Environment variable configuration (no YAML files) - Container-optimized logging to stdout/stderr - Auto-generated agent IDs for container deployments - Docker-first architecture All proven BZZZ P2P protocols, AI integration, and collaboration features are now available in containerized form. Next: Build and test container deployment. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
221 lines
6.6 KiB
Go
221 lines
6.6 KiB
Go
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")
|
|
}
|
|
} |