pundit 1.1.0 → 2.3.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 +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -52
- data/.travis.yml +25 -10
- data/CHANGELOG.md +88 -0
- data/Gemfile +4 -1
- data/LICENSE.txt +1 -1
- data/README.md +304 -87
- data/Rakefile +2 -1
- data/config/rubocop-rspec.yml +5 -0
- data/lib/generators/pundit/install/install_generator.rb +4 -2
- data/lib/generators/pundit/install/templates/application_policy.rb +8 -8
- data/lib/generators/pundit/policy/policy_generator.rb +4 -2
- data/lib/generators/pundit/policy/templates/policy.rb +4 -3
- data/lib/generators/rspec/policy_generator.rb +4 -2
- data/lib/generators/rspec/templates/policy_spec.rb +1 -2
- data/lib/generators/test_unit/policy_generator.rb +4 -2
- data/lib/generators/test_unit/templates/policy_test.rb +0 -1
- data/lib/pundit/authorization.rb +168 -0
- data/lib/pundit/policy_finder.rb +28 -32
- data/lib/pundit/rspec.rb +13 -17
- data/lib/pundit/version.rb +3 -1
- data/lib/pundit.rb +76 -190
- data/pundit.gemspec +12 -9
- data/spec/authorization_spec.rb +258 -0
- data/spec/generators_spec.rb +43 -0
- data/spec/policies/post_policy_spec.rb +3 -1
- data/spec/policy_finder_spec.rb +187 -0
- data/spec/pundit_spec.rb +147 -196
- data/spec/spec_helper.rb +110 -30
- metadata +59 -25
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
class Foo; end
|
6
|
+
RSpec.describe Pundit::PolicyFinder do
|
7
|
+
let(:user) { double }
|
8
|
+
let(:post) { Post.new(user) }
|
9
|
+
let(:comment) { CommentFourFiveSix.new }
|
10
|
+
let(:article) { Article.new }
|
11
|
+
|
12
|
+
describe "#scope" do
|
13
|
+
subject { described_class.new(post) }
|
14
|
+
|
15
|
+
it "returns a policy scope" do
|
16
|
+
expect(subject.scope).to eq PostPolicy::Scope
|
17
|
+
end
|
18
|
+
|
19
|
+
context "policy is nil" do
|
20
|
+
it "returns nil" do
|
21
|
+
allow(subject).to receive(:policy).and_return nil
|
22
|
+
expect(subject.scope).to eq nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#policy" do
|
28
|
+
context "with an instance" do
|
29
|
+
it "returns the associated policy" do
|
30
|
+
object = described_class.new(post)
|
31
|
+
|
32
|
+
expect(object.policy).to eq PostPolicy
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with an array of symbols" do
|
37
|
+
it "returns the associated namespaced policy" do
|
38
|
+
object = described_class.new(%i[project post])
|
39
|
+
|
40
|
+
expect(object.policy).to eq Project::PostPolicy
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with an array of a symbol and an instance" do
|
45
|
+
it "returns the associated namespaced policy" do
|
46
|
+
object = described_class.new([:project, post])
|
47
|
+
|
48
|
+
expect(object.policy).to eq Project::PostPolicy
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with an array of a symbol and a class with a specified policy class" do
|
53
|
+
it "returns the associated namespaced policy" do
|
54
|
+
object = described_class.new([:project, Customer::Post])
|
55
|
+
|
56
|
+
expect(object.policy).to eq Project::PostPolicy
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with an array of a symbol and a class with a specified model name" do
|
61
|
+
it "returns the associated namespaced policy" do
|
62
|
+
object = described_class.new([:project, CommentsRelation])
|
63
|
+
|
64
|
+
expect(object.policy).to eq Project::CommentPolicy
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with a class" do
|
69
|
+
it "returns the associated policy" do
|
70
|
+
object = described_class.new(Post)
|
71
|
+
|
72
|
+
expect(object.policy).to eq PostPolicy
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with a class which has a specified policy class" do
|
77
|
+
it "returns the associated policy" do
|
78
|
+
object = described_class.new(Customer::Post)
|
79
|
+
|
80
|
+
expect(object.policy).to eq PostPolicy
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with an instance which has a specified policy class" do
|
85
|
+
it "returns the associated policy" do
|
86
|
+
object = described_class.new(Customer::Post.new(user))
|
87
|
+
|
88
|
+
expect(object.policy).to eq PostPolicy
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with a class which has a specified model name" do
|
93
|
+
it "returns the associated policy" do
|
94
|
+
object = described_class.new(CommentsRelation)
|
95
|
+
|
96
|
+
expect(object.policy).to eq CommentPolicy
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "with an instance which has a specified policy class" do
|
101
|
+
it "returns the associated policy" do
|
102
|
+
object = described_class.new(CommentsRelation.new)
|
103
|
+
|
104
|
+
expect(object.policy).to eq CommentPolicy
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with nil" do
|
109
|
+
it "returns a NilClassPolicy" do
|
110
|
+
object = described_class.new(nil)
|
111
|
+
|
112
|
+
expect(object.policy).to eq NilClassPolicy
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "with a class that doesn't have an associated policy" do
|
117
|
+
it "returns nil" do
|
118
|
+
object = described_class.new(Foo)
|
119
|
+
|
120
|
+
expect(object.policy).to eq nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#scope!" do
|
126
|
+
context "@object is nil" do
|
127
|
+
subject { described_class.new(nil) }
|
128
|
+
|
129
|
+
it "returns the NilClass policy's scope class" do
|
130
|
+
expect(subject.scope!).to eq NilClassPolicy::Scope
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "@object is defined" do
|
135
|
+
subject { described_class.new(post) }
|
136
|
+
|
137
|
+
it "returns the scope" do
|
138
|
+
expect(subject.scope!).to eq PostPolicy::Scope
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "#param_key" do
|
144
|
+
context "object responds to model_name" do
|
145
|
+
subject { described_class.new(comment) }
|
146
|
+
|
147
|
+
it "returns the param_key" do
|
148
|
+
expect(subject.object).to respond_to(:model_name)
|
149
|
+
expect(subject.param_key).to eq "comment_four_five_six"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "object is a class" do
|
154
|
+
subject { described_class.new(Article) }
|
155
|
+
|
156
|
+
it "returns the param_key" do
|
157
|
+
expect(subject.object).not_to respond_to(:model_name)
|
158
|
+
expect(subject.object).to be_a Class
|
159
|
+
expect(subject.param_key).to eq "article"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "object is an instance of a class" do
|
164
|
+
subject { described_class.new(article) }
|
165
|
+
|
166
|
+
it "returns the param_key" do
|
167
|
+
expect(subject.object).not_to respond_to(:model_name)
|
168
|
+
expect(subject.object).not_to be_a Class
|
169
|
+
expect(subject.object).to be_an_instance_of Article
|
170
|
+
|
171
|
+
expect(subject.param_key).to eq "article"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "object is an array" do
|
176
|
+
subject { described_class.new([:project, article]) }
|
177
|
+
|
178
|
+
it "returns the param_key for the last element of the array" do
|
179
|
+
expect(subject.object).not_to respond_to(:model_name)
|
180
|
+
expect(subject.object).not_to be_a Class
|
181
|
+
expect(subject.object).to be_an_instance_of Array
|
182
|
+
|
183
|
+
expect(subject.param_key).to eq "article"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
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) }
|
@@ -8,19 +10,48 @@ describe Pundit do
|
|
8
10
|
let(:comment) { Comment.new }
|
9
11
|
let(:comment_four_five_six) { CommentFourFiveSix.new }
|
10
12
|
let(:article) { Article.new }
|
11
|
-
let(:controller) { Controller.new(user, action: "update") }
|
12
13
|
let(:artificial_blog) { ArtificialBlog.new }
|
13
14
|
let(:article_tag) { ArticleTag.new }
|
14
|
-
let(:comments_relation) { CommentsRelation.new }
|
15
|
-
let(:empty_comments_relation) { CommentsRelation.new(true) }
|
15
|
+
let(:comments_relation) { CommentsRelation.new(empty: false) }
|
16
|
+
let(:empty_comments_relation) { CommentsRelation.new(empty: true) }
|
16
17
|
let(:tag_four_five_six) { ProjectOneTwoThree::TagFourFiveSix.new(user) }
|
17
18
|
let(:avatar_four_five_six) { ProjectOneTwoThree::AvatarFourFiveSix.new }
|
19
|
+
let(:wiki) { Wiki.new }
|
18
20
|
|
19
21
|
describe ".authorize" do
|
20
22
|
it "infers the policy and authorizes based on it" do
|
21
23
|
expect(Pundit.authorize(user, post, :update?)).to be_truthy
|
22
24
|
end
|
23
25
|
|
26
|
+
it "returns the record on successful authorization" do
|
27
|
+
expect(Pundit.authorize(user, post, :update?)).to eq(post)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the record when passed record with namespace " do
|
31
|
+
expect(Pundit.authorize(user, [:project, comment], :update?)).to eq(comment)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the record when passed record with nested namespace " do
|
35
|
+
expect(Pundit.authorize(user, [:project, :admin, comment], :update?)).to eq(comment)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns the policy name symbol when passed record with headless policy" do
|
39
|
+
expect(Pundit.authorize(user, :publication, :create?)).to eq(:publication)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns the class when passed record not a particular instance" do
|
43
|
+
expect(Pundit.authorize(user, Post, :show?)).to eq(Post)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can be given a different policy class" do
|
47
|
+
expect(Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy)).to be_truthy
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can be given a different policy class using namespaces" do
|
51
|
+
expect(PublicationPolicy).to receive(:new).with(user, comment).and_call_original
|
52
|
+
expect(Pundit.authorize(user, [:project, comment], :create?, policy_class: PublicationPolicy)).to be_truthy
|
53
|
+
end
|
54
|
+
|
24
55
|
it "works with anonymous class policies" do
|
25
56
|
expect(Pundit.authorize(user, article_tag, :show?)).to be_truthy
|
26
57
|
expect { Pundit.authorize(user, article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
@@ -30,11 +61,30 @@ describe Pundit do
|
|
30
61
|
# rubocop:disable Style/MultilineBlockChain
|
31
62
|
expect do
|
32
63
|
Pundit.authorize(user, post, :destroy?)
|
33
|
-
end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this
|
64
|
+
end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this Post") do |error|
|
34
65
|
expect(error.query).to eq :destroy?
|
35
66
|
expect(error.record).to eq post
|
36
67
|
expect(error.policy).to eq Pundit.policy(user, post)
|
37
68
|
end
|
69
|
+
# rubocop:enable Style/MultilineBlockChain
|
70
|
+
end
|
71
|
+
|
72
|
+
it "raises an error with a the record, query and action when the record is namespaced" do
|
73
|
+
# rubocop:disable Style/MultilineBlockChain
|
74
|
+
expect do
|
75
|
+
Pundit.authorize(user, [:project, :admin, comment], :destroy?)
|
76
|
+
end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this Comment") do |error|
|
77
|
+
expect(error.query).to eq :destroy?
|
78
|
+
expect(error.record).to eq comment
|
79
|
+
expect(error.policy).to eq Pundit.policy(user, [:project, :admin, comment])
|
80
|
+
end
|
81
|
+
# rubocop:enable Style/MultilineBlockChain
|
82
|
+
end
|
83
|
+
|
84
|
+
it "raises an error with a invalid policy constructor" do
|
85
|
+
expect do
|
86
|
+
Pundit.authorize(user, wiki, :update?)
|
87
|
+
end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy> constructor is called")
|
38
88
|
end
|
39
89
|
end
|
40
90
|
|
@@ -44,23 +94,43 @@ describe Pundit do
|
|
44
94
|
end
|
45
95
|
|
46
96
|
it "returns an instantiated policy scope given an active model class" do
|
47
|
-
expect(Pundit.policy_scope(user, Comment)).to eq Comment
|
97
|
+
expect(Pundit.policy_scope(user, Comment)).to eq CommentScope.new(Comment)
|
48
98
|
end
|
49
99
|
|
50
100
|
it "returns an instantiated policy scope given an active record relation" do
|
51
|
-
expect(Pundit.policy_scope(user, comments_relation)).to eq comments_relation
|
101
|
+
expect(Pundit.policy_scope(user, comments_relation)).to eq CommentScope.new(comments_relation)
|
52
102
|
end
|
53
103
|
|
54
104
|
it "returns an instantiated policy scope given an empty active record relation" do
|
55
|
-
expect(Pundit.policy_scope(user, empty_comments_relation)).to eq empty_comments_relation
|
105
|
+
expect(Pundit.policy_scope(user, empty_comments_relation)).to eq CommentScope.new(empty_comments_relation)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns an instantiated policy scope given an array of a symbol and plain model class" do
|
109
|
+
expect(Pundit.policy_scope(user, [:project, Post])).to eq :read
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns an instantiated policy scope given an array of a symbol and active model class" do
|
113
|
+
expect(Pundit.policy_scope(user, [:project, Comment])).to eq Comment
|
56
114
|
end
|
57
115
|
|
58
116
|
it "returns nil if the given policy scope can't be found" do
|
59
117
|
expect(Pundit.policy_scope(user, Article)).to be_nil
|
60
118
|
end
|
61
119
|
|
62
|
-
it "
|
63
|
-
expect
|
120
|
+
it "raises an exception if nil object given" do
|
121
|
+
expect { Pundit.policy_scope(user, nil) }.to raise_error(Pundit::NotDefinedError)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "raises an error with a invalid policy scope constructor" do
|
125
|
+
expect do
|
126
|
+
Pundit.policy_scope(user, Wiki)
|
127
|
+
end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy::Scope> constructor is called")
|
128
|
+
end
|
129
|
+
|
130
|
+
it "raises an original error with a policy scope that contains error" do
|
131
|
+
expect do
|
132
|
+
Pundit.policy_scope(user, Thread)
|
133
|
+
end.to raise_error(ArgumentError)
|
64
134
|
end
|
65
135
|
end
|
66
136
|
|
@@ -70,7 +140,7 @@ describe Pundit do
|
|
70
140
|
end
|
71
141
|
|
72
142
|
it "returns an instantiated policy scope given an active model class" do
|
73
|
-
expect(Pundit.policy_scope!(user, Comment)).to eq Comment
|
143
|
+
expect(Pundit.policy_scope!(user, Comment)).to eq CommentScope.new(Comment)
|
74
144
|
end
|
75
145
|
|
76
146
|
it "throws an exception if the given policy scope can't be found" do
|
@@ -84,7 +154,21 @@ describe Pundit do
|
|
84
154
|
it "throws an exception if the given policy scope is nil" do
|
85
155
|
expect do
|
86
156
|
Pundit.policy_scope!(user, nil)
|
87
|
-
end.to raise_error(Pundit::NotDefinedError, "
|
157
|
+
end.to raise_error(Pundit::NotDefinedError, "Cannot scope NilClass")
|
158
|
+
end
|
159
|
+
|
160
|
+
it "returns an instantiated policy scope given an array of a symbol and plain model class" do
|
161
|
+
expect(Pundit.policy_scope!(user, [:project, Post])).to eq :read
|
162
|
+
end
|
163
|
+
|
164
|
+
it "returns an instantiated policy scope given an array of a symbol and active model class" do
|
165
|
+
expect(Pundit.policy_scope!(user, [:project, Comment])).to eq Comment
|
166
|
+
end
|
167
|
+
|
168
|
+
it "raises an error with a invalid policy scope constructor" do
|
169
|
+
expect do
|
170
|
+
Pundit.policy_scope(user, Wiki)
|
171
|
+
end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy::Scope> constructor is called")
|
88
172
|
end
|
89
173
|
end
|
90
174
|
|
@@ -121,42 +205,62 @@ describe Pundit do
|
|
121
205
|
end
|
122
206
|
|
123
207
|
it "returns an instantiated policy given an array of symbols" do
|
124
|
-
policy = Pundit.policy(user, [
|
208
|
+
policy = Pundit.policy(user, %i[project criteria])
|
125
209
|
expect(policy.class).to eq Project::CriteriaPolicy
|
126
210
|
expect(policy.user).to eq user
|
127
|
-
expect(policy.criteria).to eq
|
211
|
+
expect(policy.criteria).to eq :criteria
|
128
212
|
end
|
129
213
|
|
130
214
|
it "returns an instantiated policy given an array of a symbol and plain model instance" do
|
131
215
|
policy = Pundit.policy(user, [:project, post])
|
132
216
|
expect(policy.class).to eq Project::PostPolicy
|
133
217
|
expect(policy.user).to eq user
|
134
|
-
expect(policy.post).to eq
|
218
|
+
expect(policy.post).to eq post
|
219
|
+
end
|
220
|
+
|
221
|
+
it "returns an instantiated policy given an array of a symbol and a model instance with policy_class override" do
|
222
|
+
policy = Pundit.policy(user, [:project, customer_post])
|
223
|
+
expect(policy.class).to eq Project::PostPolicy
|
224
|
+
expect(policy.user).to eq user
|
225
|
+
expect(policy.post).to eq customer_post
|
135
226
|
end
|
136
227
|
|
137
228
|
it "returns an instantiated policy given an array of a symbol and an active model instance" do
|
138
229
|
policy = Pundit.policy(user, [:project, comment])
|
139
230
|
expect(policy.class).to eq Project::CommentPolicy
|
140
231
|
expect(policy.user).to eq user
|
141
|
-
expect(policy.
|
232
|
+
expect(policy.comment).to eq comment
|
142
233
|
end
|
143
234
|
|
144
235
|
it "returns an instantiated policy given an array of a symbol and a plain model class" do
|
145
236
|
policy = Pundit.policy(user, [:project, Post])
|
146
237
|
expect(policy.class).to eq Project::PostPolicy
|
147
238
|
expect(policy.user).to eq user
|
148
|
-
expect(policy.post).to eq
|
239
|
+
expect(policy.post).to eq Post
|
240
|
+
end
|
241
|
+
|
242
|
+
it "raises an error with a invalid policy constructor" do
|
243
|
+
expect do
|
244
|
+
Pundit.policy(user, Wiki)
|
245
|
+
end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy> constructor is called")
|
149
246
|
end
|
150
247
|
|
151
248
|
it "returns an instantiated policy given an array of a symbol and an active model class" do
|
152
249
|
policy = Pundit.policy(user, [:project, Comment])
|
153
250
|
expect(policy.class).to eq Project::CommentPolicy
|
154
251
|
expect(policy.user).to eq user
|
155
|
-
expect(policy.
|
252
|
+
expect(policy.comment).to eq Comment
|
253
|
+
end
|
254
|
+
|
255
|
+
it "returns an instantiated policy given an array of a symbol and a class with policy_class override" do
|
256
|
+
policy = Pundit.policy(user, [:project, Customer::Post])
|
257
|
+
expect(policy.class).to eq Project::PostPolicy
|
258
|
+
expect(policy.user).to eq user
|
259
|
+
expect(policy.post).to eq Customer::Post
|
156
260
|
end
|
157
261
|
|
158
262
|
it "returns correct policy class for an array of a multi-word symbols" do
|
159
|
-
policy = Pundit.policy(user, [
|
263
|
+
policy = Pundit.policy(user, %i[project_one_two_three criteria_four_five_six])
|
160
264
|
expect(policy.class).to eq ProjectOneTwoThree::CriteriaFourFiveSixPolicy
|
161
265
|
end
|
162
266
|
|
@@ -205,8 +309,8 @@ describe Pundit do
|
|
205
309
|
expect(Pundit.policy(user, Article)).to be_nil
|
206
310
|
end
|
207
311
|
|
208
|
-
it "returns
|
209
|
-
expect(Pundit.policy(user, nil)).to
|
312
|
+
it "returns the specified NilClassPolicy for nil" do
|
313
|
+
expect(Pundit.policy(user, nil)).to be_a NilClassPolicy
|
210
314
|
end
|
211
315
|
|
212
316
|
describe "with .policy_class set on the model" do
|
@@ -269,10 +373,10 @@ describe Pundit do
|
|
269
373
|
end
|
270
374
|
|
271
375
|
it "returns an instantiated policy given an array of symbols" do
|
272
|
-
policy = Pundit.policy!(user, [
|
376
|
+
policy = Pundit.policy!(user, %i[project criteria])
|
273
377
|
expect(policy.class).to eq Project::CriteriaPolicy
|
274
378
|
expect(policy.user).to eq user
|
275
|
-
expect(policy.criteria).to eq
|
379
|
+
expect(policy.criteria).to eq :criteria
|
276
380
|
end
|
277
381
|
|
278
382
|
it "throws an exception if the given policy can't be found" do
|
@@ -280,190 +384,37 @@ describe Pundit do
|
|
280
384
|
expect { Pundit.policy!(user, Article) }.to raise_error(Pundit::NotDefinedError)
|
281
385
|
end
|
282
386
|
|
283
|
-
it "
|
284
|
-
expect
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
describe "#verify_authorized" do
|
289
|
-
it "does nothing when authorized" do
|
290
|
-
controller.authorize(post)
|
291
|
-
controller.verify_authorized
|
292
|
-
end
|
293
|
-
|
294
|
-
it "raises an exception when not authorized" do
|
295
|
-
expect { controller.verify_authorized }.to raise_error(Pundit::AuthorizationNotPerformedError)
|
387
|
+
it "returns the specified NilClassPolicy for nil" do
|
388
|
+
expect(Pundit.policy!(user, nil)).to be_a NilClassPolicy
|
296
389
|
end
|
297
|
-
end
|
298
390
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
end
|
304
|
-
|
305
|
-
it "raises an exception when policy_scope is not used" do
|
306
|
-
expect { controller.verify_policy_scoped }.to raise_error(Pundit::PolicyScopingNotPerformedError)
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
describe "#pundit_policy_authorized?" do
|
311
|
-
it "is true when authorized" do
|
312
|
-
controller.authorize(post)
|
313
|
-
expect(controller.pundit_policy_authorized?).to be true
|
314
|
-
end
|
315
|
-
|
316
|
-
it "is false when not authorized" do
|
317
|
-
expect(controller.pundit_policy_authorized?).to be false
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
describe "#pundit_policy_scoped?" do
|
322
|
-
it "is true when policy_scope is used" do
|
323
|
-
controller.policy_scope(Post)
|
324
|
-
expect(controller.pundit_policy_scoped?).to be true
|
325
|
-
end
|
326
|
-
|
327
|
-
it "is false when policy scope is not used" do
|
328
|
-
expect(controller.pundit_policy_scoped?).to be false
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
describe "#authorize" do
|
333
|
-
it "infers the policy name and authorizes based on it" do
|
334
|
-
expect(controller.authorize(post)).to be_truthy
|
335
|
-
end
|
336
|
-
|
337
|
-
it "can be given a different permission to check" do
|
338
|
-
expect(controller.authorize(post, :show?)).to be_truthy
|
339
|
-
expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
340
|
-
end
|
341
|
-
|
342
|
-
it "works with anonymous class policies" do
|
343
|
-
expect(controller.authorize(article_tag, :show?)).to be_truthy
|
344
|
-
expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
345
|
-
end
|
346
|
-
|
347
|
-
it "throws an exception when the permission check fails" do
|
348
|
-
expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
|
349
|
-
end
|
350
|
-
|
351
|
-
it "throws an exception when a policy cannot be found" do
|
352
|
-
expect { controller.authorize(Article) }.to raise_error(Pundit::NotDefinedError)
|
353
|
-
end
|
354
|
-
|
355
|
-
it "caches the policy" do
|
356
|
-
expect(controller.policies[post]).to be_nil
|
357
|
-
controller.authorize(post)
|
358
|
-
expect(controller.policies[post]).not_to be_nil
|
359
|
-
end
|
360
|
-
|
361
|
-
it "raises an error when the given record is nil" do
|
362
|
-
expect { controller.authorize(nil, :destroy?) }.to raise_error(Pundit::NotDefinedError)
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
describe "#skip_authorization" do
|
367
|
-
it "disables authorization verification" do
|
368
|
-
controller.skip_authorization
|
369
|
-
expect { controller.verify_authorized }.not_to raise_error
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
describe "#skip_policy_scope" do
|
374
|
-
it "disables policy scope verification" do
|
375
|
-
controller.skip_policy_scope
|
376
|
-
expect { controller.verify_policy_scoped }.not_to raise_error
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
describe "#pundit_user" do
|
381
|
-
it "returns the same thing as current_user" do
|
382
|
-
expect(controller.pundit_user).to eq controller.current_user
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
describe "#policy" do
|
387
|
-
it "returns an instantiated policy" do
|
388
|
-
policy = controller.policy(post)
|
389
|
-
expect(policy.user).to eq user
|
390
|
-
expect(policy.post).to eq post
|
391
|
-
end
|
392
|
-
|
393
|
-
it "throws an exception if the given policy can't be found" do
|
394
|
-
expect { controller.policy(article) }.to raise_error(Pundit::NotDefinedError)
|
395
|
-
end
|
396
|
-
|
397
|
-
it "allows policy to be injected" do
|
398
|
-
new_policy = OpenStruct.new
|
399
|
-
controller.policies[post] = new_policy
|
400
|
-
|
401
|
-
expect(controller.policy(post)).to eq new_policy
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
describe "#policy_scope" do
|
406
|
-
it "returns an instantiated policy scope" do
|
407
|
-
expect(controller.policy_scope(Post)).to eq :published
|
408
|
-
end
|
409
|
-
|
410
|
-
it "throws an exception if the given policy can't be found" do
|
411
|
-
expect { controller.policy_scope(Article) }.to raise_error(Pundit::NotDefinedError)
|
412
|
-
end
|
413
|
-
|
414
|
-
it "allows policy_scope to be injected" do
|
415
|
-
new_scope = OpenStruct.new
|
416
|
-
controller.policy_scopes[Post] = new_scope
|
417
|
-
|
418
|
-
expect(controller.policy_scope(Post)).to eq new_scope
|
391
|
+
it "raises an error with a invalid policy constructor" do
|
392
|
+
expect do
|
393
|
+
Pundit.policy(user, Wiki)
|
394
|
+
end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy> constructor is called")
|
419
395
|
end
|
420
396
|
end
|
421
397
|
|
422
|
-
describe "
|
423
|
-
it "
|
424
|
-
|
425
|
-
title: "Hello",
|
426
|
-
votes: 5,
|
427
|
-
admin: true
|
428
|
-
})
|
429
|
-
|
430
|
-
expect(Controller.new(user, params).permitted_attributes(post)).to eq("title" => "Hello", "votes" => 5)
|
431
|
-
expect(Controller.new(double, params).permitted_attributes(post)).to eq("votes" => 5)
|
432
|
-
end
|
398
|
+
describe ".included" do
|
399
|
+
it "includes Authorization module" do
|
400
|
+
klass = Class.new
|
433
401
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
votes: 5,
|
438
|
-
admin: true
|
439
|
-
})
|
402
|
+
ActiveSupport::Deprecation.silence do
|
403
|
+
klass.include Pundit
|
404
|
+
end
|
440
405
|
|
441
|
-
expect(
|
442
|
-
expect(Controller.new(double, params).permitted_attributes(customer_post)).to eq("votes" => 5)
|
406
|
+
expect(klass).to include Pundit::Authorization
|
443
407
|
end
|
444
|
-
end
|
445
|
-
|
446
|
-
describe "#permitted_attributes_for_action" do
|
447
|
-
it "is checked if it is defined in the policy" do
|
448
|
-
params = ActionController::Parameters.new(action: "revise", post: {
|
449
|
-
title: "Hello",
|
450
|
-
body: "blah",
|
451
|
-
votes: 5,
|
452
|
-
admin: true
|
453
|
-
})
|
454
408
|
|
455
|
-
|
456
|
-
|
409
|
+
it "warns about deprecation" do
|
410
|
+
klass = Class.new
|
411
|
+
allow(ActiveSupport::Deprecation).to receive(:warn)
|
457
412
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
body: "blah",
|
462
|
-
votes: 5,
|
463
|
-
admin: true
|
464
|
-
})
|
413
|
+
ActiveSupport::Deprecation.silence do
|
414
|
+
klass.include Pundit
|
415
|
+
end
|
465
416
|
|
466
|
-
expect(
|
417
|
+
expect(ActiveSupport::Deprecation).to have_received(:warn).with start_with("'include Pundit' is deprecated")
|
467
418
|
end
|
468
419
|
end
|
469
420
|
|