fetch_ml/internal/logging/sanitize.go
Jeremie Fraeys 803677be57 feat: implement Go backend with comprehensive API and internal packages
- Add API server with WebSocket support and REST endpoints
- Implement authentication system with API keys and permissions
- Add task queue system with Redis backend and error handling
- Include storage layer with database migrations and schemas
- Add comprehensive logging, metrics, and telemetry
- Implement security middleware and network utilities
- Add experiment management and container orchestration
- Include configuration management with smart defaults
2025-12-04 16:53:53 -05:00

80 lines
2.2 KiB
Go

package logging
import (
"regexp"
"strings"
)
// Patterns for sensitive data
var (
// API keys: 32+ hex characters
apiKeyPattern = regexp.MustCompile(`\b[0-9a-fA-F]{32,}\b`)
// JWT tokens
jwtPattern = regexp.MustCompile(`eyJ[a-zA-Z0-9_-]{10,}\.eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}`)
// Password-like fields in logs
passwordPattern = regexp.MustCompile(`(?i)(password|passwd|pwd|secret|token|key)["']?\s*[:=]\s*["']?([^"'\s,}]+)`)
// Redis URLs with passwords
redisPasswordPattern = regexp.MustCompile(`redis://:[^@]+@`)
)
// SanitizeLogMessage removes sensitive data from log messages
func SanitizeLogMessage(message string) string {
// Redact API keys
message = apiKeyPattern.ReplaceAllString(message, "[REDACTED-API-KEY]")
// Redact JWT tokens
message = jwtPattern.ReplaceAllString(message, "[REDACTED-JWT]")
// Redact password-like fields
message = passwordPattern.ReplaceAllStringFunc(message, func(match string) string {
parts := passwordPattern.FindStringSubmatch(match)
if len(parts) >= 2 {
return parts[1] + "=[REDACTED]"
}
return match
})
// Redact Redis passwords from URLs
message = redisPasswordPattern.ReplaceAllString(message, "redis://:[REDACTED]@")
return message
}
// SanitizeArgs removes sensitive data from structured log arguments
func SanitizeArgs(args []any) []any {
sanitized := make([]any, len(args))
copy(sanitized, args)
for i := 0; i < len(sanitized)-1; i += 2 {
// Check if this is a key-value pair
key, okKey := sanitized[i].(string)
value, okValue := sanitized[i+1].(string)
if okKey && okValue {
lowerKey := strings.ToLower(key)
// Redact sensitive fields
if strings.Contains(lowerKey, "password") ||
strings.Contains(lowerKey, "secret") ||
strings.Contains(lowerKey, "token") ||
strings.Contains(lowerKey, "key") ||
strings.Contains(lowerKey, "api") {
sanitized[i+1] = "[REDACTED]"
} else if strings.HasPrefix(value, "redis://") {
sanitized[i+1] = SanitizeLogMessage(value)
}
}
}
return sanitized
}
// RedactAPIKey masks an API key for logging (shows first/last 4 chars)
func RedactAPIKey(key string) string {
if len(key) <= 8 {
return "[REDACTED]"
}
return key[:4] + "..." + key[len(key)-4:]
}