audit

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package audit is the transparency layer for what leaves the machine: an append-only audit log of counts (never content), an opt-in store of the exact redacted payloads of recent sends, and an optional confirm step.

Index

Constants

View Source
const FileName = "redaction-audit.jsonl"

FileName is the audit log's name inside the state directory.

View Source
const ReviewFileName = "redaction-review.json"

ReviewFileName is the review store's name inside the state directory.

Variables

View Source
var ErrDeclined = errors.New("send declined at the confirm prompt")

ErrDeclined means the user answered no to the confirm prompt; nothing was sent or recorded.

Functions

func SortedKeys

func SortedKeys(m map[string]int) []string

SortedKeys lists a count map's keys, highest count first, ties by name.

Types

type Entry

type Entry struct {
	Time        time.Time `json:"time"`
	Agent       string    `json:"agent"`
	QuestionSet string    `json:"question_set"`
	Payload     string    `json:"payload"`
}

Entry is one stored send: the exact already-redacted payload.

type Log

type Log struct {
	Path string
	// contains filtered or unexported fields
}

Log is an append-only JSONL file, 0600 in a 0700 directory.

func (*Log) Append

func (l *Log) Append(rec Record) error

Append writes one record as a single line.

type Meta

type Meta struct {
	Agent       string
	QuestionSet string
}

Meta labels a send in the audit log.

type Prompter

type Prompter interface {
	Confirm(payload string) (bool, error)
}

Prompter asks the user whether the redacted payload may be sent.

func NewPrompter

func NewPrompter(in io.Reader, out io.Writer) Prompter

NewPrompter shows the payload on out and reads a y/yes answer from in. Any other answer, including end of input, is a no.

type Record

type Record struct {
	Time        time.Time      `json:"time"`
	Agent       string         `json:"agent"`
	QuestionSet string         `json:"question_set"`
	BytesBefore int            `json:"bytes_before"`
	BytesAfter  int            `json:"bytes_after"`
	Hits        map[string]int `json:"hits"`
}

Record is one audit line. It carries rule ids and counts only: never matched content, and never the payload.

func Read

func Read(path string, since time.Time) (recs []Record, skipped int, err error)

Read returns the records at or after since (zero means all) in file order. Lines that do not parse are counted in skipped rather than failing the read.

func (Record) String

func (r Record) String() string

String renders a one-line description, for error text.

type Review

type Review struct {
	Path    string
	Enabled bool
	// Max and TTL default to 20 and 24h when zero.
	Max int
	TTL time.Duration
	// Now is the clock; nil means time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

Review keeps the last Max sends for TTL. It is off unless Enabled, because stored payloads are themselves sensitive; while off it holds nothing and deletes anything a previous run left behind.

func (*Review) Add

func (r *Review) Add(e Entry) error

Add stores e (stamped now when e.Time is zero), purges expired entries and keeps only the newest Max. It is a no-op that also purges when disabled.

func (*Review) Last

func (r *Review) Last(n int) ([]Entry, error)

Last returns up to n of the newest live entries, oldest first. Expired entries are purged as a side effect. It is empty when disabled.

type Summary

type Summary struct {
	Sends        int            `json:"sends"`
	BytesBefore  int            `json:"bytes_before"`
	BytesAfter   int            `json:"bytes_after"`
	First        time.Time      `json:"first,omitempty"`
	Last         time.Time      `json:"last,omitempty"`
	Agents       map[string]int `json:"agents"`
	QuestionSets map[string]int `json:"question_sets"`
	Hits         map[string]int `json:"hits"`
}

Summary aggregates records.

func Summarize

func Summarize(recs []Record) Summary

Summarize aggregates recs.

type Transparency

type Transparency struct {
	Log    *Log
	Review *Review
	// Prompter is set only by interactive callers (`jevkit key test`, MCP
	// jev_ask style calls). Hooks leave it nil so they never block, even when
	// redact.confirm is on.
	Prompter Prompter
	Now      func() time.Time
}

Transparency wraps the send path with an audit line, the review store and the optional confirm step.

func (*Transparency) Gate

func (t *Transparency) Gate(ctx context.Context, cfg *config.Config, m Meta, subject, text string, send config.Send) (out, pattern string, sent bool, err error)

Gate is config.Gate with transparency: never_send, then redaction, then the confirm prompt, then the audit line and review entry, then send. A failure to record stops the send: what cannot be audited is not sent.

Jump to

Keyboard shortcuts

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