hubbado-policy 1.1.1 → 1.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 +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +60 -2
- data/hubbado-policy.gemspec +1 -1
- data/lib/hubbado/policy/controls/policy.rb +18 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10ac3df17852150db0027d21e4fda49038083e6d825e41227a225864322df576
|
4
|
+
data.tar.gz: 0d303a7756e82512635a6a323939df1f794766cef2182cf405f07e72b96ad4d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83232ddd7a934bf3a3381dccfe785be182ef6d03e2fd519bc006f1a17a07c0006b87c1d0e4dd58d442b5739350edf0e6f0ae9153a88676da3a5fcb74f8b5e94f
|
7
|
+
data.tar.gz: 8086d8d2ecbbe4df566560a0d36ebad2c1010b000d70c10bb703fc6c0b0d6c1ea5fd7a8017c70dd940951676090b2afa5ab10b80e02274e109e1152a5c4da231
|
data/CHANGELOG.md
CHANGED
@@ -5,14 +5,32 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [1.2.0] - 2025-05-27
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Policy control is improved:
|
13
|
+
- When using a policy control you could permit or deny with a method
|
14
|
+
```ruby
|
15
|
+
mimic_policy = Control::Policies::ArticlePolicy.example
|
16
|
+
mimic_policy.permit(:view)
|
17
|
+
# or
|
18
|
+
mimic_policy.deny(:view)
|
19
|
+
mimic_policy.deny(:view, :a_reason) # with a reason
|
20
|
+
mimic_policy.deny(:view, data: :custom_data) # with data
|
21
|
+
mimic_policy.deny(:view, :a_reason, data: :custom_data) # or both
|
22
|
+
```
|
23
|
+
|
8
24
|
## [1.1.1] - 2025-05-26
|
9
25
|
|
10
26
|
### Fixed
|
27
|
+
|
11
28
|
- Railtie is corrected with an initializer to load I18n locales correctly.
|
12
29
|
|
13
30
|
## [1.1.0] - 2025-05-20
|
14
31
|
|
15
32
|
### Added
|
33
|
+
|
16
34
|
- Control to mimic policies
|
17
35
|
|
18
36
|
## [1.0.1] - 2025-05-20
|
@@ -22,6 +40,7 @@ Bump because rubygems does not allow repushing the same version even if it is ya
|
|
22
40
|
## [1.0.0] - 2025-05-20
|
23
41
|
|
24
42
|
### Added
|
43
|
+
|
25
44
|
- Initial release of the hubbado-policy gem
|
26
45
|
- `Policy` class with DSL for defining authorization rules
|
27
46
|
- `Result` class to represent policy outcomes
|
@@ -31,6 +50,7 @@ Bump because rubygems does not allow repushing the same version even if it is ya
|
|
31
50
|
- Full compatibility with the eventide-project/dependency gem
|
32
51
|
|
33
52
|
### Documentation
|
53
|
+
|
34
54
|
- Comprehensive README with usage examples
|
35
55
|
- Detailed explanations of all major components
|
36
56
|
- Rails integration guide
|
data/README.md
CHANGED
@@ -152,11 +152,24 @@ module Control
|
|
152
152
|
end
|
153
153
|
|
154
154
|
mimic_policy = Control::Policies::ArticlePolicy.example
|
155
|
-
mimic_policy.view? # returns
|
156
|
-
|
155
|
+
mimic_policy.view? # returns false (denied by default)
|
157
156
|
|
157
|
+
# Override specific policies
|
158
158
|
mimic_policy = Control::Policies::ArticlePolicy.example(view: ArticlePolicy.denied)
|
159
159
|
mimic_policy.view? # returns false
|
160
|
+
|
161
|
+
# Control policy behavior with permit/deny methods
|
162
|
+
mimic_policy = Control::Policies::ArticlePolicy.example
|
163
|
+
mimic_policy.permit(:view)
|
164
|
+
mimic_policy.view? # returns true
|
165
|
+
|
166
|
+
mimic_policy.deny(:view)
|
167
|
+
mimic_policy.view? # returns false
|
168
|
+
|
169
|
+
# Deny with reason and data
|
170
|
+
mimic_policy.deny(:view, :not_authorized)
|
171
|
+
mimic_policy.deny(:view, data: { reason: "custom data" })
|
172
|
+
mimic_policy.deny(:view, :not_authorized, data: { user_id: 123 })
|
160
173
|
```
|
161
174
|
|
162
175
|
## Result Objects
|
@@ -190,18 +203,55 @@ end
|
|
190
203
|
- `message` - Returns the localized error message
|
191
204
|
- `data` - Returns any additional context data
|
192
205
|
|
206
|
+
### Error Handling
|
207
|
+
|
208
|
+
Policies validate their inputs and will raise errors for invalid usage:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
# Will raise "User not provided" error
|
212
|
+
ArticlePolicy.build(nil, article)
|
213
|
+
|
214
|
+
# Control policies raise UnkownPolicy for invalid policy names
|
215
|
+
mimic_policy = Control::Policies::ArticlePolicy.example
|
216
|
+
mimic_policy.permit(:invalid_policy) # raises UnkownPolicy
|
217
|
+
```
|
218
|
+
|
219
|
+
### Accessing Result Data
|
220
|
+
|
221
|
+
When policies return additional context data, you can access it through the result:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
# In your policy
|
225
|
+
define_policy :edit do
|
226
|
+
return denied(:quota_exceeded, data: { limit: 10, current: 12 }) if over_quota?
|
227
|
+
permitted
|
228
|
+
end
|
229
|
+
|
230
|
+
# Using the result
|
231
|
+
result = policy.edit
|
232
|
+
if result.denied?
|
233
|
+
puts result.message # "You have exceeded your quota"
|
234
|
+
puts result.data[:limit] # 10
|
235
|
+
puts result.data[:current] # 12
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
193
239
|
## Scope Objects
|
194
240
|
|
195
241
|
Scope objects filter collections based on what a user is authorized to access.
|
196
242
|
|
197
243
|
### Basic Usage
|
198
244
|
|
245
|
+
Scope objects require two template methods to be implemented in subclasses:
|
246
|
+
|
199
247
|
```ruby
|
200
248
|
class ArticleScope < Hubbado::Policy::Scope
|
249
|
+
# Required: Define the base collection to filter
|
201
250
|
def self.default_scope
|
202
251
|
Article.all
|
203
252
|
end
|
204
253
|
|
254
|
+
# Required: Implement the filtering logic
|
205
255
|
def resolve(record, scope, **options)
|
206
256
|
return scope if record.admin?
|
207
257
|
|
@@ -213,6 +263,14 @@ end
|
|
213
263
|
visible_articles = ArticleScope.call(current_user)
|
214
264
|
```
|
215
265
|
|
266
|
+
**Required Methods:**
|
267
|
+
- `default_scope` - Class method that returns the base collection to filter
|
268
|
+
- `resolve(record, scope, **options)` - Instance method that applies filtering logic
|
269
|
+
|
270
|
+
Both methods must be implemented or a `MethodMissing` error will be raised.
|
271
|
+
|
272
|
+
**Important:** Like policies, use `Scope.call()` instead of manual instantiation to ensure the `configure` method is called if defined.
|
273
|
+
|
216
274
|
### Custom Scopes
|
217
275
|
|
218
276
|
You can pass custom base scopes:
|
data/hubbado-policy.gemspec
CHANGED
@@ -2,6 +2,8 @@ module Hubbado
|
|
2
2
|
module Policy
|
3
3
|
module Controls
|
4
4
|
class Policy
|
5
|
+
UnkownPolicy = Class.new(StandardError)
|
6
|
+
|
5
7
|
def self.mimic(policy_class)
|
6
8
|
policy_class.policies.each do |policy|
|
7
9
|
send(:attr_writer, policy)
|
@@ -14,6 +16,22 @@ module Hubbado
|
|
14
16
|
send(policy).permitted?
|
15
17
|
end
|
16
18
|
end
|
19
|
+
|
20
|
+
define_method :permit do |policy|
|
21
|
+
unless policy_class.instance_variable_get("@policies").include?(policy)
|
22
|
+
raise UnkownPolicy
|
23
|
+
end
|
24
|
+
|
25
|
+
send("#{policy}=", policy_class.permitted)
|
26
|
+
end
|
27
|
+
|
28
|
+
define_method :deny do |policy, reason = nil, data: nil|
|
29
|
+
unless policy_class.instance_variable_get("@policies").include?(policy)
|
30
|
+
raise UnkownPolicy
|
31
|
+
end
|
32
|
+
|
33
|
+
send("#{policy}=", policy_class.denied(reason, data: data))
|
34
|
+
end
|
17
35
|
end
|
18
36
|
|
19
37
|
def initialize(policies = {})
|