Documentation
¶
Overview ¶
Package ledger implements an append-only audit ledger stored as JSON Lines. Each record embeds the SHA-256 hash of the previous record, so any edit, insertion, or reorder breaks the chain and is caught by Verify. Open takes an advisory file lock so only one process can write a given ledger at a time.
Index ¶
- func ScrubString(s string, sensitive ...string) string
- func VerifyBundle(r io.Reader) (int, error)
- type Bundle
- type Event
- type Ledger
- func (l *Ledger) Append(ev Event) (Event, error)
- func (l *Ledger) Close() error
- func (l *Ledger) Export(w io.Writer, sessionID string) error
- func (l *Ledger) ExportBundle(w io.Writer, sessionID string, pub ed25519.PublicKey) error
- func (l *Ledger) Records() ([]Event, error)
- func (l *Ledger) Replay(sessionID string) ([]Event, error)
- func (l *Ledger) SetSigner(s *Signer)
- func (l *Ledger) Verify() error
- func (l *Ledger) VerifySignatures(pub ed25519.PublicKey, requireAll bool) error
- type Scrubber
- type Signer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ScrubString ¶
ScrubString masks declared secrets and pattern-detected credentials in a free-form string (e.g. tool stdout/stderr) so they aren't returned to clients in cleartext. Declared secrets are masked (not hashed) here, since the result is meant to stay human-readable.
func VerifyBundle ¶
VerifyBundle validates a Bundle read from r: hashes, chain linkage, and a signature on every event, checked against the embedded public key. It returns the number of verified events. A session bundle need not start at seq 1, so linkage is checked between consecutive records only.
Types ¶
type Bundle ¶
type Bundle struct {
KeyID string `json:"key_id"`
PublicKey string `json:"public_key"`
Events []Event `json:"events"`
}
Bundle is a self-contained export of events plus the public key needed to check their signatures, verifiable with VerifyBundle. Trust in the key itself is established out of band.
type Event ¶
type Event struct {
Seq int `json:"seq"`
Time time.Time `json:"time"`
SessionID string `json:"session_id"`
Sandbox string `json:"sandbox"`
Profile string `json:"profile"`
// Tool is the action surface, e.g. "shell", "file.read", "net", "approval".
Tool string `json:"tool"`
// Action is the primary argument: the command, path, or hostname.
Action string `json:"action"`
Args []string `json:"args,omitempty"`
Verdict string `json:"verdict"`
ExitCode int `json:"exit_code"`
DurationMS int64 `json:"duration_ms"`
// Meta keys are sorted before hashing so the record hash is independent
// of map iteration order.
Meta map[string]string `json:"meta,omitempty"`
Redacted bool `json:"redacted"`
// PayloadHash is the SHA-256 hex of the original payload, recorded when
// Redacted is true so plaintext can later be proven to match.
PayloadHash string `json:"payload_hash,omitempty"`
// PrevHash is empty for the genesis record.
PrevHash string `json:"prev_hash"`
Hash string `json:"hash"`
// KeyID and Sig are set when the ledger has a Signer. Both are excluded
// from hashEvent so signing does not alter the chain hash.
KeyID string `json:"key_id,omitempty"`
Sig string `json:"sig,omitempty"`
}
Event is a single audited action. Callers fill in the descriptive fields; Append assigns Seq, Time, PrevHash, and Hash.
func Redact ¶
Redact returns a copy of ev with payload fields replaced by their "sha256:<hex>" digests and Redacted set. PayloadHash records the hash of the original payload so plaintext can later be proven to match without touching the ledger. With no sensitive values, the whole payload (Action, Args, Meta values) is redacted; otherwise only strings exactly equal to a sensitive value are. Structural fields (Tool, Verdict, SessionID) are always preserved.
func Scrub ¶
Scrub returns a copy of ev with secrets removed from its payload fields (Action, Args, Meta values). Declared sensitive values are replaced by their "sha256:<hex>" digest; additionally, credential-shaped substrings are masked with redactMask. Structural fields (Tool, Verdict, SessionID, ...) are always preserved. When nothing is changed, ev is returned unmodified (Redacted stays false) so clean events remain fully readable. PayloadHash records the hash of the original payload so the plaintext can later be proven to match.
type Ledger ¶
type Ledger struct {
// contains filtered or unexported fields
}
Ledger is an append-only, hash-chained audit log backed by a JSON Lines file. Construct with Open. Safe for concurrent use.
func Open ¶
Open opens or creates the ledger file at path and recovers the chain tip and sequence number so appends continue an existing chain.
func (*Ledger) Append ¶
Append writes ev as one JSON line with chain fields set, fsyncs, and returns the stored event.
func (*Ledger) Export ¶
Export writes a pretty-printed JSON array of a session's events to w. An empty sessionID exports everything.
func (*Ledger) ExportBundle ¶
ExportBundle writes a Bundle of the session's events (all events when sessionID is ""), embedding pub.
func (*Ledger) SetSigner ¶
SetSigner attaches a Signer so subsequent appends sign each record; nil disables signing. Call it after Open, before concurrent appends begin.
type Scrubber ¶
type Scrubber struct {
// contains filtered or unexported fields
}
Scrubber applies built-in and optional operator-provided scrub patterns.
func NewScrubber ¶
NewScrubber returns a scrubber that always includes built-in secret patterns.
type Signer ¶
type Signer struct {
// contains filtered or unexported fields
}
Signer signs ledger record hashes with an ed25519 key so a third party holding the public key can verify records were not altered.
func LoadOrCreateSigner ¶
LoadOrCreateSigner loads the signing key from dir, generating and persisting a new keypair on first use.