fetch_ml/internal/audit/alert.go
Jeremie Fraeys a981e89005
feat(security): add audit subsystem and tenant isolation
Implement comprehensive audit and security infrastructure:
- Immutable audit logs with platform-specific backends (Linux/Other)
- Sealed log entries with tamper-evident checksums
- Audit alert system for real-time security notifications
- Log rotation with retention policies
- Checkpoint-based audit verification

Add multi-tenant security features:
- Tenant manager with quota enforcement
- Middleware for tenant authentication/authorization
- Per-tenant cryptographic key isolation
- Supply chain security for container verification
- Cross-platform secure file utilities (Unix/Windows)

Add test coverage:
- Unit tests for audit alerts and sealed logs
- Platform-specific audit backend tests
2026-02-26 12:03:45 -05:00

89 lines
2.3 KiB
Go

// Package audit provides tamper-evident audit logging with hash chaining
package audit
import (
"context"
"fmt"
"time"
)
// TamperAlert represents a tampering detection event
type TamperAlert struct {
DetectedAt time.Time `json:"detected_at"`
Severity string `json:"severity"` // "critical", "warning"
Description string `json:"description"`
ExpectedHash string `json:"expected_hash,omitempty"`
ActualHash string `json:"actual_hash,omitempty"`
FilePath string `json:"file_path,omitempty"`
}
// AlertManager defines the interface for tamper alerting
type AlertManager interface {
Alert(ctx context.Context, a TamperAlert) error
}
// LoggingAlerter logs alerts to a standard logger
type LoggingAlerter struct {
logger interface {
Error(msg string, keysAndValues ...any)
Warn(msg string, keysAndValues ...any)
}
}
// NewLoggingAlerter creates a new logging alerter
func NewLoggingAlerter(logger interface {
Error(msg string, keysAndValues ...any)
Warn(msg string, keysAndValues ...any)
}) *LoggingAlerter {
return &LoggingAlerter{logger: logger}
}
// Alert logs the tamper alert
func (l *LoggingAlerter) Alert(_ context.Context, a TamperAlert) error {
if l.logger == nil {
return nil
}
if a.Severity == "critical" {
l.logger.Error("TAMPERING DETECTED",
"description", a.Description,
"expected_hash", a.ExpectedHash,
"actual_hash", a.ActualHash,
"file_path", a.FilePath,
"detected_at", a.DetectedAt,
)
} else {
l.logger.Warn("Potential tampering detected",
"description", a.Description,
"expected_hash", a.ExpectedHash,
"actual_hash", a.ActualHash,
"file_path", a.FilePath,
"detected_at", a.DetectedAt,
)
}
return nil
}
// MultiAlerter sends alerts to multiple backends
type MultiAlerter struct {
alerters []AlertManager
}
// NewMultiAlerter creates a new multi-alerter
func NewMultiAlerter(alerters ...AlertManager) *MultiAlerter {
return &MultiAlerter{alerters: alerters}
}
// Alert sends alert to all configured alerters
func (m *MultiAlerter) Alert(ctx context.Context, a TamperAlert) error {
var errs []error
for _, alerter := range m.alerters {
if err := alerter.Alert(ctx, a); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return fmt.Errorf("alert failures: %v", errs)
}
return nil
}