lex-kerberos 0.1.0 → 0.1.2
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 +4 -4
- data/CHANGELOG.md +19 -0
- data/CLAUDE.md +3 -3
- data/README.md +5 -2
- data/lib/legion/extensions/kerberos/helpers/ldap.rb +22 -6
- data/lib/legion/extensions/kerberos/runners/authenticate.rb +13 -20
- data/lib/legion/extensions/kerberos/version.rb +1 -1
- metadata +1 -2
- data/Gemfile.lock +0 -159
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 69c3dd5c8ef68a25cc39f06b412e3b9f07854e02643ef44bf2f1082965c72d62
|
|
4
|
+
data.tar.gz: 0d1b20b4dfc12d31e21a9a00c14be7f76f15ece54a2d8fdb3fcc9703ee76cc46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7663b961a7468ccb52e6133b9d12ab57cb47c086cfe2f6264f3a35f3697340a5725415aeb5d115838d44bb0195b4d8e5cb25ef05b681a3680561d57734ffcae
|
|
7
|
+
data.tar.gz: 27de46aa7005ba6d43a57b0460f2436fecf15a4851a0cccc6f5198efbd82c906d4b9b17f37c8d571a538ba4514ff594a5d5bca614c518050bf735bcd1dca00fb
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.2] - 2026-03-18
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Organizational LDAP attributes: `title`, `department`, `company`, `co`, `c`, `l`, `st`, `cn`, `whenCreated`
|
|
9
|
+
- `PROFILE_MAP` constant maps LDAP attribute names to readable Ruby symbols
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- `USER_ATTRIBUTES` expanded to include organizational fields
|
|
13
|
+
- `extract_profile` uses `PROFILE_MAP` for declarative attribute mapping
|
|
14
|
+
|
|
15
|
+
## [0.1.1] - 2026-03-18
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- LDAP user profile fetching: `givenName`, `sn`, `mail`, `displayName` attributes returned from `lookup_groups`
|
|
19
|
+
- `first_name`, `last_name`, `email`, `display_name` fields in authenticate runner result
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- LDAP search now fetches `USER_ATTRIBUTES` constant (memberOf + profile fields) instead of just group attribute
|
|
23
|
+
|
|
5
24
|
## [0.1.0] - 2026-03-17
|
|
6
25
|
|
|
7
26
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -10,7 +10,7 @@ Legion Extension that provides Kerberos/SPNEGO authentication. Validates SPNEGO
|
|
|
10
10
|
|
|
11
11
|
**GitHub**: https://github.com/LegionIO/lex-kerberos
|
|
12
12
|
**License**: MIT
|
|
13
|
-
**Version**: 0.1.
|
|
13
|
+
**Version**: 0.1.2
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
16
16
|
|
|
@@ -34,13 +34,13 @@ Legion::Extensions::Kerberos
|
|
|
34
34
|
|------|---------|
|
|
35
35
|
| `lib/legion/extensions/kerberos.rb` | Entry point, requires all helpers/runners/actors, extends Core |
|
|
36
36
|
| `lib/legion/extensions/kerberos/helpers/spnego.rb` | GSSAPI token acceptance via `gssapi` gem; `accept_spnego_token`, `extract_username`, `extract_realm` |
|
|
37
|
-
| `lib/legion/extensions/kerberos/helpers/ldap.rb` | LDAP group lookup via `net-ldap`; `lookup_groups`
|
|
37
|
+
| `lib/legion/extensions/kerberos/helpers/ldap.rb` | LDAP group lookup + profile via `net-ldap`; `lookup_groups` returns groups + org attributes via `PROFILE_MAP` |
|
|
38
38
|
| `lib/legion/extensions/kerberos/helpers/keytab.rb` | Multi-source keytab resolution; vault:// URI, file path, Base64 blob; writes to `~/.legionio/kerberos/legion.keytab` |
|
|
39
39
|
| `lib/legion/extensions/kerberos/helpers/client.rb` | `DEFAULTS` constant and `settings` method that merges with `Legion::Settings[:kerberos]` |
|
|
40
40
|
| `lib/legion/extensions/kerberos/runners/authenticate.rb` | `validate_spnego` runner: orchestrates keytab resolve → SPNEGO accept → optional LDAP lookup |
|
|
41
41
|
| `lib/legion/extensions/kerberos/actors/keytab_refresh.rb` | Hourly actor that calls `resolve_keytab` to re-cache from Vault; `run_now? false` (no immediate run at boot) |
|
|
42
42
|
| `lib/legion/extensions/kerberos/client.rb` | Standalone `Client` class with `authenticate(token:)` and `resolve_groups(username:)` |
|
|
43
|
-
| `lib/legion/extensions/kerberos/version.rb` | `VERSION = '0.1.
|
|
43
|
+
| `lib/legion/extensions/kerberos/version.rb` | `VERSION = '0.1.2'` |
|
|
44
44
|
|
|
45
45
|
## Key Patterns
|
|
46
46
|
|
data/README.md
CHANGED
|
@@ -86,9 +86,12 @@ result = client.authenticate(token: token)
|
|
|
86
86
|
# => { success: true, principal: "user@EXAMPLE.COM", username: "user",
|
|
87
87
|
# realm: "EXAMPLE.COM", output_token: "...", ... }
|
|
88
88
|
|
|
89
|
-
# Resolve LDAP groups for a username
|
|
89
|
+
# Resolve LDAP groups and profile for a username
|
|
90
90
|
groups = client.resolve_groups(username: 'user')
|
|
91
|
-
# => { success: true, groups: ["CN=Domain Users,..."], username: "user"
|
|
91
|
+
# => { success: true, groups: ["CN=Domain Users,..."], username: "user",
|
|
92
|
+
# first_name: "Jane", last_name: "Doe", email: "jane.doe@example.com",
|
|
93
|
+
# title: "Senior Engineer", department: "Platform Engineering",
|
|
94
|
+
# company: "Acme Corp", city: "Minneapolis", state: "MN", country: "USA" }
|
|
92
95
|
```
|
|
93
96
|
|
|
94
97
|
### Using helpers directly
|
|
@@ -7,6 +7,17 @@ module Legion
|
|
|
7
7
|
module Kerberos
|
|
8
8
|
module Helpers
|
|
9
9
|
module Ldap
|
|
10
|
+
USER_ATTRIBUTES = %w[
|
|
11
|
+
memberOf givenName sn mail displayName cn
|
|
12
|
+
title department company co c l st whenCreated
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
PROFILE_MAP = {
|
|
16
|
+
first_name: :givenname, last_name: :sn, email: :mail, display_name: :displayname,
|
|
17
|
+
cn: :cn, title: :title, department: :department, company: :company,
|
|
18
|
+
country: :co, country_code: :c, city: :l, state: :st, ad_created_at: :whencreated
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
10
21
|
def lookup_groups(username:, host:, base_dn:, bind_dn:, bind_password:,
|
|
11
22
|
port: 636, encryption: :simple_tls,
|
|
12
23
|
user_filter: '(sAMAccountName=%<username>s)',
|
|
@@ -15,9 +26,8 @@ module Legion
|
|
|
15
26
|
bind_dn: bind_dn, bind_password: bind_password)
|
|
16
27
|
return { success: false, error: 'LDAP bind failed' } unless ldap.bind
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{ success: true, groups: groups, username: username }
|
|
29
|
+
search_user(ldap: ldap, username: username, base_dn: base_dn,
|
|
30
|
+
user_filter: user_filter, group_attribute: group_attribute)
|
|
21
31
|
rescue Net::LDAP::Error => e
|
|
22
32
|
{ success: false, error: "LDAP error: #{e.message}" }
|
|
23
33
|
end
|
|
@@ -32,13 +42,19 @@ module Legion
|
|
|
32
42
|
)
|
|
33
43
|
end
|
|
34
44
|
|
|
35
|
-
def
|
|
45
|
+
def search_user(ldap:, username:, base_dn:, user_filter:, group_attribute:)
|
|
36
46
|
filter = Net::LDAP::Filter.construct(format(user_filter, username: username))
|
|
37
47
|
groups = []
|
|
38
|
-
|
|
48
|
+
profile = {}
|
|
49
|
+
ldap.search(base: base_dn, filter: filter, attributes: USER_ATTRIBUTES) do |entry|
|
|
39
50
|
groups.concat(Array(entry[group_attribute]).map(&:to_s))
|
|
51
|
+
profile = extract_profile(entry)
|
|
40
52
|
end
|
|
41
|
-
groups
|
|
53
|
+
{ success: true, groups: groups, username: username, **profile }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def extract_profile(entry)
|
|
57
|
+
PROFILE_MAP.transform_values { |attr| entry[attr]&.first&.to_s }.compact
|
|
42
58
|
end
|
|
43
59
|
end
|
|
44
60
|
end
|
|
@@ -27,37 +27,30 @@ module Legion
|
|
|
27
27
|
service_principal: service_principal)
|
|
28
28
|
return { result: spnego } unless spnego[:success]
|
|
29
29
|
|
|
30
|
-
groups, ldap_error = resolve_groups(ldap: ldap, cfg: s, username: spnego[:username])
|
|
30
|
+
groups, ldap_error, profile = resolve_groups(ldap: ldap, cfg: s, username: spnego[:username])
|
|
31
31
|
|
|
32
|
-
{ result: build_result(spnego: spnego, groups: groups, ldap_error: ldap_error) }
|
|
32
|
+
{ result: build_result(spnego: spnego, groups: groups, ldap_error: ldap_error, profile: profile) }
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
private
|
|
36
36
|
|
|
37
37
|
def resolve_groups(ldap:, cfg:, username:)
|
|
38
38
|
ldap_opts = ldap || cfg[:ldap] || {}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
return [[], nil, {}] unless ldap_opts[:host]
|
|
40
|
+
|
|
41
|
+
result = lookup_groups(username: username, **ldap_opts)
|
|
42
|
+
if result[:success]
|
|
43
|
+
profile = result.slice(:first_name, :last_name, :email, :display_name)
|
|
44
|
+
[result[:groups], nil, profile]
|
|
43
45
|
else
|
|
44
|
-
|
|
45
|
-
ldap_error = nil
|
|
46
|
+
[[], result[:error], {}]
|
|
46
47
|
end
|
|
47
|
-
[groups, ldap_error]
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def build_result(spnego:, groups:, ldap_error:)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
username: spnego[:username],
|
|
55
|
-
realm: spnego[:realm],
|
|
56
|
-
groups: groups,
|
|
57
|
-
output_token: spnego[:output_token],
|
|
58
|
-
auth_method: 'kerberos',
|
|
59
|
-
ldap_error: ldap_error
|
|
60
|
-
}.compact
|
|
50
|
+
def build_result(spnego:, groups:, ldap_error:, profile: {})
|
|
51
|
+
spnego_fields = spnego.slice(:principal, :username, :realm, :output_token)
|
|
52
|
+
{ success: true, groups: groups, auth_method: 'kerberos',
|
|
53
|
+
ldap_error: ldap_error, **spnego_fields, **profile }.compact
|
|
61
54
|
end
|
|
62
55
|
|
|
63
56
|
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-kerberos
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -50,7 +50,6 @@ files:
|
|
|
50
50
|
- CHANGELOG.md
|
|
51
51
|
- CLAUDE.md
|
|
52
52
|
- Gemfile
|
|
53
|
-
- Gemfile.lock
|
|
54
53
|
- README.md
|
|
55
54
|
- lex-kerberos.gemspec
|
|
56
55
|
- lib/legion/extensions/kerberos.rb
|
data/Gemfile.lock
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
lex-kerberos (0.1.0)
|
|
5
|
-
gssapi (~> 1.3)
|
|
6
|
-
net-ldap (~> 0.19)
|
|
7
|
-
|
|
8
|
-
GEM
|
|
9
|
-
remote: https://rubygems.org/
|
|
10
|
-
specs:
|
|
11
|
-
addressable (2.8.9)
|
|
12
|
-
public_suffix (>= 2.0.2, < 8.0)
|
|
13
|
-
ast (2.4.3)
|
|
14
|
-
base64 (0.3.0)
|
|
15
|
-
bigdecimal (4.0.1)
|
|
16
|
-
diff-lcs (1.6.2)
|
|
17
|
-
docile (1.4.1)
|
|
18
|
-
ffi (1.17.3)
|
|
19
|
-
ffi (1.17.3-aarch64-linux-gnu)
|
|
20
|
-
ffi (1.17.3-aarch64-linux-musl)
|
|
21
|
-
ffi (1.17.3-arm-linux-gnu)
|
|
22
|
-
ffi (1.17.3-arm-linux-musl)
|
|
23
|
-
ffi (1.17.3-arm64-darwin)
|
|
24
|
-
ffi (1.17.3-x86-linux-gnu)
|
|
25
|
-
ffi (1.17.3-x86-linux-musl)
|
|
26
|
-
ffi (1.17.3-x86_64-darwin)
|
|
27
|
-
ffi (1.17.3-x86_64-linux-gnu)
|
|
28
|
-
ffi (1.17.3-x86_64-linux-musl)
|
|
29
|
-
gssapi (1.3.1)
|
|
30
|
-
ffi (>= 1.0.1)
|
|
31
|
-
json (2.19.1)
|
|
32
|
-
json-schema (6.2.0)
|
|
33
|
-
addressable (~> 2.8)
|
|
34
|
-
bigdecimal (>= 3.1, < 5)
|
|
35
|
-
language_server-protocol (3.17.0.5)
|
|
36
|
-
lint_roller (1.1.0)
|
|
37
|
-
mcp (0.8.0)
|
|
38
|
-
json-schema (>= 4.1)
|
|
39
|
-
net-ldap (0.20.0)
|
|
40
|
-
base64
|
|
41
|
-
ostruct
|
|
42
|
-
ostruct (0.6.3)
|
|
43
|
-
parallel (1.27.0)
|
|
44
|
-
parser (3.3.10.2)
|
|
45
|
-
ast (~> 2.4.1)
|
|
46
|
-
racc
|
|
47
|
-
prism (1.9.0)
|
|
48
|
-
public_suffix (7.0.5)
|
|
49
|
-
racc (1.8.1)
|
|
50
|
-
rainbow (3.1.1)
|
|
51
|
-
regexp_parser (2.11.3)
|
|
52
|
-
rspec (3.13.2)
|
|
53
|
-
rspec-core (~> 3.13.0)
|
|
54
|
-
rspec-expectations (~> 3.13.0)
|
|
55
|
-
rspec-mocks (~> 3.13.0)
|
|
56
|
-
rspec-core (3.13.6)
|
|
57
|
-
rspec-support (~> 3.13.0)
|
|
58
|
-
rspec-expectations (3.13.5)
|
|
59
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
60
|
-
rspec-support (~> 3.13.0)
|
|
61
|
-
rspec-mocks (3.13.8)
|
|
62
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
63
|
-
rspec-support (~> 3.13.0)
|
|
64
|
-
rspec-support (3.13.7)
|
|
65
|
-
rubocop (1.85.1)
|
|
66
|
-
json (~> 2.3)
|
|
67
|
-
language_server-protocol (~> 3.17.0.2)
|
|
68
|
-
lint_roller (~> 1.1.0)
|
|
69
|
-
mcp (~> 0.6)
|
|
70
|
-
parallel (~> 1.10)
|
|
71
|
-
parser (>= 3.3.0.2)
|
|
72
|
-
rainbow (>= 2.2.2, < 4.0)
|
|
73
|
-
regexp_parser (>= 2.9.3, < 3.0)
|
|
74
|
-
rubocop-ast (>= 1.49.0, < 2.0)
|
|
75
|
-
ruby-progressbar (~> 1.7)
|
|
76
|
-
unicode-display_width (>= 2.4.0, < 4.0)
|
|
77
|
-
rubocop-ast (1.49.1)
|
|
78
|
-
parser (>= 3.3.7.2)
|
|
79
|
-
prism (~> 1.7)
|
|
80
|
-
ruby-progressbar (1.13.0)
|
|
81
|
-
simplecov (0.22.0)
|
|
82
|
-
docile (~> 1.1)
|
|
83
|
-
simplecov-html (~> 0.11)
|
|
84
|
-
simplecov_json_formatter (~> 0.1)
|
|
85
|
-
simplecov-html (0.13.2)
|
|
86
|
-
simplecov_json_formatter (0.1.4)
|
|
87
|
-
unicode-display_width (3.2.0)
|
|
88
|
-
unicode-emoji (~> 4.1)
|
|
89
|
-
unicode-emoji (4.2.0)
|
|
90
|
-
|
|
91
|
-
PLATFORMS
|
|
92
|
-
aarch64-linux-gnu
|
|
93
|
-
aarch64-linux-musl
|
|
94
|
-
arm-linux-gnu
|
|
95
|
-
arm-linux-musl
|
|
96
|
-
arm64-darwin
|
|
97
|
-
ruby
|
|
98
|
-
x86-linux-gnu
|
|
99
|
-
x86-linux-musl
|
|
100
|
-
x86_64-darwin
|
|
101
|
-
x86_64-linux-gnu
|
|
102
|
-
x86_64-linux-musl
|
|
103
|
-
|
|
104
|
-
DEPENDENCIES
|
|
105
|
-
lex-kerberos!
|
|
106
|
-
rspec (~> 3.13)
|
|
107
|
-
rubocop (~> 1.75)
|
|
108
|
-
simplecov (~> 0.22)
|
|
109
|
-
|
|
110
|
-
CHECKSUMS
|
|
111
|
-
addressable (2.8.9) sha256=cc154fcbe689711808a43601dee7b980238ce54368d23e127421753e46895485
|
|
112
|
-
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
113
|
-
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
114
|
-
bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
|
|
115
|
-
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
|
116
|
-
docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
|
|
117
|
-
ffi (1.17.3) sha256=0e9f39f7bb3934f77ad6feab49662be77e87eedcdeb2a3f5c0234c2938563d4c
|
|
118
|
-
ffi (1.17.3-aarch64-linux-gnu) sha256=28ad573df26560f0aedd8a90c3371279a0b2bd0b4e834b16a2baa10bd7a97068
|
|
119
|
-
ffi (1.17.3-aarch64-linux-musl) sha256=020b33b76775b1abacc3b7d86b287cef3251f66d747092deec592c7f5df764b2
|
|
120
|
-
ffi (1.17.3-arm-linux-gnu) sha256=5bd4cea83b68b5ec0037f99c57d5ce2dd5aa438f35decc5ef68a7d085c785668
|
|
121
|
-
ffi (1.17.3-arm-linux-musl) sha256=0d7626bb96265f9af78afa33e267d71cfef9d9a8eb8f5525344f8da6c7d76053
|
|
122
|
-
ffi (1.17.3-arm64-darwin) sha256=0c690555d4cee17a7f07c04d59df39b2fba74ec440b19da1f685c6579bb0717f
|
|
123
|
-
ffi (1.17.3-x86-linux-gnu) sha256=868a88fcaf5186c3a46b7c7c2b2c34550e1e61a405670ab23f5b6c9971529089
|
|
124
|
-
ffi (1.17.3-x86-linux-musl) sha256=f0286aa6ef40605cf586e61406c446de34397b85dbb08cc99fdaddaef8343945
|
|
125
|
-
ffi (1.17.3-x86_64-darwin) sha256=1f211811eb5cfaa25998322cdd92ab104bfbd26d1c4c08471599c511f2c00bb5
|
|
126
|
-
ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f
|
|
127
|
-
ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56
|
|
128
|
-
gssapi (1.3.1) sha256=c51cf30842ee39bd93ce7fc33e20405ff8a04cda9dec6092071b61258284aee1
|
|
129
|
-
json (2.19.1) sha256=dd94fdc59e48bff85913829a32350b3148156bc4fd2a95a2568a78b11344082d
|
|
130
|
-
json-schema (6.2.0) sha256=e8bff46ed845a22c1ab2bd0d7eccf831c01fe23bb3920caa4c74db4306813666
|
|
131
|
-
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
132
|
-
lex-kerberos (0.1.0)
|
|
133
|
-
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
134
|
-
mcp (0.8.0) sha256=ae8bd146bb8e168852866fd26f805f52744f6326afb3211e073f78a95e0c34fb
|
|
135
|
-
net-ldap (0.20.0) sha256=b2080b350753a9ac4930869ded8e61a1d2151c01e03b0bf07b4675cbd9ce5372
|
|
136
|
-
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
|
|
137
|
-
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
|
138
|
-
parser (3.3.10.2) sha256=6f60c84aa4bdcedb6d1a2434b738fe8a8136807b6adc8f7f53b97da9bc4e9357
|
|
139
|
-
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
140
|
-
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
|
|
141
|
-
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
142
|
-
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
143
|
-
regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
|
|
144
|
-
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
|
|
145
|
-
rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
|
|
146
|
-
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
|
147
|
-
rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
|
|
148
|
-
rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
|
|
149
|
-
rubocop (1.85.1) sha256=3dbcf9e961baa4c376eeeb2a03913dca5e3987033b04d38fa538aa1e7406cc77
|
|
150
|
-
rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
|
|
151
|
-
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
152
|
-
simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
|
|
153
|
-
simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
|
|
154
|
-
simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
|
|
155
|
-
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
156
|
-
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
157
|
-
|
|
158
|
-
BUNDLED WITH
|
|
159
|
-
4.0.8
|