Class: Woods::Console::AuditLogger
- Inherits:
-
Object
- Object
- Woods::Console::AuditLogger
- Defined in:
- lib/woods/console/audit_logger.rb
Overview
Logs all Tier 4 tool invocations to a JSONL file.
Each line is a JSON object with: tool name, params, timestamp, confirmation status, and result summary.
Params and result summaries are passed through CredentialScanner so credentials an agent pastes inline into ‘console_eval` (or any other tool) do not land in audit logs unredacted.
Constant Summary collapse
- MAX_FIELD_CHARS =
Soft cap on any single logged field. Stops an attacker with Tier-4 access from filling disk via arbitrarily long params.
16_384
Instance Method Summary collapse
-
#entries ⇒ Array<Hash>
Read all audit entries.
-
#initialize(path:, scanner: nil) ⇒ AuditLogger
constructor
A new instance of AuditLogger.
-
#log(tool:, params:, confirmed:, result_summary:) ⇒ void
Write an audit entry.
-
#size ⇒ Integer
Number of audit entries.
Constructor Details
#initialize(path:, scanner: nil) ⇒ AuditLogger
Returns a new instance of AuditLogger.
32 33 34 35 |
# File 'lib/woods/console/audit_logger.rb', line 32 def initialize(path:, scanner: nil) @path = path @scanner = scanner || CredentialScanner.new end |
Instance Method Details
#entries ⇒ Array<Hash>
Read all audit entries.
121 122 123 124 125 126 127 |
# File 'lib/woods/console/audit_logger.rb', line 121 def entries return [] unless File.exist?(@path) File.readlines(@path).filter_map do |line| JSON.parse(line.strip) unless line.strip.empty? end end |
#log(tool:, params:, confirmed:, result_summary:) ⇒ void
This method returns an undefined value.
Write an audit entry.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/woods/console/audit_logger.rb', line 44 def log(tool:, params:, confirmed:, result_summary:) ensure_directory! entry = { tool: tool, params: redact(truncate_deep(params)), confirmed: confirmed, result_summary: redact(truncate_value(result_summary)), timestamp: Time.now.utc.iso8601 } # Exclusive flock around the append — concurrent Tier-4 invocations # across Puma threads would otherwise interleave bytes and produce # malformed JSONL lines (integrity hit on audit review). File.open(@path, File::WRONLY | File::APPEND | File::CREAT, 0o644) do |f| f.flock(File::LOCK_EX) f.puts(JSON.generate(sanitize_controls(entry))) end end |
#size ⇒ Integer
Number of audit entries.
132 133 134 |
# File 'lib/woods/console/audit_logger.rb', line 132 def size entries.size end |