ledger

package
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func ScrubString

func ScrubString(s string, sensitive ...string) string

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

func VerifyBundle(r io.Reader) (int, error)

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

func Redact(ev Event, sensitive ...string) Event

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

func Scrub(ev Event, sensitive ...string) Event

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

func Open(path string) (*Ledger, error)

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

func (l *Ledger) Append(ev Event) (Event, error)

Append writes ev as one JSON line with chain fields set, fsyncs, and returns the stored event.

func (*Ledger) Close

func (l *Ledger) Close() error

Close releases the underlying file handle.

func (*Ledger) Export

func (l *Ledger) Export(w io.Writer, sessionID string) error

Export writes a pretty-printed JSON array of a session's events to w. An empty sessionID exports everything.

func (*Ledger) ExportBundle

func (l *Ledger) ExportBundle(w io.Writer, sessionID string, pub ed25519.PublicKey) error

ExportBundle writes a Bundle of the session's events (all events when sessionID is ""), embedding pub.

func (*Ledger) Records

func (l *Ledger) Records() ([]Event, error)

Records returns every event in the ledger, in write order.

func (*Ledger) Replay

func (l *Ledger) Replay(sessionID string) ([]Event, error)

Replay returns the ordered events for a single session.

func (*Ledger) SetSigner

func (l *Ledger) SetSigner(s *Signer)

SetSigner attaches a Signer so subsequent appends sign each record; nil disables signing. Call it after Open, before concurrent appends begin.

func (*Ledger) Verify

func (l *Ledger) Verify() error

Verify recomputes every record's hash and chain linkage, returning an error identifying the first bad record or nil if the chain is intact.

func (*Ledger) VerifySignatures

func (l *Ledger) VerifySignatures(pub ed25519.PublicKey, requireAll bool) error

VerifySignatures recomputes every record's hash and checks signatures against pub. When requireAll is true, an unsigned record is an error.

type Scrubber

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

Scrubber applies built-in and optional operator-provided scrub patterns.

func NewScrubber

func NewScrubber(extraPatterns ...*regexp.Regexp) *Scrubber

NewScrubber returns a scrubber that always includes built-in secret patterns.

func (*Scrubber) Scrub

func (sb *Scrubber) Scrub(ev Event, sensitive ...string) Event

Scrub returns a copy of ev with secrets removed from payload fields.

func (*Scrubber) ScrubString

func (s *Scrubber) ScrubString(in string, sensitive ...string) string

ScrubString masks declared secrets and pattern-detected credentials in a free-form string.

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

func LoadOrCreateSigner(dir string) (*Signer, error)

LoadOrCreateSigner loads the signing key from dir, generating and persisting a new keypair on first use.

func (*Signer) KeyID

func (s *Signer) KeyID() string

KeyID returns the short public-key fingerprint recorded on signed events.

func (*Signer) Public

func (s *Signer) Public() ed25519.PublicKey

Public returns the signer's public key.

func (*Signer) Sign

func (s *Signer) Sign(hashHex string) string

Sign returns the base64 ed25519 signature over a record hash.

Jump to

Keyboard shortcuts

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