declarative_policy 2.0.1 → 2.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 +4 -4
- data/CHANGELOG.md +2 -0
- data/README.md +15 -1
- data/declarative-policy.gemspec +1 -1
- data/doc/defining-policies.md +36 -0
- data/lib/declarative_policy/base.rb +24 -5
- data/lib/declarative_policy/policy_dsl.rb +8 -2
- data/lib/declarative_policy/prevent_all_dsl.rb +25 -0
- data/lib/declarative_policy/version.rb +1 -1
- data/lib/declarative_policy.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 05f875265a827bd025947cd0098d09804051cf0fa2c02857aa230e03d8554f02
|
|
4
|
+
data.tar.gz: 38452f2308ad61d9cf54bb604f68cbdd73cb75d342ea24a55c265ee708f588b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 82ac859206da667fb45b59662aa9a35fb760f59179e0976f9e7ed9ffba92259ba271fa6732ec9b84e3e14e14961f1362fb13077deb7191c75436c83ef60ab342
|
|
7
|
+
data.tar.gz: c9e41debc20ab2ecc2dc8da44c2e782f50e58ec7d9cba23986c5494c7c00d334de82a3f6f2c9a5b35739a402ecc097f144cb05314ab8584f07aa46dab548b6c0
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -202,6 +202,20 @@ https://gitlab.com/gitlab-org/ruby/gems/declarative-policy. This project is inte
|
|
|
202
202
|
a safe, welcoming space for collaboration, and contributors are expected to
|
|
203
203
|
adhere to the [GitLab code of conduct](https://about.gitlab.com/community/contribute/code-of-conduct/).
|
|
204
204
|
|
|
205
|
+
## Release process
|
|
206
|
+
|
|
207
|
+
We release `declarative_policy` on an ad-hoc basis. There is no regularity to when
|
|
208
|
+
we release, we just release when we make a change - no matter the size of the
|
|
209
|
+
change.
|
|
210
|
+
|
|
211
|
+
To release a new version:
|
|
212
|
+
|
|
213
|
+
1. Create a Merge Request.
|
|
214
|
+
1. Use Merge Request template [Release.md](https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/blob/main/.gitlab/merge_request_templates/Release.md).
|
|
215
|
+
1. Follow the instructions.
|
|
216
|
+
1. After the Merge Request has been merged, a new gem version is [published automatically](https://gitlab.com/gitlab-org/components/gem-release).
|
|
217
|
+
1. Once the new gem version is visible on [RubyGems.org](https://rubygems.org/gems/declarative_policy), it is recommended to update [GitLab's `Gemfile`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/Gemfile) to bump the `declarative_policy` Ruby gem to the new version also.
|
|
218
|
+
|
|
205
219
|
## License
|
|
206
220
|
|
|
207
221
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -210,4 +224,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
210
224
|
|
|
211
225
|
Everyone interacting in the `DeclarativePolicy` project's codebase, issue
|
|
212
226
|
trackers, chat rooms and mailing lists is expected to follow
|
|
213
|
-
the [code of conduct](https://
|
|
227
|
+
the [code of conduct](https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/blob/main/CODE_OF_CONDUCT.md).
|
data/declarative-policy.gemspec
CHANGED
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
|
|
24
24
|
spec.metadata['homepage_uri'] = spec.homepage
|
|
25
25
|
spec.metadata['source_code_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/declarative-policy'
|
|
26
|
-
spec.metadata['changelog_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/
|
|
26
|
+
spec.metadata['changelog_uri'] = 'https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/releases'
|
|
27
27
|
|
|
28
28
|
spec.metadata['rubygems_mfa_required'] = 'false'
|
|
29
29
|
|
data/doc/defining-policies.md
CHANGED
|
@@ -124,6 +124,42 @@ rule { old_enough_to_drive }.policy do
|
|
|
124
124
|
end
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
#### `prevent_all`
|
|
128
|
+
|
|
129
|
+
To prevent all abilities at once, use `prevent_all`:
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
rule { banned }.prevent_all
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This is equivalent to adding a `prevent` for every ability in the policy. It is
|
|
136
|
+
commonly used to deny all access when a precondition fails (e.g. a user is
|
|
137
|
+
suspended or a resource is locked).
|
|
138
|
+
|
|
139
|
+
#### `prevent_all` with exceptions
|
|
140
|
+
|
|
141
|
+
To prevent all abilities **except** specific ones, pass a block with `except`
|
|
142
|
+
declarations:
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
rule { suspended }.prevent_all do
|
|
146
|
+
except :read
|
|
147
|
+
except :appeal_suspension
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Multiple abilities can also be listed in a single `except` call:
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
rule { suspended }.prevent_all do
|
|
155
|
+
except :read, :list, :appeal_suspension
|
|
156
|
+
end
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Excepted abilities are excluded from the blanket prevent and follow normal
|
|
160
|
+
enable/prevent evaluation. Non-excepted abilities are prevented when the rule's
|
|
161
|
+
condition holds, regardless of any `enable` rules.
|
|
162
|
+
|
|
127
163
|
Rule blocks do not have access to the internal state of the policy, and cannot
|
|
128
164
|
access the `@user` or `@subject`, or any methods on the policy instance. You
|
|
129
165
|
should not perform I/O in a rule. They exist solely to define the logical rules
|
|
@@ -113,9 +113,15 @@ module DeclarativePolicy
|
|
|
113
113
|
|
|
114
114
|
# all the [rule, action] pairs that apply to a particular ability.
|
|
115
115
|
# we combine the specific ones looked up in ability_map with the global
|
|
116
|
-
# ones.
|
|
116
|
+
# ones, filtering out any global actions that have excepted this ability.
|
|
117
117
|
def configuration_for(ability)
|
|
118
|
-
|
|
118
|
+
applicable_globals = global_actions.filter_map do |(action, rule, exceptions)|
|
|
119
|
+
next if exceptions&.include?(ability)
|
|
120
|
+
|
|
121
|
+
[action, rule]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
ability_map.actions(ability) + applicable_globals
|
|
119
125
|
end
|
|
120
126
|
|
|
121
127
|
### declaration methods ###
|
|
@@ -215,8 +221,10 @@ module DeclarativePolicy
|
|
|
215
221
|
|
|
216
222
|
# we store global prevents (from `prevent_all`) separately,
|
|
217
223
|
# so that they can be combined into every decision made.
|
|
218
|
-
|
|
219
|
-
|
|
224
|
+
# The optional `except` parameter is a Set of abilities
|
|
225
|
+
# that should be excluded from the blanket prevent.
|
|
226
|
+
def prevent_all_when(rule, except: nil)
|
|
227
|
+
own_global_actions << [:prevent, rule, except]
|
|
220
228
|
end
|
|
221
229
|
|
|
222
230
|
private
|
|
@@ -255,6 +263,8 @@ module DeclarativePolicy
|
|
|
255
263
|
# This is the main entry point for permission checks. It constructs
|
|
256
264
|
# or looks up a Runner for the given ability and asks it if it passes.
|
|
257
265
|
def allowed?(*abilities)
|
|
266
|
+
return false if abilities.empty?
|
|
267
|
+
|
|
258
268
|
abilities.all? { |a| runner(a).pass? }
|
|
259
269
|
end
|
|
260
270
|
|
|
@@ -351,8 +361,17 @@ module DeclarativePolicy
|
|
|
351
361
|
|
|
352
362
|
# used in specs - returns true if there is no possible way for any action
|
|
353
363
|
# to be allowed, determined only by the global :prevent_all rules.
|
|
364
|
+
# Only considers global actions with no exceptions (a prevent_all with
|
|
365
|
+
# exceptions cannot fully ban, since the excepted abilities may still pass).
|
|
354
366
|
def banned?
|
|
355
|
-
global_steps = self.class.global_actions.
|
|
367
|
+
global_steps = self.class.global_actions.filter_map do |(action, rule, exceptions)|
|
|
368
|
+
next if exceptions && !exceptions.empty?
|
|
369
|
+
|
|
370
|
+
Step.new(self, rule, action)
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
return false if global_steps.empty?
|
|
374
|
+
|
|
356
375
|
!Runner.new(global_steps).pass?
|
|
357
376
|
end
|
|
358
377
|
|
|
@@ -29,8 +29,14 @@ module DeclarativePolicy
|
|
|
29
29
|
@context_class.prevent_when(abilities, @rule)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def prevent_all
|
|
33
|
-
|
|
32
|
+
def prevent_all(&block)
|
|
33
|
+
if block
|
|
34
|
+
dsl = PreventAllDsl.new
|
|
35
|
+
dsl.instance_eval(&block)
|
|
36
|
+
@context_class.prevent_all_when(@rule, except: dsl.exceptions)
|
|
37
|
+
else
|
|
38
|
+
@context_class.prevent_all_when(@rule)
|
|
39
|
+
end
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
def method_missing(msg, ...)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module DeclarativePolicy
|
|
6
|
+
# A small DSL class used within a prevent_all { ... } block
|
|
7
|
+
# to capture exception abilities.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# rule { some_condition }.prevent_all do
|
|
11
|
+
# except :read
|
|
12
|
+
# except :list
|
|
13
|
+
# end
|
|
14
|
+
class PreventAllDsl
|
|
15
|
+
attr_reader :exceptions
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@exceptions = Set.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def except(*abilities)
|
|
22
|
+
@exceptions.merge(abilities)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/declarative_policy.rb
CHANGED
|
@@ -4,6 +4,7 @@ require 'set'
|
|
|
4
4
|
require_relative 'declarative_policy/cache'
|
|
5
5
|
require_relative 'declarative_policy/condition'
|
|
6
6
|
require_relative 'declarative_policy/delegate_dsl'
|
|
7
|
+
require_relative 'declarative_policy/prevent_all_dsl'
|
|
7
8
|
require_relative 'declarative_policy/policy_dsl'
|
|
8
9
|
require_relative 'declarative_policy/rule_dsl'
|
|
9
10
|
require_relative 'declarative_policy/preferred_scope'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: declarative_policy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- group::authorization
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: benchmark-ips
|
|
@@ -140,6 +140,7 @@ files:
|
|
|
140
140
|
- lib/declarative_policy/nil_policy.rb
|
|
141
141
|
- lib/declarative_policy/policy_dsl.rb
|
|
142
142
|
- lib/declarative_policy/preferred_scope.rb
|
|
143
|
+
- lib/declarative_policy/prevent_all_dsl.rb
|
|
143
144
|
- lib/declarative_policy/rule.rb
|
|
144
145
|
- lib/declarative_policy/rule_dsl.rb
|
|
145
146
|
- lib/declarative_policy/runner.rb
|
|
@@ -151,7 +152,7 @@ licenses:
|
|
|
151
152
|
metadata:
|
|
152
153
|
homepage_uri: https://gitlab.com/gitlab-org/ruby/gems/declarative-policy
|
|
153
154
|
source_code_uri: https://gitlab.com/gitlab-org/ruby/gems/declarative-policy
|
|
154
|
-
changelog_uri: https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/
|
|
155
|
+
changelog_uri: https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/releases
|
|
155
156
|
rubygems_mfa_required: 'false'
|
|
156
157
|
post_install_message:
|
|
157
158
|
rdoc_options: []
|