monorepo/cloud/maplepress-backend/pkg/logger/sanitizer_test.go

345 lines
7 KiB
Go

package logger
import (
"testing"
)
func TestRedactEmail(t *testing.T) {
redactor := NewSensitiveFieldRedactor()
tests := []struct {
name string
input string
expected string
}{
{
name: "normal email",
input: "john.doe@example.com",
expected: "jo***@example.com",
},
{
name: "short local part",
input: "ab@example.com",
expected: "**@example.com",
},
{
name: "single character local part",
input: "a@example.com",
expected: "**@example.com",
},
{
name: "empty email",
input: "",
expected: "[empty]",
},
{
name: "invalid email",
input: "notanemail",
expected: "[invalid-email]",
},
{
name: "long email",
input: "very.long.email.address@subdomain.example.com",
expected: "ve***@subdomain.example.com",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := redactor.RedactEmail(tt.input)
if result != tt.expected {
t.Errorf("RedactEmail(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}
func TestHashForLogging(t *testing.T) {
redactor := NewSensitiveFieldRedactor()
tests := []struct {
name string
input string
}{
{
name: "email",
input: "john.doe@example.com",
},
{
name: "tenant slug",
input: "my-company",
},
{
name: "another email",
input: "jane.smith@test.com",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hash1 := redactor.HashForLogging(tt.input)
hash2 := redactor.HashForLogging(tt.input)
// Hash should be consistent
if hash1 != hash2 {
t.Errorf("HashForLogging is not consistent: %q != %q", hash1, hash2)
}
// Hash should be 16 characters (8 bytes in hex)
if len(hash1) != 16 {
t.Errorf("HashForLogging length = %d, want 16", len(hash1))
}
// Hash should not contain original value
if hash1 == tt.input {
t.Errorf("HashForLogging returned original value")
}
})
}
// Different inputs should produce different hashes
hash1 := redactor.HashForLogging("john.doe@example.com")
hash2 := redactor.HashForLogging("jane.smith@example.com")
if hash1 == hash2 {
t.Error("Different inputs produced same hash")
}
// Empty string
emptyHash := redactor.HashForLogging("")
if emptyHash != "[empty]" {
t.Errorf("HashForLogging(\"\") = %q, want [empty]", emptyHash)
}
}
func TestRedactTenantSlug(t *testing.T) {
redactor := NewSensitiveFieldRedactor()
tests := []struct {
name string
input string
expected string
}{
{
name: "normal slug",
input: "my-company",
expected: "my***",
},
{
name: "short slug",
input: "abc",
expected: "***",
},
{
name: "very short slug",
input: "ab",
expected: "***",
},
{
name: "empty slug",
input: "",
expected: "[empty]",
},
{
name: "long slug",
input: "very-long-company-name",
expected: "ve***",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := redactor.RedactTenantSlug(tt.input)
if result != tt.expected {
t.Errorf("RedactTenantSlug(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}
func TestRedactAPIKey(t *testing.T) {
redactor := NewSensitiveFieldRedactor()
tests := []struct {
name string
input string
expected string
}{
{
name: "live API key",
input: "live_sk_abc123def456ghi789",
expected: "live_sk_***i789",
},
{
name: "test API key",
input: "test_sk_xyz789uvw456rst123",
expected: "test_sk_***t123",
},
{
name: "short live key",
input: "live_sk_abc",
expected: "live_sk_***",
},
{
name: "other format",
input: "sk_abc123def456",
expected: "***f456",
},
{
name: "very short key",
input: "abc",
expected: "***",
},
{
name: "empty key",
input: "",
expected: "[empty]",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := redactor.RedactAPIKey(tt.input)
if result != tt.expected {
t.Errorf("RedactAPIKey(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}
func TestRedactJWTToken(t *testing.T) {
redactor := NewSensitiveFieldRedactor()
tests := []struct {
name string
input string
expected string
}{
{
name: "normal JWT",
input: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U",
expected: "eyJhbGci...P0THsR8U",
},
{
name: "short token",
input: "short",
expected: "***",
},
{
name: "empty token",
input: "",
expected: "[empty]",
},
{
name: "minimum length token",
input: "1234567890123456",
expected: "12345678...90123456",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := redactor.RedactJWTToken(tt.input)
if result != tt.expected {
t.Errorf("RedactJWTToken(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}
func TestRedactIPAddress(t *testing.T) {
redactor := NewSensitiveFieldRedactor()
tests := []struct {
name string
input string
expected string
}{
{
name: "IPv4 address",
input: "192.168.1.100",
expected: "192.168.*.*",
},
{
name: "IPv4 public",
input: "8.8.8.8",
expected: "8.8.*.*",
},
{
name: "IPv6 address",
input: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
expected: "2001:0db8:85a3:0000:****",
},
{
name: "IPv6 shortened",
input: "2001:db8::1",
expected: "2001:db8::1:****",
},
{
name: "empty IP",
input: "",
expected: "[empty]",
},
{
name: "invalid IP",
input: "notanip",
expected: "***",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := redactor.RedactIPAddress(tt.input)
if result != tt.expected {
t.Errorf("RedactIPAddress(%q) = %q, want %q", tt.input, result, tt.expected)
}
})
}
}
func TestUserIdentifier(t *testing.T) {
userID := "user_123"
email := "john.doe@example.com"
fields := UserIdentifier(userID, email)
if len(fields) != 3 {
t.Errorf("UserIdentifier returned %d fields, want 3", len(fields))
}
// Check that fields contain expected keys
fieldKeys := make(map[string]bool)
for _, field := range fields {
fieldKeys[field.Key] = true
}
expectedKeys := []string{"user_id", "email_hash", "email_redacted"}
for _, key := range expectedKeys {
if !fieldKeys[key] {
t.Errorf("UserIdentifier missing key: %s", key)
}
}
}
func TestTenantIdentifier(t *testing.T) {
tenantID := "tenant_123"
slug := "my-company"
fields := TenantIdentifier(tenantID, slug)
if len(fields) != 3 {
t.Errorf("TenantIdentifier returned %d fields, want 3", len(fields))
}
// Check that fields contain expected keys
fieldKeys := make(map[string]bool)
for _, field := range fields {
fieldKeys[field.Key] = true
}
expectedKeys := []string{"tenant_id", "tenant_slug_hash", "tenant_slug_redacted"}
for _, key := range expectedKeys {
if !fieldKeys[key] {
t.Errorf("TenantIdentifier missing key: %s", key)
}
}
}