lex-audit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 678a76434f7d1af470a6c1302b6079dbe86f4096f5e64fff11ffe3bc80d6ab92
4
+ data.tar.gz: e873a54a8b05dee40f5d078f9f5c80e99a332b6479a98ee7a26f4faae6f983d8
5
+ SHA512:
6
+ metadata.gz: e0783cc5cc4634ad85ae9d350d05c2d40f350a180689457f2285ace36ef3f227e5a722ffb2bb5ef5596d99d03b6d015e82c3a99728d80de46ff9d0c8074bfcae
7
+ data.tar.gz: f45707d4627e116e12dd303bb26b85abc984a8cb9b342f9c836e89a33d2cd73839e15c2990fa1630ca4956fd01e42c260e892a224ed91b44d80a1c6d586b72c1
@@ -0,0 +1,16 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+
7
+ jobs:
8
+ ci:
9
+ uses: LegionIO/.github/.github/workflows/ci.yml@main
10
+
11
+ release:
12
+ needs: ci
13
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
14
+ uses: LegionIO/.github/.github/workflows/release.yml@main
15
+ secrets:
16
+ rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,53 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.4
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
6
+ Layout/LineLength:
7
+ Max: 160
8
+
9
+ Layout/SpaceAroundEqualsInParameterDefault:
10
+ EnforcedStyle: space
11
+
12
+ Layout/HashAlignment:
13
+ EnforcedHashRocketStyle: table
14
+ EnforcedColonStyle: table
15
+
16
+ Metrics/MethodLength:
17
+ Max: 50
18
+
19
+ Metrics/ClassLength:
20
+ Max: 1500
21
+
22
+ Metrics/ModuleLength:
23
+ Max: 1500
24
+
25
+ Metrics/BlockLength:
26
+ Max: 40
27
+ Exclude:
28
+ - 'spec/**/*'
29
+
30
+ Metrics/AbcSize:
31
+ Max: 60
32
+
33
+ Metrics/CyclomaticComplexity:
34
+ Max: 15
35
+
36
+ Metrics/PerceivedComplexity:
37
+ Max: 17
38
+
39
+ Style/Documentation:
40
+ Enabled: false
41
+
42
+ Style/SymbolArray:
43
+ Enabled: true
44
+
45
+ Style/FrozenStringLiteralComment:
46
+ Enabled: true
47
+ EnforcedStyle: always
48
+
49
+ Naming/FileName:
50
+ Enabled: false
51
+
52
+ Gemspec/DevelopmentDependencies:
53
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-03-16
4
+
5
+ ### Added
6
+ - Initial release: immutable audit logging with SHA-256 hash chain
7
+ - Transport layer: `audit` exchange, `audit.log` queue with `x-single-active-consumer`
8
+ - `Audit` message class with event_type-based routing keys and field validation
9
+ - `write` runner: creates hash-chained audit records in the database
10
+ - `verify` runner: validates hash chain integrity, detects tampering
11
+ - `AuditWriter` subscription actor: consumes audit messages from AMQP
12
+ - 29 specs, 0 failures
data/CLAUDE.md ADDED
@@ -0,0 +1,70 @@
1
+ # lex-audit: Immutable Audit Logging for LegionIO
2
+
3
+ **Repository Level 3 Documentation**
4
+ - **Parent**: `/Users/miverso2/rubymine/legion/extensions-core/CLAUDE.md`
5
+ - **Grandparent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
6
+
7
+ ## Purpose
8
+
9
+ Legion Extension that provides immutable, tamper-evident audit logging with a SHA-256 hash chain. Records runner executions and lifecycle transitions via AMQP. Requires `legion-data` (`data_required? true`).
10
+
11
+ **GitHub**: https://github.com/LegionIO/lex-audit
12
+ **License**: MIT
13
+ **Version**: 0.1.0
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ Legion::Extensions::Audit
19
+ ├── Actors/
20
+ │ └── AuditWriter # Subscription actor: consumes audit messages, calls write runner
21
+ ├── Runners/
22
+ │ └── Audit # write: hash-chained record insert; verify: chain integrity check
23
+ └── Transport/
24
+ ├── Exchanges/Audit # Audit exchange
25
+ ├── Queues/Audit # audit.log queue (x-single-active-consumer: true)
26
+ └── Messages/Audit # Audit message with event_type routing key, field validation
27
+ ```
28
+
29
+ ## Key Files
30
+
31
+ | Path | Purpose |
32
+ |------|---------|
33
+ | `lib/legion/extensions/audit.rb` | Entry point, extension registration (`data_required? true`) |
34
+ | `lib/legion/extensions/audit/runners/audit.rb` | Hash chain write and verify logic |
35
+ | `lib/legion/extensions/audit/actors/audit_writer.rb` | AMQP subscription actor |
36
+ | `lib/legion/extensions/audit/transport/messages/audit.rb` | Message class with validation and routing |
37
+
38
+ ## Runner Details
39
+
40
+ **write**: Fetches the last record's hash (or genesis hash `"0"*64`), computes SHA-256 of `prev_hash|event_type|principal_id|action|resource|created_at`, and inserts the record. Uses `.utc.iso8601` for timezone-safe hashing.
41
+
42
+ **verify**: Iterates all records in order, recomputes each hash, and compares. Returns `{ valid:, records_checked:, break_at: }`.
43
+
44
+ ## Hash Chain Design
45
+
46
+ - Genesis hash: `"0" * 64` (64 zeros)
47
+ - Hash content: `"#{prev_hash}|#{event_type}|#{principal_id}|#{action}|#{resource}|#{created_at.utc.iso8601}"`
48
+ - Algorithm: SHA-256
49
+ - Single-active-consumer queue ensures ordering across cluster nodes
50
+ - `Sequel.default_timezone = :utc` required for consistent hash verification
51
+
52
+ ## Integration Points
53
+
54
+ - `Legion::Audit.record` (LegionIO) publishes messages to this extension
55
+ - `Runner.run` ensure block emits `runner_execution` events
56
+ - `DigitalWorker::Lifecycle.transition!` emits `lifecycle_transition` events
57
+ - `GET /api/audit` and `GET /api/audit/verify` query the audit log
58
+ - `legion audit list` and `legion audit verify` CLI commands
59
+
60
+ ## Testing
61
+
62
+ ```bash
63
+ bundle install
64
+ bundle exec rspec # 29 examples, 0 failures
65
+ bundle exec rubocop # 0 offenses
66
+ ```
67
+
68
+ ---
69
+
70
+ **Maintained By**: Matthew Iverson (@Esity)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,86 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lex-audit (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.8.9)
10
+ public_suffix (>= 2.0.2, < 8.0)
11
+ ast (2.4.3)
12
+ bigdecimal (4.0.1)
13
+ diff-lcs (1.6.2)
14
+ json (2.19.1)
15
+ json-schema (6.2.0)
16
+ addressable (~> 2.8)
17
+ bigdecimal (>= 3.1, < 5)
18
+ language_server-protocol (3.17.0.5)
19
+ lint_roller (1.1.0)
20
+ mcp (0.8.0)
21
+ json-schema (>= 4.1)
22
+ parallel (1.27.0)
23
+ parser (3.3.10.2)
24
+ ast (~> 2.4.1)
25
+ racc
26
+ prism (1.9.0)
27
+ public_suffix (7.0.5)
28
+ racc (1.8.1)
29
+ rainbow (3.1.1)
30
+ rake (13.3.1)
31
+ regexp_parser (2.11.3)
32
+ rspec (3.13.2)
33
+ rspec-core (~> 3.13.0)
34
+ rspec-expectations (~> 3.13.0)
35
+ rspec-mocks (~> 3.13.0)
36
+ rspec-core (3.13.6)
37
+ rspec-support (~> 3.13.0)
38
+ rspec-expectations (3.13.5)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.13.0)
41
+ rspec-mocks (3.13.8)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.13.0)
44
+ rspec-support (3.13.7)
45
+ rubocop (1.85.1)
46
+ json (~> 2.3)
47
+ language_server-protocol (~> 3.17.0.2)
48
+ lint_roller (~> 1.1.0)
49
+ mcp (~> 0.6)
50
+ parallel (~> 1.10)
51
+ parser (>= 3.3.0.2)
52
+ rainbow (>= 2.2.2, < 4.0)
53
+ regexp_parser (>= 2.9.3, < 3.0)
54
+ rubocop-ast (>= 1.49.0, < 2.0)
55
+ ruby-progressbar (~> 1.7)
56
+ unicode-display_width (>= 2.4.0, < 4.0)
57
+ rubocop-ast (1.49.1)
58
+ parser (>= 3.3.7.2)
59
+ prism (~> 1.7)
60
+ rubocop-rspec (3.9.0)
61
+ lint_roller (~> 1.1)
62
+ rubocop (~> 1.81)
63
+ ruby-progressbar (1.13.0)
64
+ sequel (5.102.0)
65
+ bigdecimal
66
+ sqlite3 (2.9.2-arm64-darwin)
67
+ sqlite3 (2.9.2-x86_64-linux-gnu)
68
+ unicode-display_width (3.2.0)
69
+ unicode-emoji (~> 4.1)
70
+ unicode-emoji (4.2.0)
71
+
72
+ PLATFORMS
73
+ arm64-darwin-25
74
+ x86_64-linux
75
+
76
+ DEPENDENCIES
77
+ lex-audit!
78
+ rake
79
+ rspec
80
+ rubocop
81
+ rubocop-rspec
82
+ sequel
83
+ sqlite3
84
+
85
+ BUNDLED WITH
86
+ 2.6.9
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # lex-audit
2
+
3
+ Immutable audit logging with SHA-256 hash chain for [LegionIO](https://github.com/LegionIO/LegionIO). Records every runner execution and lifecycle transition as a tamper-evident audit trail.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install lex-audit
9
+ ```
10
+
11
+ ## Functions
12
+
13
+ - **write** - Create a hash-chained audit record (each record's hash depends on the previous record)
14
+ - **verify** - Validate the entire hash chain to detect any tampering or corruption
15
+
16
+ ## How It Works
17
+
18
+ Every audit record includes a SHA-256 hash computed from: `prev_hash|event_type|principal_id|action|resource|created_at`. Each record references the previous record's hash, forming an immutable chain. Breaking any record invalidates all subsequent hashes.
19
+
20
+ The `audit.log` queue uses `x-single-active-consumer: true` to ensure only one consumer writes at a time, preserving hash chain ordering across a cluster.
21
+
22
+ `Legion::Audit.record` in LegionIO publishes audit events via AMQP. It uses triple-guard checks and silent rescue to never interfere with normal operation.
23
+
24
+ ## Event Types
25
+
26
+ | Type | Source | Description |
27
+ |------|--------|-------------|
28
+ | `runner_execution` | Runner.run | Every task execution with duration and status |
29
+ | `lifecycle_transition` | DigitalWorker::Lifecycle | Worker state machine transitions |
30
+
31
+ ## Requirements
32
+
33
+ - Ruby >= 3.4
34
+ - [LegionIO](https://github.com/LegionIO/LegionIO) framework
35
+ - `legion-data` (database required)
36
+
37
+ ## License
38
+
39
+ MIT
data/lex-audit.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'legion/extensions/audit/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'lex-audit'
9
+ spec.version = Legion::Extensions::Audit::VERSION
10
+ spec.authors = ['Esity']
11
+ spec.email = ['matthewdiverson@gmail.com']
12
+
13
+ spec.summary = 'Legion::Extensions::Audit'
14
+ spec.description = 'Immutable audit logging with SHA-256 hash chain for LegionIO execution decisions'
15
+ spec.homepage = 'https://github.com/LegionIO/lex-audit'
16
+ spec.license = 'MIT'
17
+ spec.required_ruby_version = '>= 3.4'
18
+
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-audit'
21
+ spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-audit/blob/main/CHANGELOG.md'
22
+ spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-audit'
23
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-audit/issues'
24
+ spec.metadata['rubygems_mfa_required'] = 'true'
25
+
26
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ end
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_development_dependency 'rake'
32
+ spec.add_development_dependency 'rspec'
33
+ spec.add_development_dependency 'rubocop'
34
+ spec.add_development_dependency 'rubocop-rspec'
35
+ spec.add_development_dependency 'sequel'
36
+ spec.add_development_dependency 'sqlite3'
37
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/actors/subscription'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Audit
8
+ module Actor
9
+ class AuditWriter < Legion::Extensions::Actors::Subscription
10
+ def runner_function
11
+ 'write'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Audit
8
+ module Runners
9
+ module Audit
10
+ include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
11
+
12
+ GENESIS_HASH = ('0' * 64).freeze
13
+
14
+ def write(event_type:, principal_id:, action:, resource:, **opts)
15
+ prev = Legion::Data::Model::AuditLog.order(Sequel.desc(:id)).first
16
+ prev_hash = prev ? prev.record_hash : GENESIS_HASH
17
+
18
+ created_at = opts[:created_at] ? Time.parse(opts[:created_at].to_s) : Time.now.utc
19
+ content = "#{prev_hash}|#{event_type}|#{principal_id}|#{action}|#{resource}|#{created_at.utc.iso8601}"
20
+ record_hash = Digest::SHA256.hexdigest(content)
21
+
22
+ detail_json = opts[:detail] ? Legion::JSON.dump(opts[:detail]) : nil
23
+
24
+ record = Legion::Data::Model::AuditLog.create(
25
+ event_type: event_type,
26
+ principal_id: principal_id,
27
+ principal_type: opts[:principal_type] || 'system',
28
+ action: action,
29
+ resource: resource,
30
+ source: opts[:source] || 'unknown',
31
+ node: opts[:node] || 'unknown',
32
+ status: opts[:status] || 'success',
33
+ duration_ms: opts[:duration_ms],
34
+ detail: detail_json,
35
+ record_hash: record_hash,
36
+ prev_hash: prev_hash,
37
+ created_at: created_at
38
+ )
39
+
40
+ { success: true, audit_id: record.id, record_hash: record_hash }
41
+ end
42
+
43
+ def verify(limit: nil, **_opts)
44
+ prev_hash = GENESIS_HASH
45
+ broken_at = nil
46
+ count = 0
47
+
48
+ dataset = Legion::Data::Model::AuditLog.order(:id)
49
+ dataset = dataset.limit(limit) if limit
50
+
51
+ dataset.each do |record|
52
+ content = "#{prev_hash}|#{record.event_type}|#{record.principal_id}|#{record.action}|#{record.resource}|#{record.created_at.utc.iso8601}"
53
+ expected = Digest::SHA256.hexdigest(content)
54
+ unless record.record_hash == expected
55
+ broken_at = record.id
56
+ break
57
+ end
58
+ prev_hash = record.record_hash
59
+ count += 1
60
+ end
61
+
62
+ { valid: broken_at.nil?, records_checked: count, break_at: broken_at }
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Audit
6
+ module Transport
7
+ module Exchanges
8
+ class Audit < Legion::Transport::Exchange
9
+ def exchange_name
10
+ 'audit'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Audit
6
+ module Transport
7
+ module Messages
8
+ class Audit < Legion::Transport::Message
9
+ def routing_key
10
+ "audit.#{@options[:event_type] || 'unknown'}"
11
+ end
12
+
13
+ def type
14
+ 'audit'
15
+ end
16
+
17
+ def encrypt?
18
+ false
19
+ end
20
+
21
+ def validate
22
+ raise 'event_type is required' unless @options[:event_type]
23
+ raise 'principal_id is required' unless @options[:principal_id]
24
+ raise 'action is required' unless @options[:action]
25
+ raise 'resource is required' unless @options[:resource]
26
+
27
+ @valid = true
28
+ end
29
+
30
+ def message
31
+ {
32
+ event_type: @options[:event_type],
33
+ principal_id: @options[:principal_id],
34
+ principal_type: @options[:principal_type] || 'system',
35
+ action: @options[:action],
36
+ resource: @options[:resource],
37
+ source: @options[:source] || 'unknown',
38
+ node: @options[:node],
39
+ status: @options[:status] || 'success',
40
+ duration_ms: @options[:duration_ms],
41
+ detail: @options[:detail],
42
+ created_at: @options[:created_at] || Time.now.utc.iso8601
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Audit
6
+ module Transport
7
+ module Queues
8
+ class Audit < Legion::Transport::Queue
9
+ def queue_name
10
+ 'audit.log'
11
+ end
12
+
13
+ def queue_options
14
+ {
15
+ arguments: {
16
+ 'x-single-active-consumer': true,
17
+ 'x-dead-letter-exchange': 'audit.dlx'
18
+ },
19
+ auto_delete: false
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Audit
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/audit/version'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Audit
8
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
9
+
10
+ def self.data_required?
11
+ true
12
+ end
13
+
14
+ def data_required?
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-audit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Esity
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rake
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rubocop
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rubocop-rspec
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: sequel
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: sqlite3
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ description: Immutable audit logging with SHA-256 hash chain for LegionIO execution
97
+ decisions
98
+ email:
99
+ - matthewdiverson@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".github/workflows/ci.yml"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
107
+ - CHANGELOG.md
108
+ - CLAUDE.md
109
+ - Gemfile
110
+ - Gemfile.lock
111
+ - README.md
112
+ - lex-audit.gemspec
113
+ - lib/legion/extensions/audit.rb
114
+ - lib/legion/extensions/audit/actors/audit_writer.rb
115
+ - lib/legion/extensions/audit/runners/audit.rb
116
+ - lib/legion/extensions/audit/transport/exchanges/audit.rb
117
+ - lib/legion/extensions/audit/transport/messages/audit.rb
118
+ - lib/legion/extensions/audit/transport/queues/audit.rb
119
+ - lib/legion/extensions/audit/version.rb
120
+ homepage: https://github.com/LegionIO/lex-audit
121
+ licenses:
122
+ - MIT
123
+ metadata:
124
+ homepage_uri: https://github.com/LegionIO/lex-audit
125
+ source_code_uri: https://github.com/LegionIO/lex-audit
126
+ changelog_uri: https://github.com/LegionIO/lex-audit/blob/main/CHANGELOG.md
127
+ documentation_uri: https://github.com/LegionIO/lex-audit
128
+ bug_tracker_uri: https://github.com/LegionIO/lex-audit/issues
129
+ rubygems_mfa_required: 'true'
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '3.4'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubygems_version: 3.6.9
145
+ specification_version: 4
146
+ summary: Legion::Extensions::Audit
147
+ test_files: []