pundit 2.0.0 → 2.1.1
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/.gitignore +1 -0
- data/.rubocop.yml +15 -51
- data/.travis.yml +18 -14
- data/CHANGELOG.md +56 -3
- data/Gemfile +2 -11
- data/LICENSE.txt +1 -1
- data/README.md +36 -16
- data/Rakefile +2 -0
- data/lib/generators/pundit/install/install_generator.rb +4 -2
- data/lib/generators/pundit/install/templates/application_policy.rb +6 -2
- data/lib/generators/pundit/policy/policy_generator.rb +4 -2
- data/lib/generators/rspec/policy_generator.rb +4 -2
- data/lib/generators/rspec/templates/policy_spec.rb +1 -1
- data/lib/generators/test_unit/policy_generator.rb +4 -2
- data/lib/pundit/policy_finder.rb +3 -1
- data/lib/pundit/rspec.rb +6 -14
- data/lib/pundit/version.rb +1 -1
- data/lib/pundit.rb +33 -19
- data/pundit.gemspec +13 -2
- data/spec/policies/post_policy_spec.rb +3 -1
- data/spec/policy_finder_spec.rb +82 -17
- data/spec/pundit_spec.rb +78 -25
- data/spec/spec_helper.rb +34 -23
- metadata +130 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: def6c710d9f9d1705ca43cdad9364bb34ce5d878b8a3a9bf26d336802e40efeb
|
|
4
|
+
data.tar.gz: 0d6618cb61dfef8ae18f811a73b3f059d9945f8def7f9b2f794ae095b3a0f0cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7105cd0a84469071de9211e19f7e7a31f4ea8b5283d7b1ed007b6533805de18d105c09128a9936144612f3daa8fadfdf0698f7448d8db94e47bb459efaa11c4b
|
|
7
|
+
data.tar.gz: 3805e2664f21f30c66e9a9a05606f0d0d18b1607137e794948c7907bd33c6d6e64a45b9abb97d2f1a21df0d46497ff708679442807e152fa167abc461c8c0abe
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
|
|
3
|
-
TargetRubyVersion: 2.1
|
|
2
|
+
TargetRubyVersion: 2.6
|
|
4
3
|
Exclude:
|
|
5
|
-
- "
|
|
6
|
-
- "vendor/**/*"
|
|
7
|
-
- "lib/generators/**/*"
|
|
4
|
+
- "lib/generators/**/templates/**/*"
|
|
8
5
|
|
|
9
6
|
Metrics/BlockLength:
|
|
10
7
|
Exclude:
|
|
@@ -30,33 +27,9 @@ Metrics/CyclomaticComplexity:
|
|
|
30
27
|
Metrics/PerceivedComplexity:
|
|
31
28
|
Enabled: false
|
|
32
29
|
|
|
33
|
-
Style/StructInheritance:
|
|
34
|
-
Enabled: false
|
|
35
|
-
|
|
36
30
|
Layout/AlignParameters:
|
|
37
31
|
EnforcedStyle: with_fixed_indentation
|
|
38
32
|
|
|
39
|
-
Style/StringLiterals:
|
|
40
|
-
EnforcedStyle: double_quotes
|
|
41
|
-
|
|
42
|
-
Style/StringLiteralsInInterpolation:
|
|
43
|
-
EnforcedStyle: double_quotes
|
|
44
|
-
|
|
45
|
-
Layout/ClosingParenthesisIndentation:
|
|
46
|
-
Enabled: false
|
|
47
|
-
|
|
48
|
-
Style/OneLineConditional:
|
|
49
|
-
Enabled: false
|
|
50
|
-
|
|
51
|
-
Style/AndOr:
|
|
52
|
-
Enabled: false
|
|
53
|
-
|
|
54
|
-
Style/Not:
|
|
55
|
-
Enabled: false
|
|
56
|
-
|
|
57
|
-
Documentation:
|
|
58
|
-
Enabled: false # TODO: Enable again once we have more docs
|
|
59
|
-
|
|
60
33
|
Layout/CaseIndentation:
|
|
61
34
|
EnforcedStyle: case
|
|
62
35
|
SupportedStyles:
|
|
@@ -64,40 +37,31 @@ Layout/CaseIndentation:
|
|
|
64
37
|
- end
|
|
65
38
|
IndentOneStep: true
|
|
66
39
|
|
|
40
|
+
Layout/EndAlignment:
|
|
41
|
+
EnforcedStyleAlignWith: variable
|
|
42
|
+
|
|
67
43
|
Style/PercentLiteralDelimiters:
|
|
68
44
|
PreferredDelimiters:
|
|
69
45
|
'%w': "[]"
|
|
70
46
|
'%W': "[]"
|
|
71
47
|
|
|
72
|
-
|
|
73
|
-
EnforcedStyle:
|
|
74
|
-
|
|
75
|
-
Style/SignalException:
|
|
76
|
-
Enabled: false
|
|
77
|
-
|
|
78
|
-
Layout/IndentationWidth:
|
|
79
|
-
Enabled: false
|
|
80
|
-
|
|
81
|
-
Style/TrivialAccessors:
|
|
82
|
-
ExactNameMatch: true
|
|
83
|
-
|
|
84
|
-
Layout/EndAlignment:
|
|
85
|
-
EnforcedStyleAlignWith: variable
|
|
86
|
-
|
|
87
|
-
Layout/DefEndAlignment:
|
|
88
|
-
Enabled: false
|
|
48
|
+
Style/StringLiterals:
|
|
49
|
+
EnforcedStyle: double_quotes
|
|
89
50
|
|
|
90
|
-
|
|
91
|
-
|
|
51
|
+
Style/StringLiteralsInInterpolation:
|
|
52
|
+
EnforcedStyle: double_quotes
|
|
92
53
|
|
|
93
|
-
Style/
|
|
54
|
+
Style/StructInheritance:
|
|
94
55
|
Enabled: false
|
|
95
56
|
|
|
96
|
-
Style/
|
|
57
|
+
Style/AndOr:
|
|
97
58
|
Enabled: false
|
|
98
59
|
|
|
99
|
-
|
|
60
|
+
Style/Not:
|
|
100
61
|
Enabled: false
|
|
101
62
|
|
|
102
63
|
Style/DoubleNegation:
|
|
103
64
|
Enabled: false
|
|
65
|
+
|
|
66
|
+
Documentation:
|
|
67
|
+
Enabled: false # TODO: Enable again once we have more docs
|
data/.travis.yml
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
-
|
|
3
|
-
before_install:
|
|
4
|
-
- gem update --system
|
|
5
|
-
- gem install bundler
|
|
2
|
+
dist: focal
|
|
6
3
|
|
|
7
4
|
matrix:
|
|
8
5
|
include:
|
|
9
|
-
-
|
|
6
|
+
- name: "RuboCop lint on pre-installed Ruby version"
|
|
7
|
+
rvm: 2.7.1 # Pre-installed Ruby version
|
|
8
|
+
before_install:
|
|
9
|
+
- gem install bundler
|
|
10
10
|
script: bundle exec rake rubocop # ONLY lint once, first
|
|
11
|
-
- rvm: 2.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- rvm:
|
|
11
|
+
- rvm: 2.6.7
|
|
12
|
+
before_script:
|
|
13
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
|
14
|
+
- chmod +x ./cc-test-reporter
|
|
15
|
+
- ./cc-test-reporter before-build
|
|
16
|
+
after_script:
|
|
17
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
|
18
|
+
- rvm: 2.7.3
|
|
19
|
+
- rvm: 3.0.1
|
|
20
|
+
- rvm: jruby-9.2.17.0
|
|
20
21
|
env:
|
|
21
22
|
- JRUBY_OPTS="--debug"
|
|
23
|
+
- rvm: truffleruby-head
|
|
24
|
+
allow_failures:
|
|
25
|
+
- rvm: truffleruby-head
|
data/CHANGELOG.md
CHANGED
|
@@ -1,21 +1,74 @@
|
|
|
1
1
|
# Pundit
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 2.1.1 (2021-08-13)
|
|
6
|
+
|
|
7
|
+
Friday 13th-release!
|
|
8
|
+
|
|
9
|
+
Careful! The bugfix below (#626) could break existing code. If you rely on the
|
|
10
|
+
return value for `authorize` and namespaced policies you might need to do some
|
|
11
|
+
changes.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `.authorize` and `#authorize` return the instance, even for namespaced
|
|
16
|
+
policies (#626)
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Generate application scope with `protected` attr_readers. (#616)
|
|
21
|
+
|
|
22
|
+
### Removed
|
|
23
|
+
|
|
24
|
+
- Dropped support for Ruby end-of-life versions: 2.1 and 2.2. (#604)
|
|
25
|
+
- Dropped support for Ruby end-of-life versions: 2.3 (#633)
|
|
26
|
+
- Dropped support for Ruby end-of-life versions: 2.4, 2.5 and JRuby 9.1 (#676)
|
|
27
|
+
- Dropped support for RSpec 2 (#615)
|
|
28
|
+
|
|
29
|
+
## 2.1.0 (2019-08-14)
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Avoid name clashes with the Error class. (#590)
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Return a safer default NotAuthorizedError message. (#583)
|
|
38
|
+
|
|
39
|
+
## 2.0.1 (2019-01-18)
|
|
40
|
+
|
|
41
|
+
### Breaking changes
|
|
42
|
+
|
|
43
|
+
None
|
|
44
|
+
|
|
45
|
+
### Other changes
|
|
46
|
+
|
|
47
|
+
- Improve exception handling for `#policy_scope` and `#policy_scope!`. (#550)
|
|
48
|
+
- Add `:policy` metadata to RSpec template. (#566)
|
|
49
|
+
|
|
3
50
|
## 2.0.0 (2018-07-21)
|
|
4
51
|
|
|
5
52
|
No changes since beta1
|
|
6
53
|
|
|
7
54
|
## 2.0.0.beta1 (2018-07-04)
|
|
8
55
|
|
|
56
|
+
### Breaking changes
|
|
57
|
+
|
|
58
|
+
- Only pass last element of "namespace array" to policy and scope. (#529)
|
|
59
|
+
- Raise `InvalidConstructorError` if a policy or policy scope with an invalid constructor is called. (#462)
|
|
60
|
+
- Return passed object from `#authorize` method to make chaining possible. (#385)
|
|
61
|
+
|
|
62
|
+
### Other changes
|
|
63
|
+
|
|
9
64
|
- Add `policy_class` option to `authorize` to be able to override the policy. (#441)
|
|
10
65
|
- Add `policy_scope_class` option to `authorize` to be able to override the policy scope. (#441)
|
|
11
66
|
- Fix `param_key` issue when passed an array. (#529)
|
|
12
|
-
- Only pass last element of "namespace array" to policy and scope. (#529)
|
|
13
67
|
- Allow specification of a `NilClassPolicy`. (#525)
|
|
14
68
|
- Make sure `policy_class` override is called when passed an array. (#475)
|
|
15
|
-
|
|
69
|
+
|
|
16
70
|
- Use `action_name` instead of `params[:action]`. (#419)
|
|
17
71
|
- Add `pundit_params_for` method to make it easy to customize params fetching. (#502)
|
|
18
|
-
- Return passed object from `#authorize` method to make chaining possible. (#385)
|
|
19
72
|
|
|
20
73
|
## 1.1.0 (2016-01-14)
|
|
21
74
|
|
data/Gemfile
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
source "https://rubygems.org"
|
|
2
4
|
|
|
3
5
|
ruby RUBY_VERSION
|
|
4
6
|
|
|
5
7
|
gemspec
|
|
6
|
-
|
|
7
|
-
group :development, :test do
|
|
8
|
-
gem "actionpack"
|
|
9
|
-
gem "activemodel"
|
|
10
|
-
gem "bundler"
|
|
11
|
-
gem "pry"
|
|
12
|
-
gem "rake"
|
|
13
|
-
gem "rspec"
|
|
14
|
-
gem "rubocop"
|
|
15
|
-
gem "yard"
|
|
16
|
-
end
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Pundit provides a set of helpers which guide you in leveraging regular Ruby
|
|
9
9
|
classes and object oriented design patterns to build a simple, robust and
|
|
10
|
-
|
|
10
|
+
scalable authorization system.
|
|
11
11
|
|
|
12
12
|
Links:
|
|
13
13
|
|
|
@@ -31,7 +31,6 @@ Include Pundit in your application controller:
|
|
|
31
31
|
``` ruby
|
|
32
32
|
class ApplicationController < ActionController::Base
|
|
33
33
|
include Pundit
|
|
34
|
-
protect_from_forgery
|
|
35
34
|
end
|
|
36
35
|
```
|
|
37
36
|
|
|
@@ -61,7 +60,7 @@ class PostPolicy
|
|
|
61
60
|
end
|
|
62
61
|
|
|
63
62
|
def update?
|
|
64
|
-
user.admin?
|
|
63
|
+
user.admin? || !post.published?
|
|
65
64
|
end
|
|
66
65
|
end
|
|
67
66
|
```
|
|
@@ -165,13 +164,18 @@ def admin_list
|
|
|
165
164
|
end
|
|
166
165
|
```
|
|
167
166
|
|
|
168
|
-
`authorize` returns the
|
|
167
|
+
`authorize` returns the instance passed to it, so you can chain it like this:
|
|
169
168
|
|
|
170
169
|
Controller:
|
|
171
170
|
```ruby
|
|
172
171
|
def show
|
|
173
172
|
@user = authorize User.find(params[:id])
|
|
174
173
|
end
|
|
174
|
+
|
|
175
|
+
# return the record even for namespaced policies
|
|
176
|
+
def show
|
|
177
|
+
@user = authorize [:admin, User.find(params[:id])]
|
|
178
|
+
end
|
|
175
179
|
```
|
|
176
180
|
|
|
177
181
|
You can easily get a hold of an instance of the policy through the `policy`
|
|
@@ -195,6 +199,10 @@ class DashboardPolicy < Struct.new(:user, :dashboard)
|
|
|
195
199
|
end
|
|
196
200
|
```
|
|
197
201
|
|
|
202
|
+
Note that the headless policy still needs to accept two arguments. The
|
|
203
|
+
second argument will just be the symbol `:dashboard` in this case which
|
|
204
|
+
is what is passed as the record to `authorize` below.
|
|
205
|
+
|
|
198
206
|
```ruby
|
|
199
207
|
# In controllers
|
|
200
208
|
authorize :dashboard, :show?
|
|
@@ -216,8 +224,6 @@ define a class called a policy scope. It can look something like this:
|
|
|
216
224
|
``` ruby
|
|
217
225
|
class PostPolicy < ApplicationPolicy
|
|
218
226
|
class Scope
|
|
219
|
-
attr_reader :user, :scope
|
|
220
|
-
|
|
221
227
|
def initialize(user, scope)
|
|
222
228
|
@user = user
|
|
223
229
|
@scope = scope
|
|
@@ -230,6 +236,10 @@ class PostPolicy < ApplicationPolicy
|
|
|
230
236
|
scope.where(published: true)
|
|
231
237
|
end
|
|
232
238
|
end
|
|
239
|
+
|
|
240
|
+
private
|
|
241
|
+
|
|
242
|
+
attr_reader :user, :scope
|
|
233
243
|
end
|
|
234
244
|
|
|
235
245
|
def update?
|
|
@@ -292,13 +302,11 @@ def index
|
|
|
292
302
|
end
|
|
293
303
|
```
|
|
294
304
|
|
|
295
|
-
|
|
296
|
-
the `PostPolicy::Scope` class, it will instantiate this class and call
|
|
297
|
-
`resolve` on the instance. In this case it is a shortcut for doing:
|
|
305
|
+
In this case it is a shortcut for doing:
|
|
298
306
|
|
|
299
307
|
``` ruby
|
|
300
308
|
def index
|
|
301
|
-
@
|
|
309
|
+
@publications = PublicationPolicy::Scope.new(current_user, Post).resolve
|
|
302
310
|
end
|
|
303
311
|
```
|
|
304
312
|
|
|
@@ -387,6 +395,16 @@ class Post
|
|
|
387
395
|
end
|
|
388
396
|
```
|
|
389
397
|
|
|
398
|
+
Alternatively, you can declare an instance method:
|
|
399
|
+
|
|
400
|
+
``` ruby
|
|
401
|
+
class Post
|
|
402
|
+
def policy_class
|
|
403
|
+
PostablePolicy
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
```
|
|
407
|
+
|
|
390
408
|
## Just plain old Ruby
|
|
391
409
|
|
|
392
410
|
As you can see, Pundit doesn't do anything you couldn't have easily done
|
|
@@ -472,7 +490,6 @@ method in every controller.
|
|
|
472
490
|
|
|
473
491
|
```ruby
|
|
474
492
|
class ApplicationController < ActionController::Base
|
|
475
|
-
protect_from_forgery
|
|
476
493
|
include Pundit
|
|
477
494
|
|
|
478
495
|
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
|
@@ -593,8 +610,7 @@ class Admin::PostController < AdminController
|
|
|
593
610
|
end
|
|
594
611
|
|
|
595
612
|
def show
|
|
596
|
-
post = Post.find(params[:id])
|
|
597
|
-
authorize(post)
|
|
613
|
+
post = authorize Post.find(params[:id])
|
|
598
614
|
end
|
|
599
615
|
end
|
|
600
616
|
```
|
|
@@ -637,9 +653,8 @@ end
|
|
|
637
653
|
|
|
638
654
|
## Strong parameters
|
|
639
655
|
|
|
640
|
-
In Rails
|
|
641
|
-
|
|
642
|
-
mass-assignment protection is handled in the controller. With Pundit you can
|
|
656
|
+
In Rails,
|
|
657
|
+
mass-assignment protection is handled in the controller. With Pundit you can
|
|
643
658
|
control which attributes a user has access to update via your policies. You can
|
|
644
659
|
set up a `permitted_attributes` method in your policy like this:
|
|
645
660
|
|
|
@@ -778,9 +793,14 @@ Pundit does not provide a DSL for testing scopes. Just test it like a regular Ru
|
|
|
778
793
|
- [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
|
|
779
794
|
- [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
|
|
780
795
|
- [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
|
|
796
|
+
- [Testing Pundit with Minitest](https://github.com/varvet/pundit/issues/204#issuecomment-60166450)
|
|
781
797
|
- [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
|
|
782
798
|
- [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
|
|
783
799
|
|
|
800
|
+
## Other implementations
|
|
801
|
+
|
|
802
|
+
- [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](http://flask.pocoo.org/) extension "heavily inspired by" Pundit
|
|
803
|
+
|
|
784
804
|
# License
|
|
785
805
|
|
|
786
806
|
Licensed under the MIT license, see the separate LICENSE.txt file.
|
data/Rakefile
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pundit
|
|
2
4
|
module Generators
|
|
3
5
|
class InstallGenerator < ::Rails::Generators::Base
|
|
4
|
-
source_root File.expand_path(
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
5
7
|
|
|
6
8
|
def copy_application_policy
|
|
7
|
-
template
|
|
9
|
+
template "application_policy.rb", "app/policies/application_policy.rb"
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class ApplicationPolicy
|
|
2
4
|
attr_reader :user, :record
|
|
3
5
|
|
|
@@ -35,8 +37,6 @@ class ApplicationPolicy
|
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
class Scope
|
|
38
|
-
attr_reader :user, :scope
|
|
39
|
-
|
|
40
40
|
def initialize(user, scope)
|
|
41
41
|
@user = user
|
|
42
42
|
@scope = scope
|
|
@@ -45,5 +45,9 @@ class ApplicationPolicy
|
|
|
45
45
|
def resolve
|
|
46
46
|
scope.all
|
|
47
47
|
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
attr_reader :user, :scope
|
|
48
52
|
end
|
|
49
53
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Pundit
|
|
2
4
|
module Generators
|
|
3
5
|
class PolicyGenerator < ::Rails::Generators::NamedBase
|
|
4
|
-
source_root File.expand_path(
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
5
7
|
|
|
6
8
|
def create_policy
|
|
7
|
-
template
|
|
9
|
+
template "policy.rb", File.join("app/policies", class_path, "#{file_name}_policy.rb")
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
hook_for :test_framework
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rspec
|
|
2
4
|
module Generators
|
|
3
5
|
class PolicyGenerator < ::Rails::Generators::NamedBase
|
|
4
|
-
source_root File.expand_path(
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
5
7
|
|
|
6
8
|
def create_policy_spec
|
|
7
|
-
template
|
|
9
|
+
template "policy_spec.rb", File.join("spec/policies", class_path, "#{file_name}_policy_spec.rb")
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module TestUnit
|
|
2
4
|
module Generators
|
|
3
5
|
class PolicyGenerator < ::Rails::Generators::NamedBase
|
|
4
|
-
source_root File.expand_path(
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
5
7
|
|
|
6
8
|
def create_policy_test
|
|
7
|
-
template
|
|
9
|
+
template "policy_test.rb", File.join("test/policies", class_path, "#{file_name}_policy_test.rb")
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
end
|
data/lib/pundit/policy_finder.rb
CHANGED
data/lib/pundit/rspec.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Pundit
|
|
4
4
|
module RSpec
|
|
@@ -72,17 +72,9 @@ module Pundit
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
RSpec.configure do |config|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
else
|
|
82
|
-
config.include(
|
|
83
|
-
Pundit::RSpec::PolicyExampleGroup,
|
|
84
|
-
type: :policy,
|
|
85
|
-
example_group: { file_path: %r{spec/policies} }
|
|
86
|
-
)
|
|
87
|
-
end
|
|
75
|
+
config.include(
|
|
76
|
+
Pundit::RSpec::PolicyExampleGroup,
|
|
77
|
+
type: :policy,
|
|
78
|
+
file_path: %r{spec/policies}
|
|
79
|
+
)
|
|
88
80
|
end
|
data/lib/pundit/version.rb
CHANGED
data/lib/pundit.rb
CHANGED
|
@@ -8,16 +8,18 @@ require "active_support/core_ext/object/blank"
|
|
|
8
8
|
require "active_support/core_ext/module/introspection"
|
|
9
9
|
require "active_support/dependencies/autoload"
|
|
10
10
|
|
|
11
|
+
# @api private
|
|
12
|
+
# To avoid name clashes with common Error naming when mixing in Pundit,
|
|
13
|
+
# keep it here with compact class style definition.
|
|
14
|
+
class Pundit::Error < StandardError; end # rubocop:disable Style/ClassAndModuleChildren
|
|
15
|
+
|
|
11
16
|
# @api public
|
|
12
17
|
module Pundit
|
|
13
|
-
SUFFIX = "Policy"
|
|
18
|
+
SUFFIX = "Policy"
|
|
14
19
|
|
|
15
20
|
# @api private
|
|
16
21
|
module Generators; end
|
|
17
22
|
|
|
18
|
-
# @api private
|
|
19
|
-
class Error < StandardError; end
|
|
20
|
-
|
|
21
23
|
# Error that will be raised when authorization has failed
|
|
22
24
|
class NotAuthorizedError < Error
|
|
23
25
|
attr_reader :query, :record, :policy
|
|
@@ -30,7 +32,7 @@ module Pundit
|
|
|
30
32
|
@record = options[:record]
|
|
31
33
|
@policy = options[:policy]
|
|
32
34
|
|
|
33
|
-
message = options.fetch(:message) { "not allowed to #{query} this #{record.
|
|
35
|
+
message = options.fetch(:message) { "not allowed to #{query} this #{record.class}" }
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
super(message)
|
|
@@ -69,7 +71,7 @@ module Pundit
|
|
|
69
71
|
|
|
70
72
|
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
|
|
71
73
|
|
|
72
|
-
record
|
|
74
|
+
record.is_a?(Array) ? record.last : record
|
|
73
75
|
end
|
|
74
76
|
|
|
75
77
|
# Retrieves the policy scope for the given record.
|
|
@@ -80,10 +82,16 @@ module Pundit
|
|
|
80
82
|
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
|
81
83
|
# @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
|
|
82
84
|
def policy_scope(user, scope)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
policy_scope_class = PolicyFinder.new(scope).scope
|
|
86
|
+
return unless policy_scope_class
|
|
87
|
+
|
|
88
|
+
begin
|
|
89
|
+
policy_scope = policy_scope_class.new(user, pundit_model(scope))
|
|
90
|
+
rescue ArgumentError
|
|
91
|
+
raise InvalidConstructorError, "Invalid #<#{policy_scope_class}> constructor is called"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
policy_scope.resolve
|
|
87
95
|
end
|
|
88
96
|
|
|
89
97
|
# Retrieves the policy scope for the given record.
|
|
@@ -95,10 +103,16 @@ module Pundit
|
|
|
95
103
|
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
|
96
104
|
# @return [Scope{#resolve}] instance of scope class which can resolve to a scope
|
|
97
105
|
def policy_scope!(user, scope)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
policy_scope_class = PolicyFinder.new(scope).scope!
|
|
107
|
+
return unless policy_scope_class
|
|
108
|
+
|
|
109
|
+
begin
|
|
110
|
+
policy_scope = policy_scope_class.new(user, pundit_model(scope))
|
|
111
|
+
rescue ArgumentError
|
|
112
|
+
raise InvalidConstructorError, "Invalid #<#{policy_scope_class}> constructor is called"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
policy_scope.resolve
|
|
102
116
|
end
|
|
103
117
|
|
|
104
118
|
# Retrieves the policy for the given record.
|
|
@@ -110,7 +124,7 @@ module Pundit
|
|
|
110
124
|
# @return [Object, nil] instance of policy class with query methods
|
|
111
125
|
def policy(user, record)
|
|
112
126
|
policy = PolicyFinder.new(record).policy
|
|
113
|
-
policy
|
|
127
|
+
policy&.new(user, pundit_model(record))
|
|
114
128
|
rescue ArgumentError
|
|
115
129
|
raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
|
|
116
130
|
end
|
|
@@ -130,7 +144,7 @@ module Pundit
|
|
|
130
144
|
raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
|
|
131
145
|
end
|
|
132
146
|
|
|
133
|
-
|
|
147
|
+
private
|
|
134
148
|
|
|
135
149
|
def pundit_model(record)
|
|
136
150
|
record.is_a?(Array) ? record.last : record
|
|
@@ -153,7 +167,7 @@ module Pundit
|
|
|
153
167
|
end
|
|
154
168
|
end
|
|
155
169
|
|
|
156
|
-
protected
|
|
170
|
+
protected
|
|
157
171
|
|
|
158
172
|
# @return [Boolean] whether authorization has been performed, i.e. whether
|
|
159
173
|
# one {#authorize} or {#skip_authorization} has been called
|
|
@@ -208,7 +222,7 @@ protected
|
|
|
208
222
|
|
|
209
223
|
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
|
|
210
224
|
|
|
211
|
-
record
|
|
225
|
+
record.is_a?(Array) ? record.last : record
|
|
212
226
|
end
|
|
213
227
|
|
|
214
228
|
# Allow this action not to perform authorization.
|
|
@@ -303,7 +317,7 @@ protected
|
|
|
303
317
|
current_user
|
|
304
318
|
end
|
|
305
319
|
|
|
306
|
-
private
|
|
320
|
+
private
|
|
307
321
|
|
|
308
322
|
def pundit_policy_scope(scope)
|
|
309
323
|
policy_scopes[scope] ||= Pundit.policy_scope!(pundit_user, scope)
|
data/pundit.gemspec
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
lib = File.expand_path("lib", __dir__)
|
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
5
|
require "pundit/version"
|
|
@@ -5,17 +7,26 @@ require "pundit/version"
|
|
|
5
7
|
Gem::Specification.new do |gem|
|
|
6
8
|
gem.name = "pundit"
|
|
7
9
|
gem.version = Pundit::VERSION
|
|
8
|
-
gem.authors = ["Jonas Nicklas", "
|
|
10
|
+
gem.authors = ["Jonas Nicklas", "Varvet AB"]
|
|
9
11
|
gem.email = ["jonas.nicklas@gmail.com", "dev@elabs.se"]
|
|
10
12
|
gem.description = "Object oriented authorization for Rails applications"
|
|
11
13
|
gem.summary = "OO authorization for Rails"
|
|
12
14
|
gem.homepage = "https://github.com/varvet/pundit"
|
|
13
15
|
gem.license = "MIT"
|
|
14
16
|
|
|
15
|
-
gem.files = `git ls-files`.split(
|
|
17
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
16
18
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
17
19
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
18
20
|
gem.require_paths = ["lib"]
|
|
19
21
|
|
|
20
22
|
gem.add_dependency "activesupport", ">= 3.0.0"
|
|
23
|
+
gem.add_development_dependency "actionpack", ">= 3.0.0"
|
|
24
|
+
gem.add_development_dependency "activemodel", ">= 3.0.0"
|
|
25
|
+
gem.add_development_dependency "bundler"
|
|
26
|
+
gem.add_development_dependency "pry"
|
|
27
|
+
gem.add_development_dependency "rake"
|
|
28
|
+
gem.add_development_dependency "rspec", ">= 3.0.0"
|
|
29
|
+
gem.add_development_dependency "rubocop", "0.74.0"
|
|
30
|
+
gem.add_development_dependency "simplecov", ">= 0.17.0"
|
|
31
|
+
gem.add_development_dependency "yard"
|
|
21
32
|
end
|
data/spec/policy_finder_spec.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "spec_helper"
|
|
2
4
|
|
|
3
|
-
describe Pundit::PolicyFinder do
|
|
5
|
+
RSpec.describe Pundit::PolicyFinder do
|
|
4
6
|
let(:user) { double }
|
|
5
7
|
let(:post) { Post.new(user) }
|
|
6
8
|
let(:comment) { CommentFourFiveSix.new }
|
|
@@ -22,37 +24,100 @@ describe Pundit::PolicyFinder do
|
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
describe "#policy" do
|
|
25
|
-
|
|
27
|
+
context "with an instance" do
|
|
28
|
+
it "returns the associated policy" do
|
|
29
|
+
object = described_class.new(post)
|
|
30
|
+
|
|
31
|
+
expect(object.policy).to eq PostPolicy
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "with an array of symbols" do
|
|
36
|
+
it "returns the associated namespaced policy" do
|
|
37
|
+
object = described_class.new(%i[project post])
|
|
38
|
+
|
|
39
|
+
expect(object.policy).to eq Project::PostPolicy
|
|
40
|
+
end
|
|
41
|
+
end
|
|
26
42
|
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
context "with an array of a symbol and an instance" do
|
|
44
|
+
it "returns the associated namespaced policy" do
|
|
45
|
+
object = described_class.new([:project, post])
|
|
46
|
+
|
|
47
|
+
expect(object.policy).to eq Project::PostPolicy
|
|
48
|
+
end
|
|
29
49
|
end
|
|
30
50
|
|
|
31
|
-
context "with a
|
|
32
|
-
it "returns
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
context "with an array of a symbol and a class with a specified policy class" do
|
|
52
|
+
it "returns the associated namespaced policy" do
|
|
53
|
+
object = described_class.new([:project, Customer::Post])
|
|
54
|
+
|
|
55
|
+
expect(object.policy).to eq Project::PostPolicy
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context "with an array of a symbol and a class with a specified model name" do
|
|
60
|
+
it "returns the associated namespaced policy" do
|
|
61
|
+
object = described_class.new([:project, CommentsRelation])
|
|
62
|
+
|
|
63
|
+
expect(object.policy).to eq Project::CommentPolicy
|
|
35
64
|
end
|
|
36
65
|
end
|
|
37
66
|
|
|
38
67
|
context "with a class" do
|
|
39
|
-
it "returns
|
|
40
|
-
|
|
41
|
-
|
|
68
|
+
it "returns the associated policy" do
|
|
69
|
+
object = described_class.new(Post)
|
|
70
|
+
|
|
71
|
+
expect(object.policy).to eq PostPolicy
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context "with a class which has a specified policy class" do
|
|
76
|
+
it "returns the associated policy" do
|
|
77
|
+
object = described_class.new(Customer::Post)
|
|
78
|
+
|
|
79
|
+
expect(object.policy).to eq PostPolicy
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "with an instance which has a specified policy class" do
|
|
84
|
+
it "returns the associated policy" do
|
|
85
|
+
object = described_class.new(Customer::Post.new(user))
|
|
86
|
+
|
|
87
|
+
expect(object.policy).to eq PostPolicy
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "with a class which has a specified model name" do
|
|
92
|
+
it "returns the associated policy" do
|
|
93
|
+
object = described_class.new(CommentsRelation)
|
|
94
|
+
|
|
95
|
+
expect(object.policy).to eq CommentPolicy
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context "with an instance which has a specified policy class" do
|
|
100
|
+
it "returns the associated policy" do
|
|
101
|
+
object = described_class.new(CommentsRelation.new)
|
|
102
|
+
|
|
103
|
+
expect(object.policy).to eq CommentPolicy
|
|
42
104
|
end
|
|
43
105
|
end
|
|
44
106
|
|
|
45
107
|
context "with nil" do
|
|
46
|
-
it "returns
|
|
47
|
-
|
|
48
|
-
|
|
108
|
+
it "returns a NilClassPolicy" do
|
|
109
|
+
object = described_class.new(nil)
|
|
110
|
+
|
|
111
|
+
expect(object.policy).to eq NilClassPolicy
|
|
49
112
|
end
|
|
50
113
|
end
|
|
51
114
|
|
|
52
|
-
context "with a
|
|
115
|
+
context "with a class that doesn't have an associated policy" do
|
|
53
116
|
it "returns nil" do
|
|
54
|
-
|
|
55
|
-
|
|
117
|
+
class Foo; end
|
|
118
|
+
object = described_class.new(Foo)
|
|
119
|
+
|
|
120
|
+
expect(object.policy).to eq nil
|
|
56
121
|
end
|
|
57
122
|
end
|
|
58
123
|
end
|
data/spec/pundit_spec.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "spec_helper"
|
|
2
4
|
|
|
3
|
-
describe Pundit do
|
|
5
|
+
RSpec.describe Pundit do
|
|
4
6
|
let(:user) { double }
|
|
5
7
|
let(:post) { Post.new(user) }
|
|
6
8
|
let(:customer_post) { Customer::Post.new(user) }
|
|
@@ -16,12 +18,33 @@ describe Pundit do
|
|
|
16
18
|
let(:tag_four_five_six) { ProjectOneTwoThree::TagFourFiveSix.new(user) }
|
|
17
19
|
let(:avatar_four_five_six) { ProjectOneTwoThree::AvatarFourFiveSix.new }
|
|
18
20
|
let(:wiki) { Wiki.new }
|
|
21
|
+
let(:thread) { Thread.new }
|
|
19
22
|
|
|
20
23
|
describe ".authorize" do
|
|
21
24
|
it "infers the policy and authorizes based on it" do
|
|
22
25
|
expect(Pundit.authorize(user, post, :update?)).to be_truthy
|
|
23
26
|
end
|
|
24
27
|
|
|
28
|
+
it "returns the record on successful authorization" do
|
|
29
|
+
expect(Pundit.authorize(user, post, :update?)).to eq(post)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "returns the record when passed record with namespace " do
|
|
33
|
+
expect(Pundit.authorize(user, [:project, comment], :update?)).to eq(comment)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "returns the record when passed record with nested namespace " do
|
|
37
|
+
expect(Pundit.authorize(user, [:project, :admin, comment], :update?)).to eq(comment)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "returns the policy name symbol when passed record with headless policy" do
|
|
41
|
+
expect(Pundit.authorize(user, :publication, :create?)).to eq(:publication)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "returns the class when passed record not a particular instance" do
|
|
45
|
+
expect(Pundit.authorize(user, Post, :show?)).to eq(Post)
|
|
46
|
+
end
|
|
47
|
+
|
|
25
48
|
it "can be given a different policy class" do
|
|
26
49
|
expect(Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy)).to be_truthy
|
|
27
50
|
end
|
|
@@ -35,7 +58,7 @@ describe Pundit do
|
|
|
35
58
|
# rubocop:disable Style/MultilineBlockChain
|
|
36
59
|
expect do
|
|
37
60
|
Pundit.authorize(user, post, :destroy?)
|
|
38
|
-
end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this
|
|
61
|
+
end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this Post") do |error|
|
|
39
62
|
expect(error.query).to eq :destroy?
|
|
40
63
|
expect(error.record).to eq post
|
|
41
64
|
expect(error.policy).to eq Pundit.policy(user, post)
|
|
@@ -88,6 +111,12 @@ describe Pundit do
|
|
|
88
111
|
Pundit.policy_scope(user, Wiki)
|
|
89
112
|
end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy::Scope> constructor is called")
|
|
90
113
|
end
|
|
114
|
+
|
|
115
|
+
it "raises an original error with a policy scope that contains error" do
|
|
116
|
+
expect do
|
|
117
|
+
Pundit.policy_scope(user, Thread)
|
|
118
|
+
end.to raise_error(ArgumentError)
|
|
119
|
+
end
|
|
91
120
|
end
|
|
92
121
|
|
|
93
122
|
describe ".policy_scope!" do
|
|
@@ -401,7 +430,23 @@ describe Pundit do
|
|
|
401
430
|
end
|
|
402
431
|
|
|
403
432
|
it "returns the record on successful authorization" do
|
|
404
|
-
expect(controller.authorize(post)).to
|
|
433
|
+
expect(controller.authorize(post)).to eq(post)
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it "returns the record when passed record with namespace " do
|
|
437
|
+
expect(controller.authorize([:project, comment], :update?)).to eq(comment)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
it "returns the record when passed record with nested namespace " do
|
|
441
|
+
expect(controller.authorize([:project, :admin, comment], :update?)).to eq(comment)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
it "returns the policy name symbol when passed record with headless policy" do
|
|
445
|
+
expect(controller.authorize(:publication, :create?)).to eq(:publication)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
it "returns the class when passed record not a particular instance" do
|
|
449
|
+
expect(controller.authorize(Post, :show?)).to eq(Post)
|
|
405
450
|
end
|
|
406
451
|
|
|
407
452
|
it "can be given a different permission to check" do
|
|
@@ -511,11 +556,13 @@ describe Pundit do
|
|
|
511
556
|
|
|
512
557
|
describe "#permitted_attributes" do
|
|
513
558
|
it "checks policy for permitted attributes" do
|
|
514
|
-
params = ActionController::Parameters.new(
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
559
|
+
params = ActionController::Parameters.new(
|
|
560
|
+
post: {
|
|
561
|
+
title: "Hello",
|
|
562
|
+
votes: 5,
|
|
563
|
+
admin: true
|
|
564
|
+
}
|
|
565
|
+
)
|
|
519
566
|
|
|
520
567
|
action = "update"
|
|
521
568
|
|
|
@@ -527,11 +574,13 @@ describe Pundit do
|
|
|
527
574
|
end
|
|
528
575
|
|
|
529
576
|
it "checks policy for permitted attributes for record of a ActiveModel type" do
|
|
530
|
-
params = ActionController::Parameters.new(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
577
|
+
params = ActionController::Parameters.new(
|
|
578
|
+
customer_post: {
|
|
579
|
+
title: "Hello",
|
|
580
|
+
votes: 5,
|
|
581
|
+
admin: true
|
|
582
|
+
}
|
|
583
|
+
)
|
|
535
584
|
|
|
536
585
|
action = "update"
|
|
537
586
|
|
|
@@ -547,24 +596,28 @@ describe Pundit do
|
|
|
547
596
|
|
|
548
597
|
describe "#permitted_attributes_for_action" do
|
|
549
598
|
it "is checked if it is defined in the policy" do
|
|
550
|
-
params = ActionController::Parameters.new(
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
599
|
+
params = ActionController::Parameters.new(
|
|
600
|
+
post: {
|
|
601
|
+
title: "Hello",
|
|
602
|
+
body: "blah",
|
|
603
|
+
votes: 5,
|
|
604
|
+
admin: true
|
|
605
|
+
}
|
|
606
|
+
)
|
|
556
607
|
|
|
557
608
|
action = "revise"
|
|
558
609
|
expect(Controller.new(user, action, params).permitted_attributes(post).to_h).to eq("body" => "blah")
|
|
559
610
|
end
|
|
560
611
|
|
|
561
612
|
it "can be explicitly set" do
|
|
562
|
-
params = ActionController::Parameters.new(
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
613
|
+
params = ActionController::Parameters.new(
|
|
614
|
+
post: {
|
|
615
|
+
title: "Hello",
|
|
616
|
+
body: "blah",
|
|
617
|
+
votes: 5,
|
|
618
|
+
admin: true
|
|
619
|
+
}
|
|
620
|
+
)
|
|
568
621
|
|
|
569
622
|
action = "update"
|
|
570
623
|
expect(Controller.new(user, action, params).permitted_attributes(post, :revise).to_h).to eq("body" => "blah")
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "simplecov"
|
|
4
|
+
SimpleCov.start do
|
|
5
|
+
add_filter "/spec/"
|
|
6
|
+
end
|
|
7
|
+
|
|
1
8
|
require "pundit"
|
|
2
9
|
require "pundit/rspec"
|
|
3
10
|
|
|
@@ -9,22 +16,6 @@ require "active_support/core_ext"
|
|
|
9
16
|
require "active_model/naming"
|
|
10
17
|
require "action_controller/metal/strong_parameters"
|
|
11
18
|
|
|
12
|
-
I18n.enforce_available_locales = false
|
|
13
|
-
|
|
14
|
-
module PunditSpecHelper
|
|
15
|
-
extend RSpec::Matchers::DSL
|
|
16
|
-
|
|
17
|
-
matcher :be_truthy do
|
|
18
|
-
match do |actual|
|
|
19
|
-
actual
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
RSpec.configure do |config|
|
|
25
|
-
config.include PunditSpecHelper
|
|
26
|
-
end
|
|
27
|
-
|
|
28
19
|
class PostPolicy < Struct.new(:user, :post)
|
|
29
20
|
class Scope < Struct.new(:user, :scope)
|
|
30
21
|
def resolve
|
|
@@ -84,10 +75,6 @@ module Customer
|
|
|
84
75
|
def self.policy_class
|
|
85
76
|
PostPolicy
|
|
86
77
|
end
|
|
87
|
-
|
|
88
|
-
def policy_class
|
|
89
|
-
self.class.policy_class
|
|
90
|
-
end
|
|
91
78
|
end
|
|
92
79
|
end
|
|
93
80
|
|
|
@@ -135,7 +122,7 @@ class CommentsRelation
|
|
|
135
122
|
@empty
|
|
136
123
|
end
|
|
137
124
|
|
|
138
|
-
def model_name
|
|
125
|
+
def self.model_name
|
|
139
126
|
Comment.model_name
|
|
140
127
|
end
|
|
141
128
|
end
|
|
@@ -172,6 +159,10 @@ class CriteriaPolicy < Struct.new(:user, :criteria); end
|
|
|
172
159
|
|
|
173
160
|
module Project
|
|
174
161
|
class CommentPolicy < Struct.new(:user, :comment)
|
|
162
|
+
def update?
|
|
163
|
+
true
|
|
164
|
+
end
|
|
165
|
+
|
|
175
166
|
class Scope < Struct.new(:user, :scope)
|
|
176
167
|
def resolve
|
|
177
168
|
scope
|
|
@@ -188,6 +179,14 @@ module Project
|
|
|
188
179
|
end
|
|
189
180
|
end
|
|
190
181
|
end
|
|
182
|
+
|
|
183
|
+
module Admin
|
|
184
|
+
class CommentPolicy < Struct.new(:user, :comment)
|
|
185
|
+
def update?
|
|
186
|
+
true
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
191
190
|
end
|
|
192
191
|
|
|
193
192
|
class DenierPolicy < Struct.new(:user, :record)
|
|
@@ -199,9 +198,9 @@ end
|
|
|
199
198
|
class Controller
|
|
200
199
|
include Pundit
|
|
201
200
|
# Mark protected methods public so they may be called in test
|
|
202
|
-
# rubocop:disable
|
|
201
|
+
# rubocop:disable Style/AccessModifierDeclarations
|
|
203
202
|
public(*Pundit.protected_instance_methods)
|
|
204
|
-
# rubocop:enable
|
|
203
|
+
# rubocop:enable Style/AccessModifierDeclarations
|
|
205
204
|
|
|
206
205
|
attr_reader :current_user, :action_name, :params
|
|
207
206
|
|
|
@@ -236,6 +235,18 @@ class WikiPolicy
|
|
|
236
235
|
end
|
|
237
236
|
end
|
|
238
237
|
|
|
238
|
+
class Thread
|
|
239
|
+
def self.all; end
|
|
240
|
+
end
|
|
241
|
+
class ThreadPolicy < Struct.new(:user, :thread)
|
|
242
|
+
class Scope < Struct.new(:user, :scope)
|
|
243
|
+
def resolve
|
|
244
|
+
# deliberate wrong useage of the method
|
|
245
|
+
scope.all(:unvalid, :parameters)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
239
250
|
class PostFourFiveSix < Struct.new(:user); end
|
|
240
251
|
|
|
241
252
|
class CommentFourFiveSix; extend ActiveModel::Naming; end
|
metadata
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pundit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonas Nicklas
|
|
8
|
-
-
|
|
8
|
+
- Varvet AB
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2021-08-13 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activesupport
|
|
@@ -25,6 +25,132 @@ dependencies:
|
|
|
25
25
|
- - ">="
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
27
|
version: 3.0.0
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: actionpack
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: 3.0.0
|
|
35
|
+
type: :development
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: 3.0.0
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
name: activemodel
|
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: 3.0.0
|
|
49
|
+
type: :development
|
|
50
|
+
prerelease: false
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: 3.0.0
|
|
56
|
+
- !ruby/object:Gem::Dependency
|
|
57
|
+
name: bundler
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
- !ruby/object:Gem::Dependency
|
|
71
|
+
name: pry
|
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
- !ruby/object:Gem::Dependency
|
|
85
|
+
name: rake
|
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
type: :development
|
|
92
|
+
prerelease: false
|
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
- !ruby/object:Gem::Dependency
|
|
99
|
+
name: rspec
|
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: 3.0.0
|
|
105
|
+
type: :development
|
|
106
|
+
prerelease: false
|
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: 3.0.0
|
|
112
|
+
- !ruby/object:Gem::Dependency
|
|
113
|
+
name: rubocop
|
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - '='
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: 0.74.0
|
|
119
|
+
type: :development
|
|
120
|
+
prerelease: false
|
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - '='
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: 0.74.0
|
|
126
|
+
- !ruby/object:Gem::Dependency
|
|
127
|
+
name: simplecov
|
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
|
129
|
+
requirements:
|
|
130
|
+
- - ">="
|
|
131
|
+
- !ruby/object:Gem::Version
|
|
132
|
+
version: 0.17.0
|
|
133
|
+
type: :development
|
|
134
|
+
prerelease: false
|
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
136
|
+
requirements:
|
|
137
|
+
- - ">="
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: 0.17.0
|
|
140
|
+
- !ruby/object:Gem::Dependency
|
|
141
|
+
name: yard
|
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: '0'
|
|
147
|
+
type: :development
|
|
148
|
+
prerelease: false
|
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
150
|
+
requirements:
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: '0'
|
|
28
154
|
description: Object oriented authorization for Rails applications
|
|
29
155
|
email:
|
|
30
156
|
- jonas.nicklas@gmail.com
|
|
@@ -82,8 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
82
208
|
- !ruby/object:Gem::Version
|
|
83
209
|
version: '0'
|
|
84
210
|
requirements: []
|
|
85
|
-
|
|
86
|
-
rubygems_version: 2.7.6
|
|
211
|
+
rubygems_version: 3.2.25
|
|
87
212
|
signing_key:
|
|
88
213
|
specification_version: 4
|
|
89
214
|
summary: OO authorization for Rails
|