- 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
80 lines
2.2 KiB
Go
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:]
|
|
}
|