Module: Reeve::Audit
- Defined in:
- lib/reeve/audit.rb,
lib/reeve/audit/entry.rb,
lib/reeve/audit/query.rb,
lib/reeve/audit/recorder.rb,
lib/reeve/audit/redactor.rb
Overview
The append-only ledger: one row per guarded invocation, allowed or denied (Constitution II, FR-008).
This file is the opt-in boundary. require "reeve" must keep working in a bare Ruby
process with no ActiveRecord (SC-008), so nothing here is loaded by the core — a host
(or the generated initializer) requires "reeve/audit" when it wants the table-backed
recorder.
require "reeve/audit"
Reeve::Audit::Query.for_principal(user)
.for_agent("claude-desktop")
.between(1.week.ago, Time.current)
.pluck(:tool_name, :record_type, :record_ids, :outcome, :rule)
What this module guarantees
- exactly one row per invocation, allowed or denied —
invocation_idis unique, and a replayed invocation is a no-op insert rather than a second row; ruleis never null: every row explains itself;- arguments are post-redaction, and no unredacted copy is written anywhere;
record_countstays true even whenrecord_idswas capped, andtruncatedsays so;occurred_atis invocation time, not write time;- no public method updates or deletes an entry.
What it does not
- It does not stop a database superuser, a migration, or raw SQL from rewriting the
table. Immutability is enforced at the library level; the generated migration
documents the
GRANT INSERT, SELECTthat enforces the rest where it can actually be enforced, and the gem makes no stronger claim than that. - No retention, rotation or archival yet — the table is host-owned and the host's existing policies apply.
- No cryptographic chaining or tamper-evidence yet. If that lands it arrives as a nullable column, which the audit-entry contract's versioning already permits.
("yet" rather than "in v1": the gem version and the audit-entry contract version are different numbers that move independently, and writing v1 for one of them read as the other.)
Defined Under Namespace
Modules: Query Classes: Entry, Recorder, Redactor
Constant Summary collapse
- CONTRACT_VERSION =
The version of the audit-entry shape, as documented in specs/001-guardrails-core/contracts/audit-entry.md (FR-015). Adding a nullable column is a MINOR change and leaves this alone; removing or renaming a column, or changing what a value means, is MAJOR and bumps it.
2 —
metadatacarries the transport detail the caller passed. Through version 1 it was written NULL on every row regardless of what was passed, so anything mapping version 1 rows could reasonably have read the column as "always empty". The shape did not change; what a value means did. 2- TABLE_NAME =
"reeve_audit_entries"
Class Method Summary collapse
-
.guard_registry ⇒ Object
Where per-tool redaction declarations come from: the authorization registry, if the authorization module is loaded.
-
.install!(config = Reeve.config) ⇒ Object
contracts/configuration.md documents
audit_recorderas defaulting to nil, "which resolves to Reeve::Audit::Recorder at invocation time — the default cannot be the constant itself, since the core loads without ActiveRecord".
Class Method Details
.guard_registry ⇒ Object
Where per-tool redaction declarations come from: the authorization registry, if the authorization module is loaded. Duck-typed and optional on purpose — the ledger is useful on its own, and a host running audit without guards should get the global redaction list rather than a NameError.
73 74 75 76 77 |
# File 'lib/reeve/audit.rb', line 73 def guard_registry return nil unless Reeve.respond_to?(:registry) Reeve.registry end |
.install!(config = Reeve.config) ⇒ Object
contracts/configuration.md documents audit_recorder as defaulting to nil, "which
resolves to Reeve::Audit::Recorder at invocation time — the default cannot be the
constant itself, since the core loads without ActiveRecord". This is that
resolution, performed at the first moment the constant is known to exist: the
require of this file. A host that named its own recorder keeps it.
84 85 86 87 |
# File 'lib/reeve/audit.rb', line 84 def install!(config = Reeve.config) config.audit_recorder ||= Recorder config end |