audit

package
v1.3.30 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

audit/diff.go

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Diff

func Diff(before, after any) []string

Diff returns the field names that differ between two structs. Both must be the same type. Uses json tags as field names when present.

Fields tagged with audit:"-" are always excluded from the diff, which is useful for system-managed fields like updated_at and updated_by that change on every write but carry no semantic diff value.

func Mask

func Mask(v any) any

Mask takes any value, marshals it to JSON, and returns a copy where sensitive fields (by key name) are replaced with "<redacted>". This approach is intentionally minimal: it operates on the JSON representation and thus does not require constructing typed copies.

func MaskJSON

func MaskJSON(data []byte) ([]byte, error)

MaskJSON masks sensitive fields in already-serialized JSON bytes. It is more efficient than Mask when the caller already has JSON bytes, since it avoids a redundant marshal step. Returns the original bytes unchanged if parsing fails.

func Migrate added in v1.3.5

func Migrate(db *gorm.DB) error

Migrate creates or updates the audit_logs table to match the current AuditLog schema. Call this during application startup before the first audit write.

Types

type AsyncRepository

type AsyncRepository struct {
	OnError func(Entry, error) // called on failed write
	// contains filtered or unexported fields
}

AsyncRepository writes audit entries to an underlying Repository asynchronously. It buffers entries in a channel and has a Shutdown method to flush remaining items.

func NewAsyncRepository

func NewAsyncRepository(underlying Repository, buffer int, workers int) *AsyncRepository

NewAsyncRepository creates an AsyncRepository with the given buffer size and number of concurrent drain goroutines. If workers < 1 it defaults to 1.

func (*AsyncRepository) Shutdown

func (a *AsyncRepository) Shutdown(ctx context.Context) error

Shutdown closes the queue and waits for pending items to be processed. If the provided context expires before flush completes an AppError is returned.

closed is set under mu (same mutex Write uses) so that no new wg.Add(1) calls can race with wg.Wait().

func (*AsyncRepository) Write

func (a *AsyncRepository) Write(ctx context.Context, entry Entry) error

Write enqueues an audit entry for asynchronous persistence. Returns an AppError if the repository is shut down or the internal buffer is full.

The mutex is held across the closed-check, wg.Add(1), and the non-blocking channel send so that Shutdown cannot close the channel between any of those three steps (which would cause a WaitGroup panic or a send-on-closed panic).

type AuditLog

type AuditLog struct {
	ID            uint            `json:"id"`
	EntityType    string          `json:"entity_type"`
	EntityID      int             `json:"entity_id"`
	Action        string          `json:"action"`
	ActorID       int             `json:"actor_id"`
	Metadata      json.RawMessage `json:"metadata"`
	BeforeState   json.RawMessage `json:"before_state"`
	AfterState    json.RawMessage `json:"after_state"`
	ChangedFields json.RawMessage `json:"changed_fields"`
	CreatedAt     time.Time       `json:"created_at"`
}

AuditLog represents a persisted audit entry. Tags are intentionally generic (no GORM-specific tags) so runtime packages do not import GORM directly. Note: Metadata is stored as raw JSON bytes to ensure GORM AutoMigrate can create the correct column type across dialects.

type Entry

type Entry struct {
	EntityType    string
	EntityID      int
	Action        string
	ActorID       int
	Metadata      map[string]any
	BeforeState   any // will be marshalled to JSON
	AfterState    any
	ChangedFields []string
}

Entry represents a logical audit event to persist.

func NewEntry

func NewEntry(entityType string, entityID, actorID int, action string) Entry

func (Entry) WithAfter

func (e Entry) WithAfter(v any) Entry

func (Entry) WithBefore

func (e Entry) WithBefore(v any) Entry

func (Entry) WithDiff

func (e Entry) WithDiff(fields []string) Entry

type Repository

type Repository interface {
	Write(ctx context.Context, entry Entry) error
}

Repository defines the minimal audit persistence API.

func NewRepository

func NewRepository(t database.Transactor) Repository

NewRepository constructs a Repository using the provided Transactor.

func NewRepositoryWithHook

func NewRepositoryWithHook(t database.Transactor, hook func(ctx context.Context, log AuditLog) error) Repository

NewRepositoryWithHook constructs a Repository and installs a test hook used in unit tests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL