Documentation
¶
Overview ¶
Package audit records a structured, queryable trail of every mutating action an AI agent takes against issue trackers through the daemon. Each action is captured as a CloudEvents 1.0 envelope so the trail is machine-queryable and tool-friendly rather than ad-hoc free text.
Index ¶
Constants ¶
const RetentionDays = 90
RetentionDays is the rolling window for audit event retention. Audit trails warrant longer retention than the stats trend window: accountability records of what an agent did and why are evidence that must outlive the short-lived trend graphs, so 90 days rather than 30.
const SpecVersion = "1.0"
SpecVersion is the CloudEvents specification version every emitted envelope declares. Pinned to the core 1.0 attributes the trail relies on.
Variables ¶
This section is empty.
Functions ¶
func DefaultDBPath ¶
func DefaultDBPath() string
DefaultDBPath returns the path to the audit database (~/.human/audit.db), creating the directory if needed.
Types ¶
type Actor ¶
type Actor struct {
TrackerKind string `json:"tracker_kind"`
TrackerName string `json:"tracker_name,omitempty"`
User string `json:"user,omitempty"`
}
Actor identifies which configured tracker credential performed the action. This is the CloudEvents source decomposed into queryable parts.
type Data ¶
type Data struct {
Operation string `json:"operation"`
Actor Actor `json:"actor"`
Resource Resource `json:"resource"`
Outcome Outcome `json:"outcome"`
Args []string `json:"args,omitempty"`
Decision DecisionContext `json:"decision"`
}
Data is the decomposed payload carried in the CloudEvents data attribute.
type DecisionContext ¶
type DecisionContext struct {
ModelID string `json:"model_id,omitempty"`
ModelVersion string `json:"model_version,omitempty"`
Inputs string `json:"inputs,omitempty"`
Rationale string `json:"rationale,omitempty"`
}
DecisionContext captures the model id/version, inputs, and reasoning exactly as they existed at decision time. Agent decisions are non-deterministic: a past decision cannot be reconstructed by replaying the same prompt against the model later, so the inputs and rationale must be captured here at emission time or they are lost forever.
func DecisionFromEnv ¶
func DecisionFromEnv(lookup func(string) string) DecisionContext
DecisionFromEnv reads the at-decision-time context an agent harness forwards via HUMAN_AUDIT_* environment variables. All fields are optional: a missing rationale is allowed and recorded empty (the event still captures actor/resource/operation/outcome/model).
type Event ¶
type Event struct {
SpecVersion string `json:"specversion"`
ID string `json:"id"`
Source string `json:"source"`
Type string `json:"type"`
Subject string `json:"subject,omitempty"`
Time time.Time `json:"time"`
DataContentType string `json:"datacontenttype"`
Data Data `json:"data"`
}
Event is the CloudEvents 1.0 envelope persisted and surfaced to "human audit".
func BuildEvent ¶
func BuildEvent(now time.Time, op MutatingOp, outcome Outcome, dc DecisionContext, args []string) (Event, error)
BuildEvent assembles a complete CloudEvents envelope from a detected op, the observed outcome, the at-decision-time context, and the original args. The args are stripped of credentials first so secrets never reach the durable, reviewable trail.
type MutatingOp ¶
type MutatingOp struct {
Operation string // "create","edit","delete","comment","status","start"
TrackerKind string
TrackerName string // from --tracker
Key string // issue key, empty for create
Project string // from --project, for create
}
MutatingOp is the skeleton of a detected mutating tracker command, decomposed into the parts the audit event needs.
func DetectMutating ¶
func DetectMutating(args []string) (MutatingOp, bool)
DetectMutating classifies a forwarded command's args into a mutating-op skeleton, returning ok=false for read-only or non-tracker commands.
It is broader than the daemon's detectDestructive (which only gates confirmation-worthy destructive ops): audit must also cover non-destructive mutations like create and comment. It lives here rather than in the daemon so it is testable without a running daemon and reusable by a future client-side emitter. detectDestructive is deliberately left untouched.
type Outcome ¶
type Outcome string
Outcome is the result of a mutating tracker action.
const ( // OutcomeSuccess means the command executed and exited 0. OutcomeSuccess Outcome = "success" // OutcomeFailure means the command executed and exited non-zero. OutcomeFailure Outcome = "failure" // OutcomeDenied means the action was intercepted as destructive and the // human reviewer rejected (or let time out) the confirmation. OutcomeDenied Outcome = "denied" )
type Resource ¶
type Resource struct {
Key string `json:"key,omitempty"`
Project string `json:"project,omitempty"`
}
Resource identifies the ticket or project the action targeted.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists audit events in SQLite for a structured, queryable trail. The full CloudEvents envelope is stored as JSON alongside decomposed, indexed columns so queries stay fast while the envelope round-trips intact.
func NewStore ¶
NewStore opens (or creates) a SQLite database at dbPath and ensures the schema is up to date. Use ":memory:" for in-memory databases in tests.
func (*Store) Insert ¶
Insert persists a single audit event. The full envelope is marshalled to JSON for durable, lossless replay while the decomposed columns feed the indexed query paths.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer accepts audit events on a channel and inserts them into a Store in a single background goroutine. Call Close to drain remaining events and shut down.
func NewWriter ¶
NewWriter creates a Writer and starts the background drain goroutine. The goroutine runs until ctx is cancelled or Close is called.
func (*Writer) Close ¶
func (w *Writer) Close()
Close signals the writer to stop and waits for the background goroutine to finish draining. It is idempotent and safe to call after ctx cancellation has already stopped the goroutine.
func (*Writer) Send ¶
Send enqueues an event for async persistence. If the channel is full the event is dropped with a warning rather than blocking the caller. The data channel is never closed, so Send is safe to call concurrently with — and after — Close without panicking; the quit case discards events once shut down.