audit

package
v0.1.1-alpha Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package audit writes a bounded, local JSONL audit trail without retaining terminal input, raw prompt matches, environment values, or backend errors.

Index

Constants

View Source
const (
	// CurrentSchemaVersion identifies the on-disk Entry representation.
	CurrentSchemaVersion = 1
)

Variables

View Source
var ErrClosed = errors.New("audit recorder is closed")
View Source
var ErrNotAuditJournal = errors.New("audit path contains a foreign file")

ErrNotAuditJournal reports an audit path that already holds a file Relayer did not write.

Functions

func AuditGenerationIndex

func AuditGenerationIndex(base, name string) (int, bool)

AuditGenerationIndex applies the exact filename recognition used by audit rotation. It is exported within Relayer's internal boundary so passive diagnostics can inspect precisely the files the runtime would mutate.

func DefaultPath

func DefaultPath() (string, error)

DefaultPath returns the private per-user audit file location.

func Redact

func Redact(value string) string

Redact removes common credential forms from arbitrary text. It is intentionally conservative and idempotent.

func ResolvePath

func ResolvePath(path string) (string, error)

ResolvePath returns an absolute effective path, using DefaultPath for an empty configured value.

func Validate

func Validate(config Config) error

Validate rejects ambiguous or unsafe recorder settings.

func VerifyJournalFile

func VerifyJournalFile(path string) error

VerifyJournalFile reports whether an existing path holds a Relayer audit journal. It only reads, so read-only diagnostics can warn about a foreign file before startup refuses to open it. An absent path is not an error here: callers decide what a missing journal means.

Types

type Config

type Config struct {
	Enabled       bool   `json:"enabled" yaml:"enabled"`
	Mode          Mode   `json:"mode" yaml:"mode"`
	Path          string `json:"path" yaml:"path"`
	MaxFileSizeMB int    `json:"max_file_size_mb" yaml:"max_file_size_mb"`
	MaxFiles      int    `json:"max_files" yaml:"max_files"`
}

Config controls local audit persistence. MaxFiles counts the active file as well as its rotated generations.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig enables a conservative metadata-only audit trail.

type Decision

type Decision string

Decision is the audited policy outcome. It intentionally differs from an adapter's wire decision: asking a human is an explicit, content-free audit action rather than a copy of the submitted terminal input.

const (
	DecisionAllow   Decision = "allow"
	DecisionAsk     Decision = "ask"
	DecisionDeny    Decision = "deny"
	DecisionUnknown Decision = "unknown"
)

type DecisionBy

type DecisionBy string

DecisionBy identifies the actor without storing any submitted value.

const (
	DecisionBySystem  DecisionBy = "system"
	DecisionByHuman   DecisionBy = "human"
	DecisionByPolicy  DecisionBy = "policy"
	DecisionByUnknown DecisionBy = "unknown"
)

type Entry

type Entry struct {
	SchemaVersion int                `json:"schema_version"`
	Sequence      uint64             `json:"sequence"`
	Timestamp     time.Time          `json:"timestamp"`
	EntryID       string             `json:"entry_id"`
	RunID         string             `json:"run_id"`
	Kind          Kind               `json:"kind,omitempty"`
	SessionID     string             `json:"session_id,omitempty"`
	AgentID       string             `json:"agent_id,omitempty"`
	Backend       string             `json:"backend,omitempty"`
	Adapter       string             `json:"adapter,omitempty"`
	EventID       string             `json:"event_id,omitempty"`
	EventType     adapters.EventType `json:"event_type,omitempty"`
	Risk          adapters.RiskLevel `json:"risk,omitempty"`
	Rule          string             `json:"rule,omitempty"`
	Decision      Decision           `json:"decision,omitempty"`
	DecisionBy    DecisionBy         `json:"decision_by,omitempty"`
	Outcome       Outcome            `json:"outcome,omitempty"`
	Reason        string             `json:"reason,omitempty"`
	Summary       string             `json:"summary,omitempty"`
	Sensitive     bool               `json:"sensitive"`
	Metadata      map[string]string  `json:"metadata,omitempty"`
}

Entry is the versioned JSONL record. It intentionally has no Match, manual-input, environment, or raw-error field.

func SanitizeEntry

func SanitizeEntry(entry Entry, mode Mode) Entry

SanitizeEntry returns a deep, redacted copy suitable for the selected mode.

type FileSink

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

FileSink writes complete lines synchronously and rotates them by size.

func NewFileSink

func NewFileSink(path string, maxBytes int64, maxFiles int) (*FileSink, error)

NewFileSink opens a private append-only audit file. maxFiles includes the active file, so maxFiles=1 retains no rotated generation.

func (*FileSink) Close

func (s *FileSink) Close() error

Close syncs and closes the active file once.

func (*FileSink) Path

func (s *FileSink) Path() string

Path returns the absolute active file path.

func (*FileSink) WriteLine

func (s *FileSink) WriteLine(line []byte) error

WriteLine appends and syncs exactly one complete JSONL line.

type Kind

type Kind string

Kind identifies a closed set of audit lifecycle records.

const (
	KindRunStarted     Kind = "run_started"
	KindRunFinished    Kind = "run_finished"
	KindSessionStarted Kind = "session_started"
	// KindSupervisionFinished means Relayer stopped supervising the session;
	// it does not claim that a persistent tmux process exited.
	KindSupervisionFinished Kind = "supervision_finished"
	KindSessionFinished     Kind = "session_finished"
	KindEventDetected       Kind = "event_detected"
	// KindEventWithdrawn records that an occurrence which was awaiting a human
	// stopped being pending without a decision being delivered. It is the only
	// evidence that a supervision gate opened on its own.
	KindEventWithdrawn  Kind = "event_withdrawn"
	KindPolicyEvaluated Kind = "policy_evaluated"
	KindDecision        Kind = "decision"
	KindDelivery        Kind = "delivery"
	// KindOperatorInput records only the lifecycle of a direct, human line
	// submission. Entry intentionally has no field for the submitted text,
	// its length, or the encoded terminal bytes.
	KindOperatorInput  Kind = "operator_input"
	KindAttachStarted  Kind = "attach_started"
	KindAttachFinished Kind = "attach_finished"
	KindBackendError   Kind = "backend_error"
	KindSessionCleanup Kind = "session_cleanup"
	KindUnknown        Kind = "unknown"
)

type LineSink

type LineSink interface {
	WriteLine([]byte) error
	Close() error
}

LineSink owns persistence of complete JSONL lines.

type Mode

type Mode string

Mode controls how much already-sanitized event information reaches disk.

const (
	ModeOff      Mode = "off"
	ModeMetadata Mode = "metadata"
	ModeDetailed Mode = "detailed"
)

type Option

type Option func(*openOptions) error

Option customizes Open without weakening its filesystem invariants.

func WithClock

func WithClock(clock func() time.Time) Option

WithClock supplies a deterministic recorder clock.

func WithIDGenerator

func WithIDGenerator(generator func() (string, error)) Option

WithIDGenerator supplies run and entry identifiers.

func WithRunID

func WithRunID(runID string) Option

WithRunID binds audit records to an externally reserved runtime identity. This keeps GUI generation identity stable even when auditing is disabled.

type Outcome

type Outcome string

Outcome is a safe, finite result vocabulary for lifecycle and policy audit.

const (
	OutcomeStarted                   Outcome = "started"
	OutcomeFinished                  Outcome = "finished"
	OutcomeDetected                  Outcome = "detected"
	OutcomePending                   Outcome = "pending"
	OutcomeInFlight                  Outcome = "in_flight"
	OutcomeApplied                   Outcome = "applied"
	OutcomeAsk                       Outcome = "ask"
	OutcomeDryRun                    Outcome = "dry_run"
	OutcomeFallbackUnsupported       Outcome = "fallback_unsupported"
	OutcomeFallbackStale             Outcome = "fallback_stale"
	OutcomeFallbackDeliveryUncertain Outcome = "fallback_delivery_uncertain"
	OutcomeSucceeded                 Outcome = "succeeded"
	OutcomeFailed                    Outcome = "failed"
	OutcomeCancelled                 Outcome = "cancelled"
	OutcomeSkipped                   Outcome = "skipped"
	OutcomeUnknown                   Outcome = "unknown"
)

type Recorder

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

Recorder assigns identities and a total order before writing sanitized JSONL.

func NewRecorder

func NewRecorder(
	config Config,
	sink LineSink,
	clock func() time.Time,
	idGenerator func() (string, error),
) (*Recorder, error)

NewRecorder constructs a recorder around an injectable line sink, clock, and ID generator. Nil clock and generator select secure production defaults.

func Open

func Open(config Config, options ...Option) (*Recorder, error)

Open creates a rotating FileSink and wraps it in a Recorder. Disabled and off configurations perform no filesystem or ID-generator work.

func (*Recorder) Close

func (r *Recorder) Close() error

Close is safe to call concurrently and closes the underlying sink once.

func (*Recorder) Enabled

func (r *Recorder) Enabled() bool

Enabled reports whether this recorder performs any work.

func (*Recorder) Path

func (r *Recorder) Path() string

Path returns the configured or effective audit path.

func (*Recorder) Record

func (r *Recorder) Record(entry Entry) error

Record sanitizes and synchronously persists one entry. Holding the recorder lock through WriteLine makes Sequence identical to accepted on-disk order.

func (*Recorder) RunID

func (r *Recorder) RunID() string

RunID returns the immutable identifier shared by this recorder's entries.

Jump to

Keyboard shortcuts

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