audit

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package audit manages the registry audit log ring buffer and optional external export (Splunk HEC, syslog/CEF, plain JSON).

Fan-out from the server's audit() helper to the ring buffer and exporter is async: server.audit() publishes an "audit.entry" event on the shared events.Bus; Store.Subscribe starts a background goroutine that consumes those events and writes them here. This removes the direct coupling between the server's hot request path and the audit I/O.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RedactMap added in v0.2.4

func RedactMap(m map[string]interface{}) map[string]interface{}

RedactMap returns a shallow copy of m with any values whose keys match redactKey replaced by "<redacted>". Nil-safe (returns nil).

PILOT-314: the DLQ read API (HandleGetWebhookDLQ) returns event Details verbatim. If audit redaction wasn't exhaustive, the DLQ becomes a credential-disclosure surface for anyone holding the admin token. RedactMap allows callers outside package audit to apply the same redaction rules on retrieval.

Types

type AuditExporter

type AuditExporter struct {
	// contains filtered or unexported fields
}

AuditExporter sends audit events to an external system in the configured format (Splunk HEC, syslog/CEF, or plain JSON). It runs asynchronously with a buffered channel, just like registryWebhook.

func NewAuditExporter

func NewAuditExporter(cfg *wire.BlueprintAuditExport) *AuditExporter

NewAuditExporter creates and starts a new AuditExporter for the given config. It is exported so that the server package shim (audit_export.go) can delegate to it without the sub-package re-implementing the constructor.

func NewAuditExporterWithWAL added in v0.2.4

func NewAuditExporterWithWAL(cfg *wire.BlueprintAuditExport, walPath string) *AuditExporter

NewAuditExporterWithWAL creates and starts a new AuditExporter with an on-disk write-ahead log at walPath. Use empty walPath to disable the WAL.

func (*AuditExporter) Close

func (ae *AuditExporter) Close()

Close signals the background goroutine to stop and waits for it to drain. After a clean drain, the WAL is truncated — all pending entries have been sent to the external system.

func (*AuditExporter) Export

func (ae *AuditExporter) Export(entry *Entry)

Export queues an audit entry for export. The entry is persisted to the write-ahead log before entering the channel. Non-blocking; drops if the channel buffer is full, but the WAL copy survives a crash restart.

func (*AuditExporter) Stats

func (ae *AuditExporter) Stats() (exported, dropped uint64)

Stats returns export statistics.

type AuditWAL added in v0.2.4

type AuditWAL struct {
	// contains filtered or unexported fields
}

AuditWAL persists audit entries to disk in JSON-lines format before they enter the export channel. On clean shutdown the WAL is truncated; on crash restart all entries are replayed for re-export.

func NewAuditWAL added in v0.2.4

func NewAuditWAL(path string) (*AuditWAL, error)

NewAuditWAL opens or creates the WAL file at path. Returns nil when path is empty (no persistence configured).

func (*AuditWAL) Append added in v0.2.4

func (w *AuditWAL) Append(entry *Entry) error

Append writes an audit entry as a JSON line to the WAL and fsyncs.

func (*AuditWAL) Close added in v0.2.4

func (w *AuditWAL) Close() error

Close closes the underlying file.

func (*AuditWAL) Pending added in v0.2.4

func (w *AuditWAL) Pending() ([]Entry, error)

Pending reads all entries from the WAL for replay, oldest first.

func (*AuditWAL) Truncate added in v0.2.4

func (w *AuditWAL) Truncate() error

Truncate clears the WAL. Called after clean drain on shutdown.

type Entry

type Entry struct {
	Timestamp string `json:"timestamp"`
	Action    string `json:"action"`
	NetworkID uint16 `json:"network_id,omitempty"`
	NodeID    uint32 `json:"node_id,omitempty"`
	Details   string `json:"details,omitempty"`

	// Hash-chain fields for tamper-evidence.
	// PrevHash is the SHA-256 hex digest of the previous entry
	// (empty for the genesis entry). Hash is the SHA-256 hex
	// digest of this entry encompassing PrevHash, Timestamp,
	// Action, NetworkID, NodeID, and Details.
	PrevHash string `json:"prev_hash,omitempty"`
	Hash     string `json:"hash,omitempty"`
}

Entry records a single audit event. The JSON tags match the on-wire format used by handleGetAuditLog and the snapshot serialiser.

func BuildEntry

func BuildEntry(action string, netID uint16, nodeID uint32, attrs ...any) Entry

type SplunkHECEvent

type SplunkHECEvent struct {
	Time       int64                  `json:"time"`
	Host       string                 `json:"host,omitempty"`
	Source     string                 `json:"source,omitempty"`
	SourceType string                 `json:"sourcetype,omitempty"`
	Index      string                 `json:"index,omitempty"`
	Event      map[string]interface{} `json:"event"`
}

SplunkHECEvent is the Splunk HTTP Event Collector event format.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store holds the in-memory audit ring buffer and the optional external export adapter. All exported methods are safe for concurrent use.

func NewStore

func NewStore() *Store

NewStore creates an empty Store with no exporter configured.

func (*Store) Append

func (st *Store) Append(e Entry)

Append directly inserts an entry into the ring buffer and forwards it to the exporter (if configured). It is used by the snapshot restore path which bypasses the bus (no need to publish historical entries).

Each entry is linked to its predecessor via a SHA-256 hash chain, providing tamper-evident integrity. The genesis entry has an empty PrevHash.

func (*Store) Close

func (st *Store) Close()

Close stops the bus subscriber goroutine and drains/closes the exporter.

func (*Store) ExporterConfig

func (st *Store) ExporterConfig() *wire.BlueprintAuditExport

ExporterConfig returns the active export configuration (nil = disabled).

func (*Store) ExporterStats

func (st *Store) ExporterStats() (exported, dropped uint64)

ExporterStats returns (exported, dropped) counters from the active exporter.

func (*Store) FilteredEntries

func (st *Store) FilteredEntries(filterNetID uint16, limit int) []map[string]interface{}

FilteredEntries returns audit entries newest-first, filtered by netID (0 = all) and limited to at most limit entries.

func (*Store) HandleGetAuditExport

func (st *Store) HandleGetAuditExport(_ map[string]interface{}) (map[string]interface{}, error)

HandleGetAuditExport builds the response map for a "get_audit_export" protocol request. adminCheck must be called by the caller before invoking this method (the server wraps this in handleGetAuditExport which first calls requireAdminToken).

func (*Store) RestoreLog

func (st *Store) RestoreLog(entries []Entry)

RestoreLog replaces the ring buffer with the provided slice (used during snapshot restore on startup). If the entries already carry a valid hash chain it is preserved; otherwise the chain is rebuilt from scratch.

func (*Store) SetExporter

func (st *Store) SetExporter(cfg *wire.BlueprintAuditExport)

SetExporter replaces the current exporter with a new one built from cfg. The old exporter (if any) is drained and closed. Pass nil cfg to disable. If storePath was previously set via SetStorePath, the new exporter gets a write-ahead log at "{storePath}.audit-export-wal".

func (*Store) SetStorePath added in v0.2.4

func (st *Store) SetStorePath(p string)

SetStorePath records the registry snapshot file path so the audit exporter can derive its WAL path ({storePath}.audit-export-wal). Call once during server init, before SetExporter.

func (*Store) Snapshot

func (st *Store) Snapshot() []Entry

Snapshot returns a copy of the current audit log (oldest first).

func (*Store) Subscribe

func (st *Store) Subscribe(bus events.Bus)

Subscribe starts a background goroutine that reads "audit.entry" events from the bus and forwards each one to the configured exporter. Ring-buffer writes are synchronous (via Append); this goroutine handles only async exporter fan-out. Call it once after constructing the Store.

func (*Store) VerifyIntegrity added in v0.2.4

func (st *Store) VerifyIntegrity() int

VerifyIntegrity walks the hash chain from the oldest entry to the newest. It returns the index of the first entry whose hash does not match, or -1 when the chain is fully intact.

Jump to

Keyboard shortcuts

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