Files
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

86 lines
2.3 KiB
Go

package audit
import (
"context"
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/jackc/pgx/v5/pgxpool"
)
type Event struct {
ID string
Actor string
Action string
ResourceType string
ResourceID string
Result string
OccurredAt time.Time
CorrelationID string
Before map[string]any
After map[string]any
}
type Store interface {
Append(context.Context, Event) error
}
type MemoryStore struct {
Events []Event
}
func (store *MemoryStore) Append(_ context.Context, event Event) error {
if event.ID == "" {
event.ID = newID()
}
if event.OccurredAt.IsZero() {
event.OccurredAt = time.Now().UTC()
}
store.Events = append(store.Events, event)
return nil
}
type PostgresStore struct{ Pool *pgxpool.Pool }
func (store PostgresStore) Append(ctx context.Context, event Event) error {
if store.Pool == nil {
return errors.New("audit database pool is nil")
}
if event.ID == "" {
event.ID = newID()
}
if event.OccurredAt.IsZero() {
event.OccurredAt = time.Now().UTC()
}
before, err := json.Marshal(event.Before)
if err != nil {
return errors.New("marshal audit before diff")
}
after, err := json.Marshal(event.After)
if err != nil {
return errors.New("marshal audit after diff")
}
_, err = store.Pool.Exec(ctx, `INSERT INTO audit_events (id, actor, action, resource_type, resource_id, result, occurred_at, correlation_id, before_diff, after_diff) VALUES ($1::uuid, $2, $3, $4, NULLIF($5, '')::uuid, $6, $7, $8, $9::jsonb, $10::jsonb)`, event.ID, event.Actor, event.Action, event.ResourceType, event.ResourceID, event.Result, event.OccurredAt, event.CorrelationID, before, after)
if err != nil {
return errors.New("write audit event")
}
return nil
}
func newID() string {
bytes := make([]byte, 16)
if _, err := rand.Read(bytes); err != nil {
return "00000000-0000-4000-8000-000000000000"
}
bytes[6] = (bytes[6] & 0x0f) | 0x40
bytes[8] = (bytes[8] & 0x3f) | 0x80
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", bytes[0:4], bytes[4:6], bytes[6:8], bytes[8:10], bytes[10:16])
}
func RecordSecurityAction(ctx context.Context, store Store, actor, action, result, correlationID string) error {
return store.Append(ctx, Event{Actor: actor, Action: action, ResourceType: "security", Result: result, CorrelationID: correlationID})
}