legion-rbac 0.2.6 → 0.2.8
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/.github/CODEOWNERS +7 -0
- data/.github/dependabot.yml +18 -0
- data/.github/workflows/ci.yml +20 -2
- data/CHANGELOG.md +10 -0
- data/legion-rbac.gemspec +1 -1
- data/lib/legion/rbac/routes.rb +260 -0
- data/lib/legion/rbac/version.rb +1 -1
- data/lib/legion/rbac.rb +11 -0
- metadata +6 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59a7e721e473fdb1e65fe31d2da68e7fc7fc0a65e2e077f199f62c98aaf78fb5
|
|
4
|
+
data.tar.gz: b59c16e31ab6f63b1f93947a6c47ba59c891c2275a4f73463f892f4c0a71d9a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8431ff82ad752660da99454b4170999572d2c37259fe33605238fc4faa6fdabe3d5c50a29dfc0d40c2fb45225107e457f15ac1e14aa0d8c41f6985cb39aa855
|
|
7
|
+
data.tar.gz: aafee7d9c8e9a3a07974aae8b890a8120dda0a10906a45ec1e967745563db0c2eed90ae39d2e14603d383df900ef450add66484d00cd4254288c573d976a47f2
|
data/.github/CODEOWNERS
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: bundler
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
day: monday
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
labels:
|
|
10
|
+
- "type:dependencies"
|
|
11
|
+
- package-ecosystem: github-actions
|
|
12
|
+
directory: /
|
|
13
|
+
schedule:
|
|
14
|
+
interval: weekly
|
|
15
|
+
day: monday
|
|
16
|
+
open-pull-requests-limit: 5
|
|
17
|
+
labels:
|
|
18
|
+
- "type:dependencies"
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -3,14 +3,32 @@ on:
|
|
|
3
3
|
push:
|
|
4
4
|
branches: [main]
|
|
5
5
|
pull_request:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: '0 9 * * 1'
|
|
6
8
|
|
|
7
9
|
jobs:
|
|
8
10
|
ci:
|
|
9
11
|
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
10
12
|
|
|
13
|
+
lint:
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/lint-patterns.yml@main
|
|
15
|
+
|
|
16
|
+
security:
|
|
17
|
+
uses: LegionIO/.github/.github/workflows/security-scan.yml@main
|
|
18
|
+
|
|
19
|
+
version-changelog:
|
|
20
|
+
uses: LegionIO/.github/.github/workflows/version-changelog.yml@main
|
|
21
|
+
|
|
22
|
+
dependency-review:
|
|
23
|
+
uses: LegionIO/.github/.github/workflows/dependency-review.yml@main
|
|
24
|
+
|
|
25
|
+
stale:
|
|
26
|
+
if: github.event_name == 'schedule'
|
|
27
|
+
uses: LegionIO/.github/.github/workflows/stale.yml@main
|
|
28
|
+
|
|
11
29
|
release:
|
|
12
|
-
needs: ci
|
|
30
|
+
needs: [ci, lint]
|
|
13
31
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
14
32
|
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
15
33
|
secrets:
|
|
16
|
-
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
|
34
|
+
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.8] - 2026-03-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Legion::Rbac::Routes` self-registering Sinatra route module (`lib/legion/rbac/routes.rb`): extracts all `/api/rbac/*` route handlers from LegionIO. Self-registers with `Legion::API.register_library_routes('rbac', Routes)` during boot. Includes fallback helpers for standalone mounting.
|
|
7
|
+
|
|
8
|
+
## [0.2.7] - 2026-03-22
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Corrected legion-settings version constraint to `>= 1.3.12`
|
|
12
|
+
|
|
3
13
|
## [0.2.6] - 2026-03-22
|
|
4
14
|
|
|
5
15
|
### Changed
|
data/legion-rbac.gemspec
CHANGED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Self-registering route module for legion-rbac.
|
|
4
|
+
# All routes previously defined in LegionIO/lib/legion/api/rbac.rb now live here
|
|
5
|
+
# and are mounted via Legion::API.register_library_routes when legion-rbac boots.
|
|
6
|
+
#
|
|
7
|
+
# LegionIO/lib/legion/api/rbac.rb is preserved for backward compatibility but guards
|
|
8
|
+
# its registration with defined?(Legion::Rbac::Routes) so double-registration is avoided.
|
|
9
|
+
|
|
10
|
+
module Legion
|
|
11
|
+
module Rbac
|
|
12
|
+
module Routes
|
|
13
|
+
def self.registered(app)
|
|
14
|
+
app.helpers do # rubocop:disable Metrics/BlockLength
|
|
15
|
+
unless method_defined?(:parse_request_body)
|
|
16
|
+
define_method(:parse_request_body) do
|
|
17
|
+
raw = request.body.read
|
|
18
|
+
return {} if raw.nil? || raw.empty?
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
parsed = Legion::JSON.load(raw)
|
|
22
|
+
rescue StandardError
|
|
23
|
+
halt 400, { 'Content-Type' => 'application/json' },
|
|
24
|
+
Legion::JSON.dump({ error: { code: 'invalid_json', message: 'request body is not valid JSON' } })
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
unless parsed.respond_to?(:transform_keys)
|
|
28
|
+
halt 400, { 'Content-Type' => 'application/json' },
|
|
29
|
+
Legion::JSON.dump({ error: { code: 'invalid_request_body',
|
|
30
|
+
message: 'request body must be a JSON object' } })
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
parsed.transform_keys(&:to_sym)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
unless method_defined?(:json_response)
|
|
38
|
+
define_method(:json_response) do |data, status_code: 200|
|
|
39
|
+
content_type :json
|
|
40
|
+
status status_code
|
|
41
|
+
Legion::JSON.dump({ data: data })
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
unless method_defined?(:json_error)
|
|
46
|
+
define_method(:json_error) do |code, message, status_code: 400|
|
|
47
|
+
content_type :json
|
|
48
|
+
status status_code
|
|
49
|
+
Legion::JSON.dump({ error: { code: code, message: message } })
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
unless method_defined?(:json_collection)
|
|
54
|
+
define_method(:json_collection) do |dataset|
|
|
55
|
+
content_type :json
|
|
56
|
+
Legion::JSON.dump({ data: dataset.all.map(&:values) })
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
unless method_defined?(:current_owner_msid)
|
|
61
|
+
define_method(:current_owner_msid) do
|
|
62
|
+
env['legion.owner_msid']
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
register_roles(app)
|
|
68
|
+
register_check(app)
|
|
69
|
+
register_assignments(app)
|
|
70
|
+
register_grants(app)
|
|
71
|
+
register_cross_team_grants(app)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.register_roles(app)
|
|
75
|
+
app.get '/api/rbac/roles' do
|
|
76
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
77
|
+
|
|
78
|
+
roles = Legion::Rbac.role_index.transform_values do |role|
|
|
79
|
+
{ name: role.name, description: role.description, cross_team: role.cross_team? }
|
|
80
|
+
end
|
|
81
|
+
json_response(roles)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
app.get '/api/rbac/roles/:name' do
|
|
85
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
86
|
+
|
|
87
|
+
role = Legion::Rbac.role_index[params[:name].to_sym]
|
|
88
|
+
halt 404, json_error('not_found', "Role #{params[:name]} not found", status_code: 404) unless role
|
|
89
|
+
|
|
90
|
+
json_response({
|
|
91
|
+
name: role.name,
|
|
92
|
+
description: role.description,
|
|
93
|
+
cross_team: role.cross_team?,
|
|
94
|
+
permissions: role.permissions.map { |p| { resource: p.resource_pattern, actions: p.actions } },
|
|
95
|
+
deny_rules: role.deny_rules.map { |d| { resource: d.resource_pattern, above_level: d.above_level } }
|
|
96
|
+
})
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.register_check(app)
|
|
101
|
+
app.post '/api/rbac/check' do
|
|
102
|
+
Legion::Logging.debug "API: POST /api/rbac/check params=#{params.keys}" if defined?(Legion::Logging)
|
|
103
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
104
|
+
|
|
105
|
+
body = parse_request_body
|
|
106
|
+
principal = Legion::Rbac::Principal.new(
|
|
107
|
+
id: body[:principal] || 'anonymous',
|
|
108
|
+
roles: body[:roles] || [],
|
|
109
|
+
team: body[:team]
|
|
110
|
+
)
|
|
111
|
+
result = Legion::Rbac::PolicyEngine.evaluate(
|
|
112
|
+
principal: principal,
|
|
113
|
+
action: body[:action] || 'read',
|
|
114
|
+
resource: body[:resource] || '*',
|
|
115
|
+
enforce: false
|
|
116
|
+
)
|
|
117
|
+
json_response(result)
|
|
118
|
+
rescue StandardError => e
|
|
119
|
+
Legion::Logging.error "API POST /api/rbac/check: #{e.class} — #{e.message}" if defined?(Legion::Logging)
|
|
120
|
+
json_error('rbac_error', e.message, status_code: 500)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.register_assignments(app) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
125
|
+
app.get '/api/rbac/assignments' do
|
|
126
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
127
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
128
|
+
|
|
129
|
+
dataset = Legion::Data::Model::RbacRoleAssignment.order(:id)
|
|
130
|
+
dataset = dataset.where(team: params[:team]) if params[:team]
|
|
131
|
+
dataset = dataset.where(role: params[:role]) if params[:role]
|
|
132
|
+
dataset = dataset.where(principal_id: params[:principal]) if params[:principal]
|
|
133
|
+
json_collection(dataset)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
app.post '/api/rbac/assignments' do
|
|
137
|
+
Legion::Logging.debug "API: POST /api/rbac/assignments params=#{params.keys}" if defined?(Legion::Logging)
|
|
138
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
139
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
140
|
+
|
|
141
|
+
body = parse_request_body
|
|
142
|
+
record = Legion::Data::Model::RbacRoleAssignment.create(
|
|
143
|
+
principal_type: body[:principal_type] || 'human',
|
|
144
|
+
principal_id: body[:principal_id],
|
|
145
|
+
role: body[:role],
|
|
146
|
+
team: body[:team],
|
|
147
|
+
granted_by: current_owner_msid || 'api',
|
|
148
|
+
expires_at: body[:expires_at] ? Time.parse(body[:expires_at]) : nil
|
|
149
|
+
)
|
|
150
|
+
Legion::Logging.info "API: created RBAC assignment #{record.id} role=#{body[:role]} principal=#{body[:principal_id]}" if defined?(Legion::Logging)
|
|
151
|
+
json_response(record.values, status_code: 201)
|
|
152
|
+
rescue Sequel::ValidationFailed => e
|
|
153
|
+
Legion::Logging.warn "API POST /api/rbac/assignments returned 422: #{e.message}" if defined?(Legion::Logging)
|
|
154
|
+
json_error('validation_error', e.message, status_code: 422)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
app.delete '/api/rbac/assignments/:id' do
|
|
158
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
159
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
160
|
+
|
|
161
|
+
record = Legion::Data::Model::RbacRoleAssignment[params[:id].to_i]
|
|
162
|
+
halt 404, json_error('not_found', 'Assignment not found', status_code: 404) unless record
|
|
163
|
+
|
|
164
|
+
record.destroy
|
|
165
|
+
Legion::Logging.info "API: deleted RBAC assignment #{params[:id]}" if defined?(Legion::Logging)
|
|
166
|
+
json_response({ deleted: true })
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def self.register_grants(app)
|
|
171
|
+
app.get '/api/rbac/grants' do
|
|
172
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
173
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
174
|
+
|
|
175
|
+
dataset = Legion::Data::Model::RbacRunnerGrant.order(:id)
|
|
176
|
+
dataset = dataset.where(team: params[:team]) if params[:team]
|
|
177
|
+
json_collection(dataset)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
app.post '/api/rbac/grants' do
|
|
181
|
+
Legion::Logging.debug "API: POST /api/rbac/grants params=#{params.keys}" if defined?(Legion::Logging)
|
|
182
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
183
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
184
|
+
|
|
185
|
+
body = parse_request_body
|
|
186
|
+
record = Legion::Data::Model::RbacRunnerGrant.create(
|
|
187
|
+
team: body[:team],
|
|
188
|
+
runner_pattern: body[:runner_pattern],
|
|
189
|
+
actions: Array(body[:actions]).join(','),
|
|
190
|
+
granted_by: current_owner_msid || 'api'
|
|
191
|
+
)
|
|
192
|
+
Legion::Logging.info "API: created RBAC grant #{record.id} team=#{body[:team]} pattern=#{body[:runner_pattern]}" if defined?(Legion::Logging)
|
|
193
|
+
json_response(record.values, status_code: 201)
|
|
194
|
+
rescue Sequel::ValidationFailed => e
|
|
195
|
+
Legion::Logging.warn "API POST /api/rbac/grants returned 422: #{e.message}" if defined?(Legion::Logging)
|
|
196
|
+
json_error('validation_error', e.message, status_code: 422)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
app.delete '/api/rbac/grants/:id' do
|
|
200
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
201
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
202
|
+
|
|
203
|
+
record = Legion::Data::Model::RbacRunnerGrant[params[:id].to_i]
|
|
204
|
+
halt 404, json_error('not_found', 'Grant not found', status_code: 404) unless record
|
|
205
|
+
|
|
206
|
+
record.destroy
|
|
207
|
+
Legion::Logging.info "API: deleted RBAC grant #{params[:id]}" if defined?(Legion::Logging)
|
|
208
|
+
json_response({ deleted: true })
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def self.register_cross_team_grants(app)
|
|
213
|
+
app.get '/api/rbac/grants/cross-team' do
|
|
214
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
215
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
216
|
+
|
|
217
|
+
dataset = Legion::Data::Model::RbacCrossTeamGrant.order(:id)
|
|
218
|
+
json_collection(dataset)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
app.post '/api/rbac/grants/cross-team' do
|
|
222
|
+
Legion::Logging.debug "API: POST /api/rbac/grants/cross-team params=#{params.keys}" if defined?(Legion::Logging)
|
|
223
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
224
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
225
|
+
|
|
226
|
+
body = parse_request_body
|
|
227
|
+
record = Legion::Data::Model::RbacCrossTeamGrant.create(
|
|
228
|
+
source_team: body[:source_team],
|
|
229
|
+
target_team: body[:target_team],
|
|
230
|
+
runner_pattern: body[:runner_pattern],
|
|
231
|
+
actions: Array(body[:actions]).join(','),
|
|
232
|
+
granted_by: current_owner_msid || 'api',
|
|
233
|
+
expires_at: body[:expires_at] ? Time.parse(body[:expires_at]) : nil
|
|
234
|
+
)
|
|
235
|
+
Legion::Logging.info "API: created cross-team RBAC grant #{record.id} #{body[:source_team]}->#{body[:target_team]}" if defined?(Legion::Logging)
|
|
236
|
+
json_response(record.values, status_code: 201)
|
|
237
|
+
rescue Sequel::ValidationFailed => e
|
|
238
|
+
Legion::Logging.warn "API POST /api/rbac/grants/cross-team returned 422: #{e.message}" if defined?(Legion::Logging)
|
|
239
|
+
json_error('validation_error', e.message, status_code: 422)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
app.delete '/api/rbac/grants/cross-team/:id' do
|
|
243
|
+
return json_error('rbac_unavailable', 'legion-rbac not installed', status_code: 501) unless defined?(Legion::Rbac)
|
|
244
|
+
return json_error('db_unavailable', 'legion-data not connected', status_code: 503) unless Legion::Rbac::Store.db_available?
|
|
245
|
+
|
|
246
|
+
record = Legion::Data::Model::RbacCrossTeamGrant[params[:id].to_i]
|
|
247
|
+
halt 404, json_error('not_found', 'Grant not found', status_code: 404) unless record
|
|
248
|
+
|
|
249
|
+
record.destroy
|
|
250
|
+
Legion::Logging.info "API: deleted cross-team RBAC grant #{params[:id]}" if defined?(Legion::Logging)
|
|
251
|
+
json_response({ deleted: true })
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
class << self
|
|
256
|
+
private :register_roles, :register_check, :register_assignments, :register_grants, :register_cross_team_grants
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
data/lib/legion/rbac/version.rb
CHANGED
data/lib/legion/rbac.rb
CHANGED
|
@@ -11,6 +11,7 @@ require 'legion/rbac/team_scope'
|
|
|
11
11
|
require 'legion/rbac/store'
|
|
12
12
|
require 'legion/rbac/entra_claims_mapper'
|
|
13
13
|
require 'legion/rbac/middleware'
|
|
14
|
+
require 'legion/rbac/routes'
|
|
14
15
|
|
|
15
16
|
module Legion
|
|
16
17
|
module Rbac
|
|
@@ -26,10 +27,20 @@ module Legion
|
|
|
26
27
|
class << self
|
|
27
28
|
attr_reader :role_index
|
|
28
29
|
|
|
30
|
+
def register_routes
|
|
31
|
+
return unless defined?(Legion::API) && Legion::API.respond_to?(:register_library_routes)
|
|
32
|
+
|
|
33
|
+
Legion::API.register_library_routes('rbac', Legion::Rbac::Routes)
|
|
34
|
+
Legion::Logging.debug 'Legion::Rbac routes registered with API' if defined?(Legion::Logging)
|
|
35
|
+
rescue StandardError => e
|
|
36
|
+
Legion::Logging.warn "Legion::Rbac route registration failed: #{e.message}" if defined?(Legion::Logging)
|
|
37
|
+
end
|
|
38
|
+
|
|
29
39
|
def setup
|
|
30
40
|
Legion::Settings.merge_settings(:rbac, Legion::Rbac::Settings.default)
|
|
31
41
|
@role_index = ConfigLoader.load_roles
|
|
32
42
|
Legion::Settings[:rbac][:connected] = true
|
|
43
|
+
register_routes
|
|
33
44
|
end
|
|
34
45
|
|
|
35
46
|
def shutdown
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-rbac
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 1.3.
|
|
32
|
+
version: 1.3.12
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 1.3.
|
|
39
|
+
version: 1.3.12
|
|
40
40
|
description: Role-based access control for LegionIO with team scoping and policy enforcement
|
|
41
41
|
email:
|
|
42
42
|
- matthewdiverson@gmail.com
|
|
@@ -47,6 +47,8 @@ extra_rdoc_files:
|
|
|
47
47
|
- LICENSE
|
|
48
48
|
- README.md
|
|
49
49
|
files:
|
|
50
|
+
- ".github/CODEOWNERS"
|
|
51
|
+
- ".github/dependabot.yml"
|
|
50
52
|
- ".github/workflows/ci.yml"
|
|
51
53
|
- ".gitignore"
|
|
52
54
|
- ".rspec"
|
|
@@ -67,6 +69,7 @@ files:
|
|
|
67
69
|
- lib/legion/rbac/policy_engine.rb
|
|
68
70
|
- lib/legion/rbac/principal.rb
|
|
69
71
|
- lib/legion/rbac/role.rb
|
|
72
|
+
- lib/legion/rbac/routes.rb
|
|
70
73
|
- lib/legion/rbac/settings.rb
|
|
71
74
|
- lib/legion/rbac/store.rb
|
|
72
75
|
- lib/legion/rbac/team_scope.rb
|