pundit 2.3.2 → 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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
  4. data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +4 -4
  5. data/.github/workflows/main.yml +92 -52
  6. data/.github/workflows/push_gem.yml +4 -4
  7. data/.rubocop.yml +18 -8
  8. data/.rubocop_ignore_git.yml +7 -0
  9. data/.yardopts +1 -1
  10. data/CHANGELOG.md +68 -37
  11. data/CODE_OF_CONDUCT.md +1 -1
  12. data/CONTRIBUTING.md +1 -0
  13. data/Gemfile +22 -2
  14. data/README.md +88 -15
  15. data/Rakefile +1 -0
  16. data/lib/generators/pundit/install/install_generator.rb +3 -1
  17. data/lib/generators/pundit/policy/policy_generator.rb +3 -1
  18. data/lib/generators/rspec/policy_generator.rb +4 -1
  19. data/lib/generators/test_unit/policy_generator.rb +4 -1
  20. data/lib/pundit/authorization.rb +152 -77
  21. data/lib/pundit/cache_store/legacy_store.rb +7 -0
  22. data/lib/pundit/cache_store/null_store.rb +9 -0
  23. data/lib/pundit/cache_store.rb +22 -0
  24. data/lib/pundit/context.rb +76 -26
  25. data/lib/pundit/policy_finder.rb +22 -1
  26. data/lib/pundit/railtie.rb +19 -0
  27. data/lib/pundit/rspec.rb +90 -7
  28. data/lib/pundit/version.rb +2 -1
  29. data/lib/pundit.rb +43 -15
  30. data/pundit.gemspec +8 -12
  31. data/spec/authorization_spec.rb +61 -4
  32. data/spec/policies/post_policy_spec.rb +27 -0
  33. data/spec/policy_finder_spec.rb +5 -1
  34. data/spec/pundit/helper_spec.rb +18 -0
  35. data/spec/pundit_spec.rb +58 -15
  36. data/spec/rspec_dsl_spec.rb +81 -0
  37. data/spec/simple_cov_check_action_formatter.rb +79 -0
  38. data/spec/spec_helper.rb +22 -339
  39. data/spec/support/lib/controller.rb +38 -0
  40. data/spec/support/lib/custom_cache.rb +19 -0
  41. data/spec/support/lib/instance_tracking.rb +20 -0
  42. data/spec/support/models/article.rb +4 -0
  43. data/spec/support/models/article_tag.rb +7 -0
  44. data/spec/support/models/artificial_blog.rb +7 -0
  45. data/spec/support/models/blog.rb +4 -0
  46. data/spec/support/models/comment.rb +5 -0
  47. data/spec/support/models/comment_four_five_six.rb +5 -0
  48. data/spec/support/models/comment_scope.rb +13 -0
  49. data/spec/support/models/comments_relation.rb +15 -0
  50. data/spec/support/models/customer/post.rb +11 -0
  51. data/spec/support/models/default_scope_contains_error.rb +5 -0
  52. data/spec/support/models/dummy_current_user.rb +7 -0
  53. data/spec/support/models/foo.rb +4 -0
  54. data/spec/support/models/post.rb +25 -0
  55. data/spec/support/models/post_four_five_six.rb +9 -0
  56. data/spec/support/models/project_one_two_three/avatar_four_five_six.rb +7 -0
  57. data/spec/support/models/project_one_two_three/tag_four_five_six.rb +11 -0
  58. data/spec/support/models/wiki.rb +4 -0
  59. data/spec/support/policies/article_tag_other_name_policy.rb +13 -0
  60. data/spec/support/policies/base_policy.rb +23 -0
  61. data/spec/support/policies/blog_policy.rb +5 -0
  62. data/spec/support/policies/comment_policy.rb +11 -0
  63. data/spec/support/policies/criteria_policy.rb +5 -0
  64. data/spec/support/policies/default_scope_contains_error_policy.rb +10 -0
  65. data/spec/support/policies/denier_policy.rb +7 -0
  66. data/spec/support/policies/dummy_current_user_policy.rb +9 -0
  67. data/spec/support/policies/nil_class_policy.rb +17 -0
  68. data/spec/support/policies/post_policy.rb +36 -0
  69. data/spec/support/policies/project/admin/comment_policy.rb +15 -0
  70. data/spec/support/policies/project/comment_policy.rb +17 -0
  71. data/spec/support/policies/project/criteria_policy.rb +7 -0
  72. data/spec/support/policies/project/post_policy.rb +13 -0
  73. data/spec/support/policies/project_one_two_three/avatar_four_five_six_policy.rb +6 -0
  74. data/spec/support/policies/project_one_two_three/comment_four_five_six_policy.rb +6 -0
  75. data/spec/support/policies/project_one_two_three/criteria_four_five_six_policy.rb +6 -0
  76. data/spec/support/policies/project_one_two_three/post_four_five_six_policy.rb +6 -0
  77. data/spec/support/policies/project_one_two_three/tag_four_five_six_policy.rb +6 -0
  78. data/spec/support/policies/publication_policy.rb +13 -0
  79. data/spec/support/policies/wiki_policy.rb +8 -0
  80. metadata +66 -158
  81. /data/.github/{PULL_REQUEST_TEMPLATE/pull_request_template.md → pull_request_template.md} +0 -0
  82. /data/lib/generators/pundit/install/templates/{application_policy.rb → application_policy.rb.tt} +0 -0
  83. /data/lib/generators/pundit/policy/templates/{policy.rb → policy.rb.tt} +0 -0
  84. /data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
  85. /data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
@@ -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,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CustomCache
4
+ def initialize
5
+ @store = {}
6
+ end
7
+
8
+ def to_h
9
+ @store
10
+ end
11
+
12
+ def [](key)
13
+ @store[key]
14
+ end
15
+
16
+ def []=(key, value)
17
+ @store[key] = value
18
+ end
19
+ 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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Article
4
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ArticleTag
4
+ def self.policy_class
5
+ ArticleTagOtherNamePolicy
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ArtificialBlog < Blog
4
+ def self.policy_class
5
+ BlogPolicy
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Blog
4
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comment
4
+ extend ActiveModel::Naming
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentFourFiveSix
4
+ extend ActiveModel::Naming
5
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentScope
4
+ attr_reader :original_object
5
+
6
+ def initialize(original_object)
7
+ @original_object = original_object
8
+ end
9
+
10
+ def ==(other)
11
+ original_object == other.original_object
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentsRelation
4
+ def initialize(empty: false)
5
+ @empty = empty
6
+ end
7
+
8
+ def blank?
9
+ @empty
10
+ end
11
+
12
+ def self.model_name
13
+ Comment.model_name
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Customer
4
+ class Post < ::Post
5
+ extend ActiveModel::Naming
6
+
7
+ def self.policy_class
8
+ PostPolicy
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DefaultScopeContainsError
4
+ def self.all; end
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DummyCurrentUser
4
+ def update?
5
+ user
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Foo
4
+ 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,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PostFourFiveSix
4
+ def initialize(user)
5
+ @user = user
6
+ end
7
+
8
+ attr_reader(:user)
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class AvatarFourFiveSix
5
+ extend ActiveModel::Naming
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class TagFourFiveSix
5
+ def initialize(user)
6
+ @user = user
7
+ end
8
+
9
+ attr_reader(:user)
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Wiki
4
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ArticleTagOtherNamePolicy < BasePolicy
4
+ def show?
5
+ true
6
+ end
7
+
8
+ def destroy?
9
+ false
10
+ end
11
+
12
+ alias tag record
13
+ 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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BlogPolicy < BasePolicy
4
+ alias blog record
5
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentPolicy < BasePolicy
4
+ class Scope < BaseScope
5
+ def resolve
6
+ CommentScope.new(scope)
7
+ end
8
+ end
9
+
10
+ alias comment record
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CriteriaPolicy < BasePolicy
4
+ alias criteria record
5
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DefaultScopeContainsErrorPolicy < BasePolicy
4
+ class Scope < BaseScope
5
+ def resolve
6
+ # deliberate wrong usage of the method
7
+ raise "This is an arbitrary error that should bubble up"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DenierPolicy < BasePolicy
4
+ def update?
5
+ false
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DummyCurrentUserPolicy < BasePolicy
4
+ class Scope < BasePolicy::BaseScope
5
+ def resolve
6
+ user
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NilClassPolicy < BasePolicy
4
+ class Scope
5
+ def initialize(*)
6
+ raise Pundit::NotDefinedError, "Cannot scope NilClass"
7
+ end
8
+ end
9
+
10
+ def show?
11
+ false
12
+ end
13
+
14
+ def destroy?
15
+ false
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PostPolicy < BasePolicy
4
+ class Scope < BaseScope
5
+ def resolve
6
+ scope.published
7
+ end
8
+ end
9
+
10
+ alias post record
11
+
12
+ def update?
13
+ post.user == user
14
+ end
15
+ alias edit? update?
16
+
17
+ def destroy?
18
+ false
19
+ end
20
+
21
+ def show?
22
+ true
23
+ end
24
+
25
+ def permitted_attributes
26
+ if post.user == user
27
+ %i[title votes]
28
+ else
29
+ [:votes]
30
+ end
31
+ end
32
+
33
+ def permitted_attributes_for_revise
34
+ [:body]
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Project
4
+ module Admin
5
+ class CommentPolicy < BasePolicy
6
+ def update?
7
+ true
8
+ end
9
+
10
+ def destroy?
11
+ false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Project
4
+ class CommentPolicy < BasePolicy
5
+ class Scope < BaseScope
6
+ def resolve
7
+ scope
8
+ end
9
+ end
10
+
11
+ def update?
12
+ true
13
+ end
14
+
15
+ alias comment record
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Project
4
+ class CriteriaPolicy < BasePolicy
5
+ alias criteria record
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Project
4
+ class PostPolicy < BasePolicy
5
+ class Scope < BaseScope
6
+ def resolve
7
+ scope.read
8
+ end
9
+ end
10
+
11
+ alias post record
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class AvatarFourFiveSixPolicy < BasePolicy
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class CommentFourFiveSixPolicy < BasePolicy
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class CriteriaFourFiveSixPolicy < BasePolicy
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class PostFourFiveSixPolicy < BasePolicy
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectOneTwoThree
4
+ class TagFourFiveSixPolicy < BasePolicy
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PublicationPolicy < BasePolicy
4
+ class Scope < BaseScope
5
+ def resolve
6
+ scope.published
7
+ end
8
+ end
9
+
10
+ def create?
11
+ true
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class WikiPolicy
4
+ class Scope
5
+ # deliberate typo method
6
+ def initalize; end
7
+ end
8
+ end