Class: Kotoshu::Integrity::AuditLog
- Inherits:
-
Object
- Object
- Kotoshu::Integrity::AuditLog
- Defined in:
- lib/kotoshu/integrity/audit_log.rb
Overview
Append-only JSON audit log of every resource download.
Each entry is one JSON object per line, written to ‘audit.log` under the configured Kotoshu home directory. The log is consulted by users when investigating “what did Kotoshu fetch?” and by CI for reproducibility audits.
Statuses:
"verified" — content matched manifest entry's SHA-256
"unverified" — no manifest entry available; bytes trusted as-is
"mismatch" — SHA-256 mismatch (also raises IntegrityError)
"missing" — attempted download failed (network, 404, etc.)
The log is opened, appended, and closed per entry — no long-lived file handle. Writes are line-buffered and fsync’d so the record survives a crash mid-batch.
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Class Method Summary collapse
-
.default_path ⇒ Object
Default location: $XDG_DATA_HOME/kotoshu/audit.log (~/.local/share/kotoshu/audit.log), or $KOTOSHU_AUDIT_LOG.
Instance Method Summary collapse
- #clear! ⇒ Object
-
#each ⇒ Object
Iterate every recorded entry (parsed Hashes).
- #entries ⇒ Object
-
#initialize(path: self.class.default_path) ⇒ AuditLog
constructor
A new instance of AuditLog.
-
#record(url:, status:, size: nil, sha256: nil, manifest_sha256: nil, resource_id: nil) ⇒ Object
Record one download attempt.
Constructor Details
#initialize(path: self.class.default_path) ⇒ AuditLog
Returns a new instance of AuditLog.
34 35 36 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 34 def initialize(path: self.class.default_path) @path = path end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
32 33 34 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 32 def path @path end |
Class Method Details
.default_path ⇒ Object
Default location: $XDG_DATA_HOME/kotoshu/audit.log (~/.local/share/kotoshu/audit.log), or $KOTOSHU_AUDIT_LOG.
28 29 30 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 28 def self.default_path Kotoshu::Paths.audit_log_path end |
Instance Method Details
#clear! ⇒ Object
83 84 85 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 83 def clear! FileUtils.rm_f(@path) end |
#each ⇒ Object
Iterate every recorded entry (parsed Hashes).
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 67 def each return enum_for(:each) unless block_given? return unless File.exist?(@path) File.foreach(@path, encoding: "UTF-8") do |line| line = line.strip next if line.empty? yield JSON.parse(line) end end |
#entries ⇒ Object
79 80 81 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 79 def entries each.to_a end |
#record(url:, status:, size: nil, sha256: nil, manifest_sha256: nil, resource_id: nil) ⇒ Object
Record one download attempt. Returns the written entry hash.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/kotoshu/integrity/audit_log.rb', line 46 def record(url:, status:, size: nil, sha256: nil, manifest_sha256: nil, resource_id: nil) entry = { timestamp: Time.now.utc.iso8601, url: url, resource_id: resource_id, size: size, sha256: sha256, manifest_sha256: manifest_sha256, status: status } FileUtils.mkdir_p(File.dirname(@path)) File.open(@path, "a", encoding: "UTF-8") do |f| f.flock(File::LOCK_EX) f.write("#{entry.to_json}\n") f.fsync end entry end |