lex-identity 0.2.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 +7 -0
- data/Gemfile +8 -0
- data/lex-identity.gemspec +30 -0
- data/lib/legion/extensions/identity/actors/orphan_check.rb +48 -0
- data/lib/legion/extensions/identity/client.rb +23 -0
- data/lib/legion/extensions/identity/helpers/dimensions.rb +71 -0
- data/lib/legion/extensions/identity/helpers/fingerprint.rb +166 -0
- data/lib/legion/extensions/identity/helpers/vault_secrets.rb +76 -0
- data/lib/legion/extensions/identity/local_migrations/20260316000030_create_fingerprint.rb +20 -0
- data/lib/legion/extensions/identity/runners/entra.rb +223 -0
- data/lib/legion/extensions/identity/runners/identity.rb +86 -0
- data/lib/legion/extensions/identity/version.rb +9 -0
- data/lib/legion/extensions/identity.rb +24 -0
- data/spec/legion/extensions/identity/actors/orphan_check_spec.rb +104 -0
- data/spec/legion/extensions/identity/client_spec.rb +32 -0
- data/spec/legion/extensions/identity/helpers/dimensions_spec.rb +51 -0
- data/spec/legion/extensions/identity/helpers/fingerprint_spec.rb +66 -0
- data/spec/legion/extensions/identity/runners/entra_spec.rb +405 -0
- data/spec/legion/extensions/identity/runners/identity_spec.rb +61 -0
- data/spec/local_persistence_spec.rb +329 -0
- data/spec/spec_helper.rb +33 -0
- metadata +95 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Local persistence spec for Legion::Extensions::Identity::Helpers::Fingerprint
|
|
4
|
+
#
|
|
5
|
+
# Strategy: stub Legion::Data::Local with a real in-memory Sequel SQLite database
|
|
6
|
+
# when sequel + sqlite3 are available, otherwise use a double that records calls.
|
|
7
|
+
# Either way, the Fingerprint save/load logic is exercised end-to-end.
|
|
8
|
+
|
|
9
|
+
begin
|
|
10
|
+
require 'sequel'
|
|
11
|
+
require 'sqlite3'
|
|
12
|
+
SEQUEL_AVAILABLE = true
|
|
13
|
+
rescue LoadError
|
|
14
|
+
SEQUEL_AVAILABLE = false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
RSpec.describe Legion::Extensions::Identity::Helpers::Fingerprint, 'local persistence' do
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Helpers for setting up the in-memory DB (shared between contexts)
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
def build_in_memory_db
|
|
23
|
+
db = Sequel.sqlite
|
|
24
|
+
db.create_table(:identity_fingerprint) do
|
|
25
|
+
primary_key :id
|
|
26
|
+
String :dimension, null: false, unique: true
|
|
27
|
+
Float :mean, default: 0.0
|
|
28
|
+
Float :variance, default: 0.0
|
|
29
|
+
Integer :observations, default: 0
|
|
30
|
+
DateTime :last_observed
|
|
31
|
+
end
|
|
32
|
+
db.create_table(:identity_meta) do
|
|
33
|
+
primary_key :id
|
|
34
|
+
Integer :observation_count, default: 0
|
|
35
|
+
String :entropy_history, text: true
|
|
36
|
+
end
|
|
37
|
+
db
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def stub_local(db)
|
|
41
|
+
local_mod = Module.new do
|
|
42
|
+
define_singleton_method(:connection) { db }
|
|
43
|
+
define_singleton_method(:connected?) { true }
|
|
44
|
+
end
|
|
45
|
+
stub_const('Legion::Data', Module.new)
|
|
46
|
+
stub_const('Legion::Data::Local', local_mod)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# When Sequel + sqlite3 are available: full round-trip integration tests
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
if SEQUEL_AVAILABLE
|
|
54
|
+
context 'with an in-memory SQLite database' do
|
|
55
|
+
let(:db) { build_in_memory_db }
|
|
56
|
+
|
|
57
|
+
before { stub_local(db) }
|
|
58
|
+
|
|
59
|
+
describe '#save_to_local' do
|
|
60
|
+
it 'returns true on first save' do
|
|
61
|
+
fp = described_class.new
|
|
62
|
+
expect(fp.save_to_local).to be true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'persists all 6 dimension rows to identity_fingerprint' do
|
|
66
|
+
fp = described_class.new
|
|
67
|
+
fp.observe(:communication_cadence, 0.8)
|
|
68
|
+
fp.save_to_local
|
|
69
|
+
|
|
70
|
+
rows = db[:identity_fingerprint].all
|
|
71
|
+
expect(rows.size).to eq(6)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'persists updated mean for observed dimension' do
|
|
75
|
+
fp = described_class.new
|
|
76
|
+
10.times { fp.observe(:vocabulary_patterns, 0.9) }
|
|
77
|
+
fp.save_to_local
|
|
78
|
+
|
|
79
|
+
row = db[:identity_fingerprint].where(dimension: 'vocabulary_patterns').first
|
|
80
|
+
expect(row[:mean]).to be > 0.5
|
|
81
|
+
expect(row[:observations]).to eq(10)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'persists observation_count in identity_meta' do
|
|
85
|
+
fp = described_class.new
|
|
86
|
+
3.times { fp.observe(:communication_cadence, 0.6) }
|
|
87
|
+
fp.save_to_local
|
|
88
|
+
|
|
89
|
+
meta = db[:identity_meta].first
|
|
90
|
+
expect(meta[:observation_count]).to eq(3)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'persists entropy_history as JSON in identity_meta' do
|
|
94
|
+
fp = described_class.new
|
|
95
|
+
fp.current_entropy(communication_cadence: 0.5)
|
|
96
|
+
fp.current_entropy(vocabulary_patterns: 0.6)
|
|
97
|
+
fp.save_to_local
|
|
98
|
+
|
|
99
|
+
meta = db[:identity_meta].first
|
|
100
|
+
parsed = JSON.parse(meta[:entropy_history])
|
|
101
|
+
expect(parsed.size).to eq(2)
|
|
102
|
+
expect(parsed.first).to have_key('entropy')
|
|
103
|
+
expect(parsed.first).to have_key('at')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'updates existing rows on second save (upsert)' do
|
|
107
|
+
fp = described_class.new
|
|
108
|
+
fp.observe(:emotional_response, 0.3)
|
|
109
|
+
fp.save_to_local
|
|
110
|
+
|
|
111
|
+
# mutate and save again
|
|
112
|
+
5.times { fp.observe(:emotional_response, 0.9) }
|
|
113
|
+
fp.save_to_local
|
|
114
|
+
|
|
115
|
+
rows = db[:identity_fingerprint].where(dimension: 'emotional_response').all
|
|
116
|
+
expect(rows.size).to eq(1) # still one row, not two
|
|
117
|
+
expect(rows.first[:observations]).to eq(6)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
describe '#load_from_local' do
|
|
122
|
+
it 'returns true when called with an empty DB' do
|
|
123
|
+
fp = described_class.new # load_from_local called in initialize
|
|
124
|
+
expect(fp.observation_count).to eq(0)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'restores model dimensions from DB rows' do
|
|
128
|
+
# Pre-seed DB directly
|
|
129
|
+
db[:identity_fingerprint].insert(
|
|
130
|
+
dimension: 'communication_cadence',
|
|
131
|
+
mean: 0.75, variance: 0.05, observations: 42,
|
|
132
|
+
last_observed: Time.now.utc
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
fp = described_class.new # triggers load_from_local
|
|
136
|
+
expect(fp.model[:communication_cadence][:mean]).to be_within(0.001).of(0.75)
|
|
137
|
+
expect(fp.model[:communication_cadence][:observations]).to eq(42)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'restores observation_count from identity_meta' do
|
|
141
|
+
db[:identity_meta].insert(observation_count: 57, entropy_history: '[]')
|
|
142
|
+
|
|
143
|
+
fp = described_class.new
|
|
144
|
+
expect(fp.observation_count).to eq(57)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'restores entropy_history from identity_meta JSON' do
|
|
148
|
+
history = [
|
|
149
|
+
{ 'entropy' => 0.3, 'at' => Time.now.utc.iso8601 },
|
|
150
|
+
{ 'entropy' => 0.4, 'at' => Time.now.utc.iso8601 }
|
|
151
|
+
]
|
|
152
|
+
db[:identity_meta].insert(observation_count: 0, entropy_history: JSON.generate(history))
|
|
153
|
+
|
|
154
|
+
fp = described_class.new
|
|
155
|
+
expect(fp.entropy_history.size).to eq(2)
|
|
156
|
+
expect(fp.entropy_history.first[:entropy]).to be_within(0.001).of(0.3)
|
|
157
|
+
expect(fp.entropy_history.first[:at]).to be_a(Time)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'ignores DB rows for unknown dimensions' do
|
|
161
|
+
db[:identity_fingerprint].insert(
|
|
162
|
+
dimension: 'nonexistent_dimension',
|
|
163
|
+
mean: 0.9, variance: 0.1, observations: 5,
|
|
164
|
+
last_observed: nil
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
fp = described_class.new # must not raise
|
|
168
|
+
expect(fp.model.keys).to match_array(
|
|
169
|
+
%i[communication_cadence vocabulary_patterns emotional_response
|
|
170
|
+
decision_patterns contextual_consistency temporal_patterns]
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
describe 'full round-trip' do
|
|
176
|
+
it 'survives a save-then-load cycle with identical state' do
|
|
177
|
+
# Build state in first fingerprint instance
|
|
178
|
+
fp1 = described_class.new
|
|
179
|
+
12.times { fp1.observe(:communication_cadence, 0.7) }
|
|
180
|
+
8.times { fp1.observe(:vocabulary_patterns, 0.6) }
|
|
181
|
+
fp1.current_entropy(communication_cadence: 0.65)
|
|
182
|
+
fp1.current_entropy(vocabulary_patterns: 0.55)
|
|
183
|
+
fp1.save_to_local
|
|
184
|
+
|
|
185
|
+
# Load into a fresh instance (DB already populated)
|
|
186
|
+
fp2 = described_class.new
|
|
187
|
+
|
|
188
|
+
expect(fp2.observation_count).to eq(fp1.observation_count)
|
|
189
|
+
expect(fp2.entropy_history.size).to eq(fp1.entropy_history.size)
|
|
190
|
+
|
|
191
|
+
dims = %i[communication_cadence vocabulary_patterns]
|
|
192
|
+
dims.each do |dim|
|
|
193
|
+
expect(fp2.model[dim][:mean]).to be_within(0.0001).of(fp1.model[dim][:mean])
|
|
194
|
+
expect(fp2.model[dim][:variance]).to be_within(0.0001).of(fp1.model[dim][:variance])
|
|
195
|
+
expect(fp2.model[dim][:observations]).to eq(fp1.model[dim][:observations])
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it 'preserves maturity after round-trip' do
|
|
200
|
+
fp1 = described_class.new
|
|
201
|
+
15.times { fp1.observe(:decision_patterns, 0.5) }
|
|
202
|
+
expect(fp1.maturity).to eq(:developing)
|
|
203
|
+
fp1.save_to_local
|
|
204
|
+
|
|
205
|
+
fp2 = described_class.new
|
|
206
|
+
expect(fp2.maturity).to eq(:developing)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it 'preserves entropy trend direction after round-trip' do
|
|
210
|
+
fp1 = described_class.new
|
|
211
|
+
# Ascending entropy values — second half larger than first half
|
|
212
|
+
[0.1, 0.1, 0.1, 0.1, 0.7, 0.8, 0.9, 0.95, 0.98, 1.0].each do |e|
|
|
213
|
+
fp1.instance_variable_get(:@entropy_history) << { entropy: e, at: Time.now.utc }
|
|
214
|
+
end
|
|
215
|
+
fp1.save_to_local
|
|
216
|
+
|
|
217
|
+
fp2 = described_class.new
|
|
218
|
+
expect(fp2.entropy_history.map { |h| h[:entropy] }).to eq(
|
|
219
|
+
fp1.entropy_history.map { |h| h[:entropy] }
|
|
220
|
+
)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
else
|
|
226
|
+
# ---------------------------------------------------------------------------
|
|
227
|
+
# Fallback: double-based tests when Sequel is not in the bundle
|
|
228
|
+
# ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
context 'when Sequel is not available (double-based fallback)' do
|
|
231
|
+
let(:fingerprint_rows) { {} }
|
|
232
|
+
let(:meta_rows) { [] }
|
|
233
|
+
|
|
234
|
+
let(:fp_dataset) do
|
|
235
|
+
d = double('fingerprint_dataset')
|
|
236
|
+
allow(d).to receive(:where) { |args|
|
|
237
|
+
scoped = double('scoped_fp_dataset')
|
|
238
|
+
allow(scoped).to receive(:first) { fingerprint_rows[args[:dimension]] }
|
|
239
|
+
allow(scoped).to receive(:update) { |row|
|
|
240
|
+
fingerprint_rows[row[:dimension] || args[:dimension]] = row
|
|
241
|
+
}
|
|
242
|
+
scoped
|
|
243
|
+
}
|
|
244
|
+
allow(d).to receive(:insert) { |row| fingerprint_rows[row[:dimension]] = row }
|
|
245
|
+
allow(d).to receive(:each) { |&block| fingerprint_rows.each_value(&block) }
|
|
246
|
+
allow(d).to receive(:first) { fingerprint_rows.values.first }
|
|
247
|
+
d
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
let(:meta_dataset) do
|
|
251
|
+
d = double('meta_dataset')
|
|
252
|
+
allow(d).to receive(:first) { meta_rows.first }
|
|
253
|
+
allow(d).to receive(:insert) { |row| meta_rows << row }
|
|
254
|
+
allow(d).to receive(:where) do
|
|
255
|
+
scoped = double('scoped_meta_dataset')
|
|
256
|
+
allow(scoped).to receive(:update) { |row| meta_rows[0] = meta_rows[0]&.merge(row) }
|
|
257
|
+
scoped
|
|
258
|
+
end
|
|
259
|
+
d
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
let(:db) do
|
|
263
|
+
d = double('Sequel::Database')
|
|
264
|
+
allow(d).to receive(:[]).with(:identity_fingerprint).and_return(fp_dataset)
|
|
265
|
+
allow(d).to receive(:[]).with(:identity_meta).and_return(meta_dataset)
|
|
266
|
+
d
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
before do
|
|
270
|
+
local_mod = Module.new do
|
|
271
|
+
define_singleton_method(:connection) { nil } # overridden per example
|
|
272
|
+
define_singleton_method(:connected?) { true }
|
|
273
|
+
end
|
|
274
|
+
stub_const('Legion::Data', Module.new)
|
|
275
|
+
stub_const('Legion::Data::Local', local_mod)
|
|
276
|
+
allow(Legion::Data::Local).to receive(:connection).and_return(db)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'calls insert on the fingerprint dataset during save_to_local' do
|
|
280
|
+
fp = described_class.new
|
|
281
|
+
expect(fp_dataset).to receive(:insert).at_least(:once)
|
|
282
|
+
fp.save_to_local
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it 'calls insert on the meta dataset during save_to_local' do
|
|
286
|
+
fp = described_class.new
|
|
287
|
+
expect(meta_dataset).to receive(:insert).once
|
|
288
|
+
fp.save_to_local
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
it 'does not raise when local is unavailable (Legion::Data::Local not defined)' do
|
|
292
|
+
# Remove the stub so defined? check returns false
|
|
293
|
+
hide_const('Legion::Data::Local')
|
|
294
|
+
expect { described_class.new }.not_to raise_error
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# ---------------------------------------------------------------------------
|
|
300
|
+
# Behaviour when Legion::Data::Local is not defined (always run)
|
|
301
|
+
# ---------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
describe 'when Legion::Data::Local is not available' do
|
|
304
|
+
before do
|
|
305
|
+
hide_const('Legion::Data::Local') if defined?(Legion::Data::Local)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'initialize completes without error' do
|
|
309
|
+
expect { described_class.new }.not_to raise_error
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it 'save_to_local returns nil (guard short-circuits)' do
|
|
313
|
+
fp = described_class.new
|
|
314
|
+
expect(fp.save_to_local).to be_nil
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it 'load_from_local returns nil (guard short-circuits)' do
|
|
318
|
+
fp = described_class.new
|
|
319
|
+
expect(fp.load_from_local).to be_nil
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
it 'model starts with fresh defaults' do
|
|
323
|
+
fp = described_class.new
|
|
324
|
+
expect(fp.model[:communication_cadence][:mean]).to eq(0.5)
|
|
325
|
+
expect(fp.observation_count).to eq(0)
|
|
326
|
+
expect(fp.entropy_history).to be_empty
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
|
|
5
|
+
# Stub framework classes not available outside the full Legion runtime
|
|
6
|
+
module Legion
|
|
7
|
+
module Logging
|
|
8
|
+
def self.debug(_msg); end
|
|
9
|
+
|
|
10
|
+
def self.info(_msg); end
|
|
11
|
+
|
|
12
|
+
def self.warn(_msg); end
|
|
13
|
+
|
|
14
|
+
def self.error(_msg); end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module Extensions
|
|
18
|
+
module Actors
|
|
19
|
+
class Every; end # rubocop:disable Lint/EmptyClass
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Prevent re-require of actor base when identity.rb loads orphan_check
|
|
25
|
+
$LOADED_FEATURES << 'legion/extensions/actors/every'
|
|
26
|
+
|
|
27
|
+
require 'legion/extensions/identity'
|
|
28
|
+
|
|
29
|
+
RSpec.configure do |config|
|
|
30
|
+
config.example_status_persistence_file_path = '.rspec_status'
|
|
31
|
+
config.disable_monkey_patching!
|
|
32
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-identity
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.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: sequel
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '5.70'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '5.70'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: sqlite3
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.0'
|
|
40
|
+
description: Human partner identity modeling and behavioral entropy for brain-modeled
|
|
41
|
+
agentic AI
|
|
42
|
+
email:
|
|
43
|
+
- matthewdiverson@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- Gemfile
|
|
49
|
+
- lex-identity.gemspec
|
|
50
|
+
- lib/legion/extensions/identity.rb
|
|
51
|
+
- lib/legion/extensions/identity/actors/orphan_check.rb
|
|
52
|
+
- lib/legion/extensions/identity/client.rb
|
|
53
|
+
- lib/legion/extensions/identity/helpers/dimensions.rb
|
|
54
|
+
- lib/legion/extensions/identity/helpers/fingerprint.rb
|
|
55
|
+
- lib/legion/extensions/identity/helpers/vault_secrets.rb
|
|
56
|
+
- lib/legion/extensions/identity/local_migrations/20260316000030_create_fingerprint.rb
|
|
57
|
+
- lib/legion/extensions/identity/runners/entra.rb
|
|
58
|
+
- lib/legion/extensions/identity/runners/identity.rb
|
|
59
|
+
- lib/legion/extensions/identity/version.rb
|
|
60
|
+
- spec/legion/extensions/identity/actors/orphan_check_spec.rb
|
|
61
|
+
- spec/legion/extensions/identity/client_spec.rb
|
|
62
|
+
- spec/legion/extensions/identity/helpers/dimensions_spec.rb
|
|
63
|
+
- spec/legion/extensions/identity/helpers/fingerprint_spec.rb
|
|
64
|
+
- spec/legion/extensions/identity/runners/entra_spec.rb
|
|
65
|
+
- spec/legion/extensions/identity/runners/identity_spec.rb
|
|
66
|
+
- spec/local_persistence_spec.rb
|
|
67
|
+
- spec/spec_helper.rb
|
|
68
|
+
homepage: https://github.com/LegionIO/lex-identity
|
|
69
|
+
licenses:
|
|
70
|
+
- MIT
|
|
71
|
+
metadata:
|
|
72
|
+
homepage_uri: https://github.com/LegionIO/lex-identity
|
|
73
|
+
source_code_uri: https://github.com/LegionIO/lex-identity
|
|
74
|
+
documentation_uri: https://github.com/LegionIO/lex-identity
|
|
75
|
+
changelog_uri: https://github.com/LegionIO/lex-identity
|
|
76
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-identity/issues
|
|
77
|
+
rubygems_mfa_required: 'true'
|
|
78
|
+
rdoc_options: []
|
|
79
|
+
require_paths:
|
|
80
|
+
- lib
|
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '3.4'
|
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
requirements: []
|
|
92
|
+
rubygems_version: 3.6.9
|
|
93
|
+
specification_version: 4
|
|
94
|
+
summary: LEX Identity
|
|
95
|
+
test_files: []
|