pundit 2.0.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,258 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Pundit::Authorization do
6
+ let(:controller) { Controller.new(user, "update", {}) }
7
+ let(:user) { double }
8
+ let(:post) { Post.new(user) }
9
+ let(:customer_post) { Customer::Post.new(user) }
10
+ let(:comment) { Comment.new }
11
+ let(:article) { Article.new }
12
+ let(:article_tag) { ArticleTag.new }
13
+ let(:wiki) { Wiki.new }
14
+
15
+ describe "#verify_authorized" do
16
+ it "does nothing when authorized" do
17
+ controller.authorize(post)
18
+ controller.verify_authorized
19
+ end
20
+
21
+ it "raises an exception when not authorized" do
22
+ expect { controller.verify_authorized }.to raise_error(Pundit::AuthorizationNotPerformedError)
23
+ end
24
+ end
25
+
26
+ describe "#verify_policy_scoped" do
27
+ it "does nothing when policy_scope is used" do
28
+ controller.policy_scope(Post)
29
+ controller.verify_policy_scoped
30
+ end
31
+
32
+ it "raises an exception when policy_scope is not used" do
33
+ expect { controller.verify_policy_scoped }.to raise_error(Pundit::PolicyScopingNotPerformedError)
34
+ end
35
+ end
36
+
37
+ describe "#pundit_policy_authorized?" do
38
+ it "is true when authorized" do
39
+ controller.authorize(post)
40
+ expect(controller.pundit_policy_authorized?).to be true
41
+ end
42
+
43
+ it "is false when not authorized" do
44
+ expect(controller.pundit_policy_authorized?).to be false
45
+ end
46
+ end
47
+
48
+ describe "#pundit_policy_scoped?" do
49
+ it "is true when policy_scope is used" do
50
+ controller.policy_scope(Post)
51
+ expect(controller.pundit_policy_scoped?).to be true
52
+ end
53
+
54
+ it "is false when policy scope is not used" do
55
+ expect(controller.pundit_policy_scoped?).to be false
56
+ end
57
+ end
58
+
59
+ describe "#authorize" do
60
+ it "infers the policy name and authorizes based on it" do
61
+ expect(controller.authorize(post)).to be_truthy
62
+ end
63
+
64
+ it "returns the record on successful authorization" do
65
+ expect(controller.authorize(post)).to eq(post)
66
+ end
67
+
68
+ it "returns the record when passed record with namespace " do
69
+ expect(controller.authorize([:project, comment], :update?)).to eq(comment)
70
+ end
71
+
72
+ it "returns the record when passed record with nested namespace " do
73
+ expect(controller.authorize([:project, :admin, comment], :update?)).to eq(comment)
74
+ end
75
+
76
+ it "returns the policy name symbol when passed record with headless policy" do
77
+ expect(controller.authorize(:publication, :create?)).to eq(:publication)
78
+ end
79
+
80
+ it "returns the class when passed record not a particular instance" do
81
+ expect(controller.authorize(Post, :show?)).to eq(Post)
82
+ end
83
+
84
+ it "can be given a different permission to check" do
85
+ expect(controller.authorize(post, :show?)).to be_truthy
86
+ expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
87
+ end
88
+
89
+ it "can be given a different policy class" do
90
+ expect(controller.authorize(post, :create?, policy_class: PublicationPolicy)).to be_truthy
91
+ end
92
+
93
+ it "works with anonymous class policies" do
94
+ expect(controller.authorize(article_tag, :show?)).to be_truthy
95
+ expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
96
+ end
97
+
98
+ it "throws an exception when the permission check fails" do
99
+ expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
100
+ end
101
+
102
+ it "throws an exception when a policy cannot be found" do
103
+ expect { controller.authorize(Article) }.to raise_error(Pundit::NotDefinedError)
104
+ end
105
+
106
+ it "caches the policy" do
107
+ expect(controller.policies[post]).to be_nil
108
+ controller.authorize(post)
109
+ expect(controller.policies[post]).not_to be_nil
110
+ end
111
+
112
+ it "raises an error when the given record is nil" do
113
+ expect { controller.authorize(nil, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
114
+ end
115
+
116
+ it "raises an error with a invalid policy constructor" do
117
+ expect { controller.authorize(wiki, :destroy?) }.to raise_error(Pundit::InvalidConstructorError)
118
+ end
119
+ end
120
+
121
+ describe "#skip_authorization" do
122
+ it "disables authorization verification" do
123
+ controller.skip_authorization
124
+ expect { controller.verify_authorized }.not_to raise_error
125
+ end
126
+ end
127
+
128
+ describe "#skip_policy_scope" do
129
+ it "disables policy scope verification" do
130
+ controller.skip_policy_scope
131
+ expect { controller.verify_policy_scoped }.not_to raise_error
132
+ end
133
+ end
134
+
135
+ describe "#pundit_user" do
136
+ it "returns the same thing as current_user" do
137
+ expect(controller.pundit_user).to eq controller.current_user
138
+ end
139
+ end
140
+
141
+ describe "#policy" do
142
+ it "returns an instantiated policy" do
143
+ policy = controller.policy(post)
144
+ expect(policy.user).to eq user
145
+ expect(policy.post).to eq post
146
+ end
147
+
148
+ it "throws an exception if the given policy can't be found" do
149
+ expect { controller.policy(article) }.to raise_error(Pundit::NotDefinedError)
150
+ end
151
+
152
+ it "raises an error with a invalid policy constructor" do
153
+ expect { controller.policy(wiki) }.to raise_error(Pundit::InvalidConstructorError)
154
+ end
155
+
156
+ it "allows policy to be injected" do
157
+ new_policy = OpenStruct.new
158
+ controller.policies[post] = new_policy
159
+
160
+ expect(controller.policy(post)).to eq new_policy
161
+ end
162
+ end
163
+
164
+ describe "#policy_scope" do
165
+ it "returns an instantiated policy scope" do
166
+ expect(controller.policy_scope(Post)).to eq :published
167
+ end
168
+
169
+ it "allows policy scope class to be overriden" do
170
+ expect(controller.policy_scope(Post, policy_scope_class: PublicationPolicy::Scope)).to eq :published
171
+ end
172
+
173
+ it "throws an exception if the given policy can't be found" do
174
+ expect { controller.policy_scope(Article) }.to raise_error(Pundit::NotDefinedError)
175
+ end
176
+
177
+ it "raises an error with a invalid policy scope constructor" do
178
+ expect { controller.policy_scope(Wiki) }.to raise_error(Pundit::InvalidConstructorError)
179
+ end
180
+
181
+ it "allows policy_scope to be injected" do
182
+ new_scope = OpenStruct.new
183
+ controller.policy_scopes[Post] = new_scope
184
+
185
+ expect(controller.policy_scope(Post)).to eq new_scope
186
+ end
187
+ end
188
+
189
+ describe "#permitted_attributes" do
190
+ it "checks policy for permitted attributes" do
191
+ params = ActionController::Parameters.new(
192
+ post: {
193
+ title: "Hello",
194
+ votes: 5,
195
+ admin: true
196
+ }
197
+ )
198
+
199
+ action = "update"
200
+
201
+ expect(Controller.new(user, action, params).permitted_attributes(post).to_h).to eq(
202
+ "title" => "Hello",
203
+ "votes" => 5
204
+ )
205
+ expect(Controller.new(double, action, params).permitted_attributes(post).to_h).to eq("votes" => 5)
206
+ end
207
+
208
+ it "checks policy for permitted attributes for record of a ActiveModel type" do
209
+ params = ActionController::Parameters.new(
210
+ customer_post: {
211
+ title: "Hello",
212
+ votes: 5,
213
+ admin: true
214
+ }
215
+ )
216
+
217
+ action = "update"
218
+
219
+ expect(Controller.new(user, action, params).permitted_attributes(customer_post).to_h).to eq(
220
+ "title" => "Hello",
221
+ "votes" => 5
222
+ )
223
+ expect(Controller.new(double, action, params).permitted_attributes(customer_post).to_h).to eq(
224
+ "votes" => 5
225
+ )
226
+ end
227
+ end
228
+
229
+ describe "#permitted_attributes_for_action" do
230
+ it "is checked if it is defined in the policy" do
231
+ params = ActionController::Parameters.new(
232
+ post: {
233
+ title: "Hello",
234
+ body: "blah",
235
+ votes: 5,
236
+ admin: true
237
+ }
238
+ )
239
+
240
+ action = "revise"
241
+ expect(Controller.new(user, action, params).permitted_attributes(post).to_h).to eq("body" => "blah")
242
+ end
243
+
244
+ it "can be explicitly set" do
245
+ params = ActionController::Parameters.new(
246
+ post: {
247
+ title: "Hello",
248
+ body: "blah",
249
+ votes: 5,
250
+ admin: true
251
+ }
252
+ )
253
+
254
+ action = "update"
255
+ expect(Controller.new(user, action, params).permitted_attributes(post, :revise).to_h).to eq("body" => "blah")
256
+ end
257
+ end
258
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "tmpdir"
5
+
6
+ require "rails/generators"
7
+ require "generators/pundit/install/install_generator"
8
+ require "generators/pundit/policy/policy_generator"
9
+
10
+ RSpec.describe "generators" do
11
+ before(:all) do
12
+ @tmpdir = Dir.mktmpdir
13
+
14
+ Dir.chdir(@tmpdir) do
15
+ Pundit::Generators::InstallGenerator.new([], { quiet: true }).invoke_all
16
+ Pundit::Generators::PolicyGenerator.new(%w[Widget], { quiet: true }).invoke_all
17
+
18
+ require "./app/policies/application_policy"
19
+ require "./app/policies/widget_policy"
20
+ end
21
+ end
22
+
23
+ after(:all) do
24
+ FileUtils.remove_entry(@tmpdir)
25
+ end
26
+
27
+ describe "WidgetPolicy", type: :policy do
28
+ permissions :index?, :show?, :create?, :new?, :update?, :edit?, :destroy? do
29
+ it "has safe defaults" do
30
+ expect(WidgetPolicy).not_to permit(double("User"), double("Widget"))
31
+ end
32
+ end
33
+
34
+ describe "WidgetPolicy::Scope" do
35
+ describe "#resolve" do
36
+ it "raises a descriptive error" do
37
+ scope = WidgetPolicy::Scope.new(double("User"), double("User.all"))
38
+ expect { scope.resolve }.to raise_error(NotImplementedError, /WidgetPolicy::Scope/)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
- describe PostPolicy do
5
+ RSpec.describe PostPolicy do
4
6
  let(:user) { double }
5
7
  let(:own_post) { double(user: user) }
6
8
  let(:other_post) { double(user: double) }
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
- describe Pundit::PolicyFinder do
5
+ class Foo; end
6
+ RSpec.describe Pundit::PolicyFinder do
4
7
  let(:user) { double }
5
8
  let(:post) { Post.new(user) }
6
9
  let(:comment) { CommentFourFiveSix.new }
@@ -22,37 +25,99 @@ describe Pundit::PolicyFinder do
22
25
  end
23
26
 
24
27
  describe "#policy" do
25
- subject { described_class.new(post) }
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
26
43
 
27
- it "returns a policy" do
28
- expect(subject.policy).to eq PostPolicy
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
29
50
  end
30
51
 
31
- context "with a string" do
32
- it "returns a policy" do
33
- allow(subject).to receive(:find).and_return "PostPolicy"
34
- expect(subject.policy).to eq PostPolicy
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
35
65
  end
36
66
  end
37
67
 
38
68
  context "with a class" do
39
- it "returns a policy" do
40
- allow(subject).to receive(:find).and_return PostPolicy
41
- expect(subject.policy).to eq PostPolicy
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
42
105
  end
43
106
  end
44
107
 
45
108
  context "with nil" do
46
- it "returns nil" do
47
- allow(subject).to receive(:find).and_return nil
48
- expect(subject.policy).to eq nil
109
+ it "returns a NilClassPolicy" do
110
+ object = described_class.new(nil)
111
+
112
+ expect(object.policy).to eq NilClassPolicy
49
113
  end
50
114
  end
51
115
 
52
- context "with a string that can't be constantized" do
116
+ context "with a class that doesn't have an associated policy" do
53
117
  it "returns nil" do
54
- allow(subject).to receive(:find).and_return "FooPolicy"
55
- expect(subject.policy).to eq nil
118
+ object = described_class.new(Foo)
119
+
120
+ expect(object.policy).to eq nil
56
121
  end
57
122
  end
58
123
  end