pundit 2.1.0 → 2.5.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/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
- data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +8 -0
- data/.github/pull_request_template.md +9 -0
- data/.github/workflows/main.yml +147 -0
- data/.github/workflows/push_gem.yml +33 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +26 -29
- data/.rubocop_ignore_git.yml +7 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +120 -21
- data/CODE_OF_CONDUCT.md +1 -1
- data/CONTRIBUTING.md +3 -5
- data/Gemfile +23 -2
- data/README.md +175 -78
- data/Rakefile +1 -0
- data/SECURITY.md +19 -0
- data/config/rubocop-rspec.yml +5 -0
- data/lib/generators/pundit/install/install_generator.rb +6 -2
- data/lib/generators/pundit/install/templates/{application_policy.rb → application_policy.rb.tt} +7 -3
- data/lib/generators/pundit/policy/policy_generator.rb +6 -2
- data/lib/generators/pundit/policy/templates/policy.rb.tt +16 -0
- data/lib/generators/rspec/policy_generator.rb +7 -2
- data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +1 -1
- data/lib/generators/test_unit/policy_generator.rb +7 -2
- data/lib/pundit/authorization.rb +251 -0
- data/lib/pundit/cache_store/legacy_store.rb +24 -0
- data/lib/pundit/cache_store/null_store.rb +27 -0
- data/lib/pundit/cache_store.rb +22 -0
- data/lib/pundit/context.rb +177 -0
- data/lib/pundit/policy_finder.rb +24 -3
- data/lib/pundit/railtie.rb +19 -0
- data/lib/pundit/rspec.rb +93 -20
- data/lib/pundit/version.rb +2 -1
- data/lib/pundit.rb +68 -257
- data/pundit.gemspec +10 -10
- data/spec/authorization_spec.rb +331 -0
- data/spec/generators_spec.rb +43 -0
- data/spec/policies/post_policy_spec.rb +28 -1
- data/spec/policy_finder_spec.rb +84 -17
- data/spec/pundit/helper_spec.rb +18 -0
- data/spec/pundit_spec.rb +110 -233
- data/spec/rspec_dsl_spec.rb +81 -0
- data/spec/simple_cov_check_action_formatter.rb +79 -0
- data/spec/spec_helper.rb +29 -265
- data/spec/support/lib/controller.rb +38 -0
- data/spec/support/lib/custom_cache.rb +19 -0
- data/spec/support/lib/instance_tracking.rb +20 -0
- data/spec/support/models/article.rb +4 -0
- data/spec/support/models/article_tag.rb +7 -0
- data/spec/support/models/artificial_blog.rb +7 -0
- data/spec/support/models/blog.rb +4 -0
- data/spec/support/models/comment.rb +5 -0
- data/spec/support/models/comment_four_five_six.rb +5 -0
- data/spec/support/models/comment_scope.rb +13 -0
- data/spec/support/models/comments_relation.rb +15 -0
- data/spec/support/models/customer/post.rb +11 -0
- data/spec/support/models/default_scope_contains_error.rb +5 -0
- data/spec/support/models/dummy_current_user.rb +7 -0
- data/spec/support/models/foo.rb +4 -0
- data/spec/support/models/post.rb +25 -0
- data/spec/support/models/post_four_five_six.rb +9 -0
- data/spec/support/models/project_one_two_three/avatar_four_five_six.rb +7 -0
- data/spec/support/models/project_one_two_three/tag_four_five_six.rb +11 -0
- data/spec/support/models/wiki.rb +4 -0
- data/spec/support/policies/article_tag_other_name_policy.rb +13 -0
- data/spec/support/policies/base_policy.rb +23 -0
- data/spec/support/policies/blog_policy.rb +5 -0
- data/spec/support/policies/comment_policy.rb +11 -0
- data/spec/support/policies/criteria_policy.rb +5 -0
- data/spec/support/policies/default_scope_contains_error_policy.rb +10 -0
- data/spec/support/policies/denier_policy.rb +7 -0
- data/spec/support/policies/dummy_current_user_policy.rb +9 -0
- data/spec/support/policies/nil_class_policy.rb +17 -0
- data/spec/support/policies/post_policy.rb +36 -0
- data/spec/support/policies/project/admin/comment_policy.rb +15 -0
- data/spec/support/policies/project/comment_policy.rb +17 -0
- data/spec/support/policies/project/criteria_policy.rb +7 -0
- data/spec/support/policies/project/post_policy.rb +13 -0
- data/spec/support/policies/project_one_two_three/avatar_four_five_six_policy.rb +6 -0
- data/spec/support/policies/project_one_two_three/comment_four_five_six_policy.rb +6 -0
- data/spec/support/policies/project_one_two_three/criteria_four_five_six_policy.rb +6 -0
- data/spec/support/policies/project_one_two_three/post_four_five_six_policy.rb +6 -0
- data/spec/support/policies/project_one_two_three/tag_four_five_six_policy.rb +6 -0
- data/spec/support/policies/publication_policy.rb +13 -0
- data/spec/support/policies/wiki_policy.rb +8 -0
- metadata +80 -130
- data/.travis.yml +0 -21
- data/lib/generators/pundit/policy/templates/policy.rb +0 -9
- /data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
data/spec/spec_helper.rb
CHANGED
@@ -1,271 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
if ENV["COVERAGE"]
|
4
|
+
require "simplecov"
|
5
|
+
require "simplecov_json_formatter"
|
6
|
+
require_relative "simple_cov_check_action_formatter"
|
7
|
+
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
|
8
|
+
SimpleCov::Formatter::HTMLFormatter,
|
9
|
+
SimpleCov::Formatter::JSONFormatter,
|
10
|
+
SimpleCovCheckActionFormatter.with_options(
|
11
|
+
output_filename: "simplecov-check-action.json"
|
12
|
+
)
|
13
|
+
])
|
14
|
+
SimpleCov.start do
|
15
|
+
add_filter "/spec/"
|
16
|
+
enable_coverage :branch
|
17
|
+
primary_coverage :branch
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @see https://github.com/rails/rails/issues/54260
|
22
|
+
require "logger" if RUBY_ENGINE == "jruby" && RUBY_ENGINE_VERSION.start_with?("9.3")
|
23
|
+
|
3
24
|
require "pundit"
|
4
25
|
require "pundit/rspec"
|
5
|
-
|
6
|
-
require "rack"
|
7
|
-
require "rack/test"
|
8
|
-
require "pry"
|
9
|
-
require "active_support"
|
10
|
-
require "active_support/core_ext"
|
11
26
|
require "active_model/naming"
|
12
|
-
require "action_controller/metal/strong_parameters"
|
13
|
-
|
14
|
-
I18n.enforce_available_locales = false
|
15
|
-
|
16
|
-
module PunditSpecHelper
|
17
|
-
extend RSpec::Matchers::DSL
|
18
|
-
|
19
|
-
matcher :be_truthy do
|
20
|
-
match do |actual|
|
21
|
-
actual
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
RSpec.configure do |config|
|
27
|
-
config.include PunditSpecHelper
|
28
|
-
end
|
29
|
-
|
30
|
-
class PostPolicy < Struct.new(:user, :post)
|
31
|
-
class Scope < Struct.new(:user, :scope)
|
32
|
-
def resolve
|
33
|
-
scope.published
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def update?
|
38
|
-
post.user == user
|
39
|
-
end
|
40
|
-
|
41
|
-
def destroy?
|
42
|
-
false
|
43
|
-
end
|
44
|
-
|
45
|
-
def show?
|
46
|
-
true
|
47
|
-
end
|
48
|
-
|
49
|
-
def permitted_attributes
|
50
|
-
if post.user == user
|
51
|
-
%i[title votes]
|
52
|
-
else
|
53
|
-
[:votes]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def permitted_attributes_for_revise
|
58
|
-
[:body]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class Post < Struct.new(:user)
|
63
|
-
def self.published
|
64
|
-
:published
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.read
|
68
|
-
:read
|
69
|
-
end
|
70
|
-
|
71
|
-
def to_s
|
72
|
-
"Post"
|
73
|
-
end
|
74
|
-
|
75
|
-
def inspect
|
76
|
-
"#<Post>"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
module Customer
|
81
|
-
class Post < Post
|
82
|
-
def model_name
|
83
|
-
OpenStruct.new(param_key: "customer_post")
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.policy_class
|
87
|
-
PostPolicy
|
88
|
-
end
|
89
|
-
|
90
|
-
def policy_class
|
91
|
-
self.class.policy_class
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
class CommentScope
|
97
|
-
attr_reader :original_object
|
98
|
-
def initialize(original_object)
|
99
|
-
@original_object = original_object
|
100
|
-
end
|
101
|
-
|
102
|
-
def ==(other)
|
103
|
-
original_object == other.original_object
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
class CommentPolicy < Struct.new(:user, :comment)
|
108
|
-
class Scope < Struct.new(:user, :scope)
|
109
|
-
def resolve
|
110
|
-
CommentScope.new(scope)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class PublicationPolicy < Struct.new(:user, :publication)
|
116
|
-
class Scope < Struct.new(:user, :scope)
|
117
|
-
def resolve
|
118
|
-
scope.published
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def create?
|
123
|
-
true
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
class Comment
|
128
|
-
extend ActiveModel::Naming
|
129
|
-
end
|
130
|
-
|
131
|
-
class CommentsRelation
|
132
|
-
def initialize(empty = false)
|
133
|
-
@empty = empty
|
134
|
-
end
|
135
|
-
|
136
|
-
def blank?
|
137
|
-
@empty
|
138
|
-
end
|
139
27
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
class Blog; end
|
150
|
-
|
151
|
-
class ArtificialBlog < Blog
|
152
|
-
def self.policy_class
|
153
|
-
BlogPolicy
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
class ArticleTagOtherNamePolicy < Struct.new(:user, :tag)
|
158
|
-
def show?
|
159
|
-
true
|
160
|
-
end
|
161
|
-
|
162
|
-
def destroy?
|
163
|
-
false
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
class ArticleTag
|
168
|
-
def self.policy_class
|
169
|
-
ArticleTagOtherNamePolicy
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
class CriteriaPolicy < Struct.new(:user, :criteria); end
|
174
|
-
|
175
|
-
module Project
|
176
|
-
class CommentPolicy < Struct.new(:user, :comment)
|
177
|
-
class Scope < Struct.new(:user, :scope)
|
178
|
-
def resolve
|
179
|
-
scope
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
class CriteriaPolicy < Struct.new(:user, :criteria); end
|
185
|
-
|
186
|
-
class PostPolicy < Struct.new(:user, :post)
|
187
|
-
class Scope < Struct.new(:user, :scope)
|
188
|
-
def resolve
|
189
|
-
scope.read
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
class DenierPolicy < Struct.new(:user, :record)
|
196
|
-
def update?
|
197
|
-
false
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
class Controller
|
202
|
-
include Pundit
|
203
|
-
# Mark protected methods public so they may be called in test
|
204
|
-
# rubocop:disable Layout/AccessModifierIndentation, Style/AccessModifierDeclarations
|
205
|
-
public(*Pundit.protected_instance_methods)
|
206
|
-
# rubocop:enable Layout/AccessModifierIndentation, Style/AccessModifierDeclarations
|
207
|
-
|
208
|
-
attr_reader :current_user, :action_name, :params
|
209
|
-
|
210
|
-
def initialize(current_user, action_name, params)
|
211
|
-
@current_user = current_user
|
212
|
-
@action_name = action_name
|
213
|
-
@params = params
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
class NilClassPolicy < Struct.new(:user, :record)
|
218
|
-
class Scope
|
219
|
-
def initialize(*)
|
220
|
-
raise Pundit::NotDefinedError, "Cannot scope NilClass"
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def show?
|
225
|
-
false
|
226
|
-
end
|
227
|
-
|
228
|
-
def destroy?
|
229
|
-
false
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
class Wiki; end
|
234
|
-
class WikiPolicy
|
235
|
-
class Scope
|
236
|
-
# deliberate typo method
|
237
|
-
def initalize; end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
class Thread
|
242
|
-
def self.all; end
|
243
|
-
end
|
244
|
-
class ThreadPolicy < Struct.new(:user, :thread)
|
245
|
-
class Scope < Struct.new(:user, :scope)
|
246
|
-
def resolve
|
247
|
-
# deliberate wrong useage of the method
|
248
|
-
scope.all(:unvalid, :parameters)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
class PostFourFiveSix < Struct.new(:user); end
|
254
|
-
|
255
|
-
class CommentFourFiveSix; extend ActiveModel::Naming; end
|
256
|
-
|
257
|
-
module ProjectOneTwoThree
|
258
|
-
class CommentFourFiveSixPolicy < Struct.new(:user, :post); end
|
259
|
-
|
260
|
-
class CriteriaFourFiveSixPolicy < Struct.new(:user, :criteria); end
|
261
|
-
|
262
|
-
class PostFourFiveSixPolicy < Struct.new(:user, :post); end
|
263
|
-
|
264
|
-
class TagFourFiveSix < Struct.new(:user); end
|
265
|
-
|
266
|
-
class TagFourFiveSixPolicy < Struct.new(:user, :tag); end
|
267
|
-
|
268
|
-
class AvatarFourFiveSix; extend ActiveModel::Naming; end
|
269
|
-
|
270
|
-
class AvatarFourFiveSixPolicy < Struct.new(:user, :avatar); end
|
271
|
-
end
|
28
|
+
# Load all supporting files: models, policies, etc.
|
29
|
+
require "zeitwerk"
|
30
|
+
loader = Zeitwerk::Loader.new
|
31
|
+
loader.push_dir(File.expand_path("support/models", __dir__))
|
32
|
+
loader.push_dir(File.expand_path("support/policies", __dir__))
|
33
|
+
loader.push_dir(File.expand_path("support/lib", __dir__))
|
34
|
+
loader.setup
|
35
|
+
loader.eager_load
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Controller
|
4
|
+
attr_accessor :current_user
|
5
|
+
attr_reader :action_name, :params
|
6
|
+
|
7
|
+
class View
|
8
|
+
def initialize(controller)
|
9
|
+
@controller = controller
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :controller
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def helper(mod)
|
17
|
+
View.include(mod)
|
18
|
+
end
|
19
|
+
|
20
|
+
def helper_method(method)
|
21
|
+
View.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
22
|
+
def #{method}(*args, **kwargs, &block)
|
23
|
+
controller.send(:#{method}, *args, **kwargs, &block)
|
24
|
+
end
|
25
|
+
RUBY
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
include Pundit::Authorization
|
30
|
+
# Mark protected methods public so they may be called in test
|
31
|
+
public(*Pundit::Authorization.protected_instance_methods)
|
32
|
+
|
33
|
+
def initialize(current_user, action_name, params)
|
34
|
+
@current_user = current_user
|
35
|
+
@action_name = action_name
|
36
|
+
@params = params
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InstanceTracking
|
4
|
+
module ClassMethods
|
5
|
+
def instances
|
6
|
+
@instances || 0
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_writer :instances
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.prepended(other)
|
13
|
+
other.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(*args, **kwargs, &block)
|
17
|
+
self.class.instances += 1
|
18
|
+
super(*args, **kwargs, &block)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Post
|
4
|
+
def initialize(user = nil)
|
5
|
+
@user = user
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :user
|
9
|
+
|
10
|
+
def self.published
|
11
|
+
:published
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.read
|
15
|
+
:read
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"Post"
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<Post>"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class BasePolicy
|
4
|
+
prepend InstanceTracking
|
5
|
+
|
6
|
+
class BaseScope
|
7
|
+
prepend InstanceTracking
|
8
|
+
|
9
|
+
def initialize(user, scope)
|
10
|
+
@user = user
|
11
|
+
@scope = scope
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :user, :scope
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(user, record)
|
18
|
+
@user = user
|
19
|
+
@record = record
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :user, :record
|
23
|
+
end
|