Documentation
¶
Index ¶
- Constants
- func RequireOpen(l *Log, level risk.Level) error
- type Entry
- type Filter
- type Level
- type Log
- func (l *Log) AddObserver(fn func(Entry))
- func (l *Log) Close() error
- func (l *Log) Export() (string, error)
- func (l *Log) MaxID() (int64, error)
- func (l *Log) Path() string
- func (l *Log) Query(limit int) ([]Entry, error)
- func (l *Log) QueryBySession(sessionID string) ([]Entry, error)
- func (l *Log) QueryFiltered(f Filter) ([]Entry, error)
- func (l *Log) QuerySince(afterID int64) ([]Entry, error)
- func (l *Log) Record(tool string, input interface{}, output string, risk string, level Level, ...)
- func (l *Log) RecordCtx(ctx context.Context, tool string, input interface{}, output string, ...)
- func (l *Log) SessionID() string
- func (l *Log) SetTechniqueResolver(fn TechniqueResolver)
- func (l *Log) Stats() (string, error)
- func (l *Log) TopRisks(since time.Time) ([]RiskCount, error)
- func (l *Log) TopTools(since time.Time, n int) ([]ToolCount, error)
- type RiskCount
- type TechniqueResolver
- type ToolCount
Constants ¶
const MaxQueryLimit = 10000
MaxQueryLimit caps the per-call row count returned by Query and QueryFiltered. The audit DB grows without bound across sessions; a caller asking for limit=1000000 (operator typo, malicious LLM tool call, stress test) would tie up SQLite for seconds and flood downstream consumers. 10k is generous for any reasonable triage flow — callers wanting more should paginate via Offset.
Both the REPL slash commands (/audit query, /history) and the audit_query tool consult this cap so the cap can't be bypassed by routing through a different surface.
Variables ¶
This section is empty.
Functions ¶
func RequireOpen ¶ added in v0.17.0
RequireOpen returns an error when l is nil and level is High or above. This enforces fail-closed behaviour: when the audit log is not initialised, destructive (High/Critical) actions are refused rather than proceeding silently. Low/Medium actions are permitted without an audit log for back-compat.
Types ¶
type Entry ¶
type Entry struct {
ID int64 `json:"id"`
Timestamp time.Time `json:"timestamp"`
Tool string `json:"tool"`
Input string `json:"input"`
Output string `json:"output"`
Risk string `json:"risk"`
Level Level `json:"level"`
SessionID string `json:"session_id"`
Duration int64 `json:"duration_ms"`
Success bool `json:"success"`
// TraceID correlates this entry with one REPL turn. Not persisted to
// the DB (schema predates the field); carried in-memory so observers
// (rules engine, webhooks, slog) can surface the turn that produced
// it. Empty when the caller did not route through obs.WithTrace.
TraceID string `json:"trace_id,omitempty"`
// TechniqueIDs records the MITRE ATT&CK technique IDs the tool
// contributes to at recording time (P1-07). Populated by the
// agent from the attack.Index; derived, not persisted to the
// DB schema. Enables the /report ATT&CK coverage heatmap to
// trust entry-time mappings even if the index changes later.
TechniqueIDs []string `json:"technique_ids,omitempty"`
}
type Filter ¶
type Filter struct {
Tool string // substring match on tool name (LIKE '%<v>%')
Risk string // exact: low|medium|high|critical
Session string // exact session id
Since time.Time // timestamp >= Since when non-zero
Until time.Time // timestamp <= Until when non-zero
Success *bool // nil = any; &true / &false to filter
Contains string // substring match on input OR output
Limit int // default 100 when <= 0
Offset int // rows to skip for pagination
}
Filter is the declarative query shape accepted by QueryFiltered. Zero fields are ignored; non-zero fields are ANDed together. All string matches against indexed columns are exact (Risk, Session) or substring (Tool, Contains); none use user-supplied SQL fragments.
type Log ¶
type Log struct {
// contains filtered or unexported fields
}
func Open ¶
Open prepares the audit log at dbPath. It takes a non-blocking advisory flock on the db file so only one PromptZero process writes to a given path at a time; if that lock is already held, Open falls back to a PID-suffixed sibling path (<dbPath>.<pid>) and logs a warning. The fallback keeps the REPL responsive instead of hard-erroring when a stale or sibling process still holds the primary log — each process gets its own WAL-backed sqlite file and concurrent writers no longer corrupt each other.
The lock is released on Log.Close.
func (*Log) AddObserver ¶
AddObserver registers a callback fired after every successful Record insert. Observers run synchronously on the caller goroutine, so keep them fast — for anything network-bound (webhooks) the observer should enqueue and return immediately. Adding during iteration is safe; observers added mid-notify are picked up on the next event.
func (*Log) MaxID ¶
MaxID returns the current highest row id, used by the /audit tail implementation to watch for new inserts.
func (*Log) Path ¶
Path returns the on-disk path of the sqlite db backing this log. When the primary path was contended at Open time this will be the PID-suffixed fallback; tests and /audit tail use it to distinguish the two cases.
func (*Log) QueryFiltered ¶
QueryFiltered returns audit entries matching f. All user-supplied values are bound as SQL parameters — no string interpolation, so operator input cannot inject SQL. An empty Filter returns the most recent 100 entries.
func (*Log) QuerySince ¶
QuerySince returns entries whose id is strictly greater than afterID, ordered oldest-first. Pair with MaxID() to tail new audit rows.
func (*Log) RecordCtx ¶
func (l *Log) RecordCtx(ctx context.Context, tool string, input interface{}, output string, risk string, level Level, duration time.Duration, success bool)
RecordCtx is the ctx-aware Record path. When ctx carries a trace (via obs.WithTrace) the trace ID is attached to the emitted Entry and the structured log line so observers can correlate the audit row with the REPL turn that produced it.
func (*Log) SetTechniqueResolver ¶ added in v0.3.0
func (l *Log) SetTechniqueResolver(fn TechniqueResolver)
SetTechniqueResolver installs the ATT&CK tool-to-technique mapping used to populate Entry.TechniqueIDs. Pass nil to disable. Safe to call from setup code before Record begins; callers during Record accept the race (the next entry picks up the new resolver).
type TechniqueResolver ¶ added in v0.3.0
TechniqueResolver is an optional hook that maps a tool name to the ATT&CK technique IDs it contributes to. Installed via SetTechniqueResolver; wired at agent startup to internal/attack's Index (P1-07). Empty slice / nil resolver means entries carry no TechniqueIDs.