Major changes: - Add internal/logging package with field constants, context propagation, sensitive data auto-redaction, and per-component log levels - Add worker timeout constants (TimeoutQuickOp, TimeoutHealthCheck, etc.) - Extend SDLC with callback handlers, generate endpoints, and executor - Add new cookbook trees for aeries and slackpath progression - Add skeleton templates for queue, realtime, and microservices - Add worker component template with async job processing - Refactor services and handlers to use new logging infrastructure - Split component.go into component_infra.go and component_listing.go Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
package logging
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
// AuditAction represents a security-relevant action.
|
|
type AuditAction string
|
|
|
|
const (
|
|
AuditActionCreate AuditAction = "create"
|
|
AuditActionRead AuditAction = "read"
|
|
AuditActionUpdate AuditAction = "update"
|
|
AuditActionDelete AuditAction = "delete"
|
|
AuditActionLogin AuditAction = "login"
|
|
AuditActionLogout AuditAction = "logout"
|
|
AuditActionGrant AuditAction = "grant"
|
|
AuditActionRevoke AuditAction = "revoke"
|
|
AuditActionExecute AuditAction = "execute"
|
|
AuditActionDeploy AuditAction = "deploy"
|
|
AuditActionProvision AuditAction = "provision"
|
|
AuditActionDeprovision AuditAction = "deprovision"
|
|
)
|
|
|
|
// AuditResult represents the outcome of an audited action.
|
|
type AuditResult string
|
|
|
|
const (
|
|
AuditResultSuccess AuditResult = "success"
|
|
AuditResultFailure AuditResult = "failure"
|
|
AuditResultDenied AuditResult = "denied"
|
|
)
|
|
|
|
// AuditEvent represents a security audit event.
|
|
type AuditEvent struct {
|
|
// Timestamp is when the event occurred.
|
|
Timestamp time.Time
|
|
|
|
// Action is what was attempted.
|
|
Action AuditAction
|
|
|
|
// Resource is what the action was performed on.
|
|
Resource string
|
|
|
|
// ResourceID identifies the specific resource.
|
|
ResourceID string
|
|
|
|
// Result is the outcome of the action.
|
|
Result AuditResult
|
|
|
|
// UserID is who performed the action (empty for system actions).
|
|
UserID string
|
|
|
|
// APIKeyID is the API key used (empty for internal actions).
|
|
APIKeyID string
|
|
|
|
// RequestID correlates to the HTTP request.
|
|
RequestID string
|
|
|
|
// Details contains additional context.
|
|
Details map[string]any
|
|
}
|
|
|
|
// AuditLogger logs security-relevant events.
|
|
// Audit logs are always written regardless of log level.
|
|
type AuditLogger struct {
|
|
logger *Logger
|
|
}
|
|
|
|
// NewAuditLogger creates a new audit logger.
|
|
func NewAuditLogger(l *Logger) *AuditLogger {
|
|
return &AuditLogger{
|
|
logger: l.WithComponent("audit"),
|
|
}
|
|
}
|
|
|
|
// Log logs an audit event.
|
|
func (a *AuditLogger) Log(ctx context.Context, event AuditEvent) {
|
|
if event.Timestamp.IsZero() {
|
|
event.Timestamp = time.Now()
|
|
}
|
|
|
|
// Build attributes
|
|
attrs := []any{
|
|
FieldAuditAction, string(event.Action),
|
|
FieldAuditResource, event.Resource,
|
|
FieldAuditResult, string(event.Result),
|
|
"resource_id", event.ResourceID,
|
|
"timestamp", event.Timestamp.Format(time.RFC3339),
|
|
}
|
|
|
|
if event.UserID != "" {
|
|
attrs = append(attrs, FieldUserID, event.UserID)
|
|
}
|
|
if event.APIKeyID != "" {
|
|
attrs = append(attrs, FieldAPIKeyID, event.APIKeyID)
|
|
}
|
|
if event.RequestID != "" {
|
|
attrs = append(attrs, FieldRequestID, event.RequestID)
|
|
}
|
|
|
|
// Add details as individual fields
|
|
for k, v := range event.Details {
|
|
attrs = append(attrs, k, v)
|
|
}
|
|
|
|
// Audit logs are always Info level (never skipped)
|
|
a.logger.Info("audit event", attrs...)
|
|
}
|
|
|
|
// LogAction is a convenience method for logging simple actions.
|
|
func (a *AuditLogger) LogAction(ctx context.Context, action AuditAction, resource, resourceID string, result AuditResult) {
|
|
// Extract context values if available
|
|
l := FromContext(ctx)
|
|
event := AuditEvent{
|
|
Action: action,
|
|
Resource: resource,
|
|
ResourceID: resourceID,
|
|
Result: result,
|
|
}
|
|
|
|
// Try to extract request ID from the context logger
|
|
// This works because the middleware adds these fields
|
|
a.Log(ctx, event)
|
|
_ = l // We might want to extract fields from context in the future
|
|
}
|
|
|
|
// LogSuccess logs a successful action.
|
|
func (a *AuditLogger) LogSuccess(ctx context.Context, action AuditAction, resource, resourceID string) {
|
|
a.LogAction(ctx, action, resource, resourceID, AuditResultSuccess)
|
|
}
|
|
|
|
// LogFailure logs a failed action.
|
|
func (a *AuditLogger) LogFailure(ctx context.Context, action AuditAction, resource, resourceID string) {
|
|
a.LogAction(ctx, action, resource, resourceID, AuditResultFailure)
|
|
}
|
|
|
|
// LogDenied logs a denied action.
|
|
func (a *AuditLogger) LogDenied(ctx context.Context, action AuditAction, resource, resourceID string) {
|
|
a.LogAction(ctx, action, resource, resourceID, AuditResultDenied)
|
|
}
|