action_policy 0.2.4 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -64
  3. data/.travis.yml +13 -10
  4. data/CHANGELOG.md +216 -1
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +1 -1
  7. data/Rakefile +10 -0
  8. data/action_policy.gemspec +5 -3
  9. data/benchmarks/namespaced_lookup_cache.rb +18 -22
  10. data/docs/README.md +3 -3
  11. data/docs/_sidebar.md +4 -0
  12. data/docs/aliases.md +9 -5
  13. data/docs/authorization_context.md +59 -1
  14. data/docs/behaviour.md +113 -0
  15. data/docs/caching.md +6 -4
  16. data/docs/custom_policy.md +1 -2
  17. data/docs/debugging.md +55 -0
  18. data/docs/decorators.md +27 -0
  19. data/docs/i18n.md +41 -2
  20. data/docs/instrumentation.md +70 -2
  21. data/docs/lookup_chain.md +5 -4
  22. data/docs/namespaces.md +1 -1
  23. data/docs/non_rails.md +2 -3
  24. data/docs/pundit_migration.md +77 -2
  25. data/docs/quick_start.md +5 -5
  26. data/docs/rails.md +5 -2
  27. data/docs/reasons.md +50 -3
  28. data/docs/scoping.md +262 -0
  29. data/docs/testing.md +232 -21
  30. data/docs/writing_policies.md +1 -1
  31. data/gemfiles/jruby.gemfile +3 -0
  32. data/gemfiles/rails42.gemfile +3 -0
  33. data/gemfiles/rails6.gemfile +8 -0
  34. data/gemfiles/railsmaster.gemfile +1 -1
  35. data/lib/action_policy.rb +3 -3
  36. data/lib/action_policy/authorizer.rb +12 -4
  37. data/lib/action_policy/base.rb +2 -0
  38. data/lib/action_policy/behaviour.rb +14 -3
  39. data/lib/action_policy/behaviours/memoized.rb +1 -1
  40. data/lib/action_policy/behaviours/policy_for.rb +12 -3
  41. data/lib/action_policy/behaviours/scoping.rb +32 -0
  42. data/lib/action_policy/behaviours/thread_memoized.rb +1 -1
  43. data/lib/action_policy/ext/hash_transform_keys.rb +19 -0
  44. data/lib/action_policy/ext/module_namespace.rb +1 -1
  45. data/lib/action_policy/ext/policy_cache_key.rb +2 -1
  46. data/lib/action_policy/ext/proc_case_eq.rb +14 -0
  47. data/lib/action_policy/ext/string_constantize.rb +1 -0
  48. data/lib/action_policy/ext/symbol_classify.rb +22 -0
  49. data/lib/action_policy/i18n.rb +56 -0
  50. data/lib/action_policy/lookup_chain.rb +21 -3
  51. data/lib/action_policy/policy/cache.rb +10 -6
  52. data/lib/action_policy/policy/core.rb +31 -19
  53. data/lib/action_policy/policy/execution_result.rb +12 -0
  54. data/lib/action_policy/policy/pre_check.rb +2 -6
  55. data/lib/action_policy/policy/reasons.rb +99 -12
  56. data/lib/action_policy/policy/scoping.rb +165 -0
  57. data/lib/action_policy/rails/authorizer.rb +20 -0
  58. data/lib/action_policy/rails/controller.rb +4 -14
  59. data/lib/action_policy/rails/ext/active_record.rb +10 -0
  60. data/lib/action_policy/rails/policy/instrumentation.rb +24 -0
  61. data/lib/action_policy/rails/scope_matchers/action_controller_params.rb +19 -0
  62. data/lib/action_policy/rails/scope_matchers/active_record.rb +29 -0
  63. data/lib/action_policy/railtie.rb +29 -7
  64. data/lib/action_policy/rspec.rb +1 -0
  65. data/lib/action_policy/rspec/be_authorized_to.rb +1 -1
  66. data/lib/action_policy/rspec/dsl.rb +103 -0
  67. data/lib/action_policy/rspec/have_authorized_scope.rb +126 -0
  68. data/lib/action_policy/rspec/pundit_syntax.rb +1 -1
  69. data/lib/action_policy/test_helper.rb +69 -4
  70. data/lib/action_policy/testing.rb +54 -0
  71. data/lib/action_policy/utils/pretty_print.rb +137 -0
  72. data/lib/action_policy/utils/suggest_message.rb +21 -0
  73. data/lib/action_policy/version.rb +1 -1
  74. metadata +58 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01a2dfdc255ba25c36b8054db9d56372ffb2a47137dd412568a6d3c9f2f2c81a
4
- data.tar.gz: 27f0e25159c6a5d5bca89a238e8342dcdc852d24a2f9129365de455ccb859690
3
+ metadata.gz: 3f655148e9920ff5afe7b4fdcd52fb15475dc72e84e46545820769b2d68b9f48
4
+ data.tar.gz: a4fd3da807acc43638357557f8df80745b14033d7f7183a5f7e5468f4df7fc51
5
5
  SHA512:
6
- metadata.gz: 682229b71f8de1c7828028d7731cc7fead59c86ad82285ae6989d1df476a402bc8f5f6984799e7b9dacb83e867bb5ad0688bc91d943045b116c005b35ccf0b47
7
- data.tar.gz: 2fe558adf815be0c32a9b683470ff95f75b3f3fe431aa959c3c60420f8faa2e28de3d390b20b19eb007cc86c999540d86b3491fdf94861a2a41cb98dc251bca5
6
+ metadata.gz: eadd511dc2a0d912ded1b35af655896210fbade0e18923d0e42261e7ee3db4bc68773b3c9acc90c9cb0a3e54e4dcec601800aedf5c52d2d7a3615edc18b26c44
7
+ data.tar.gz: c9e1ef737e1f3b764ec5d0a94585a5f80ed7c5f180c42e3ff7053ada2c1578d9b2bf6d8572199dca57dac330918b98e7aea4be032a9b2d6febf0ff96441c2eda
@@ -1,32 +1,44 @@
1
1
  require:
2
+ - standard/cop/semantic_blocks
2
3
  - rubocop-md
3
4
 
5
+ inherit_gem:
6
+ standard: config/base.yml
7
+
4
8
  AllCops:
5
- Include:
6
- - 'lib/**/*.rb'
7
- - 'lib/**/*.rake'
8
- - 'test/**/*.rb'
9
9
  Exclude:
10
- - 'bin/**/*'
11
- - 'gemfiles/**/*'
12
- - 'vendor/**/*'
10
+ - 'bin/*'
13
11
  - 'tmp/**/*'
12
+ - 'Gemfile'
13
+ - 'vendor/**/*'
14
+ - 'gemfiles/**/*'
14
15
  DisplayCopNames: true
15
- StyleGuideCopsOnly: false
16
- TargetRubyVersion: 2.3
16
+ TargetRubyVersion: 2.4s
17
17
 
18
- Rails:
18
+ Standard/SemanticBlocks:
19
19
  Enabled: false
20
20
 
21
- Bundler/OrderedGems:
22
- Enabled: false
21
+ Style/FrozenStringLiteralComment:
22
+ Enabled: true
23
+
24
+ Style/TrailingCommaInArrayLiteral:
25
+ EnforcedStyleForMultiline: no_comma
26
+
27
+ Style/TrailingCommaInHashLiteral:
28
+ EnforcedStyleForMultiline: no_comma
29
+
30
+ Layout/AlignParameters:
31
+ EnforcedStyle: with_first_parameter
23
32
 
24
33
  Lint/Void:
25
34
  Exclude:
26
35
  - '**/*.md'
27
36
 
28
- Lint/SplatKeywordArguments:
29
- Enabled: false
37
+ # See https://github.com/rubocop-hq/rubocop/issues/4222
38
+ Lint/AmbiguousBlockAssociation:
39
+ Exclude:
40
+ - 'spec/**/*'
41
+ - '**/*.md'
30
42
 
31
43
  Lint/DuplicateMethods:
32
44
  Exclude:
@@ -34,58 +46,8 @@ Lint/DuplicateMethods:
34
46
 
35
47
  Naming/FileName:
36
48
  Exclude:
37
- - 'Rakefile'
38
- - 'Gemfile'
39
49
  - '**/*.md'
40
50
 
41
51
  Layout/InitialIndentation:
42
52
  Exclude:
43
53
  - 'CHANGELOG.md'
44
-
45
- Naming/UncommunicativeMethodParamName:
46
- Enabled: false
47
-
48
- Naming/VariableNumber:
49
- Exclude:
50
- - 'test/**/*.rb'
51
-
52
- Style/SymbolArray:
53
- Enabled: false
54
-
55
- Style/Documentation:
56
- Exclude:
57
- - 'test/**/*.rb'
58
- - '**/*.md'
59
-
60
- Style/StringLiterals:
61
- EnforcedStyle: double_quotes
62
-
63
- Style/RegexpLiteral:
64
- Enabled: false
65
-
66
- Style/NumericPredicate:
67
- Enabled: false
68
-
69
- Style/Lambda:
70
- Enabled: false
71
-
72
- Layout/SpaceInsideStringInterpolation:
73
- EnforcedStyle: no_space
74
-
75
- Lint/AmbiguousRegexpLiteral:
76
- Enabled: false
77
-
78
- Metrics/LineLength:
79
- Max: 100
80
-
81
- Metrics/AbcSize:
82
- Exclude:
83
- - 'test/**/*.rb'
84
-
85
- Metrics/BlockLength:
86
- Exclude:
87
- - 'spec/**/*.rb'
88
-
89
- Metrics/MethodLength:
90
- Exclude:
91
- - 'test/**/*.rb'
@@ -1,28 +1,31 @@
1
1
  sudo: false
2
2
  language: ruby
3
- rvm:
4
- - 2.5.0
5
-
3
+ cache: bundler
6
4
  notifications:
7
5
  email: false
8
6
 
7
+ before_install:
8
+ - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
9
+ - gem install bundler -v '< 2'
10
+
11
+ script:
12
+ - bundle exec rake test:ci
13
+
9
14
  matrix:
10
15
  fast_finish: true
11
16
  include:
12
17
  - rvm: ruby-head
13
18
  gemfile: gemfiles/railsmaster.gemfile
14
- - rvm: jruby-9.2.0.0
19
+ - rvm: jruby-9.2.5.0
15
20
  gemfile: gemfiles/jruby.gemfile
16
- - rvm: 2.5.1
21
+ - rvm: 2.6.0
22
+ gemfile: gemfiles/rails6.gemfile
23
+ - rvm: 2.5.3
17
24
  gemfile: Gemfile
18
- - rvm: 2.5.1
19
- gemfile: gemfiles/rails42.gemfile
20
25
  - rvm: 2.4.3
21
- gemfile: Gemfile
22
- - rvm: 2.3.1
23
26
  gemfile: gemfiles/rails42.gemfile
24
27
  allow_failures:
25
28
  - rvm: ruby-head
26
29
  gemfile: gemfiles/railsmaster.gemfile
27
- - rvm: jruby-9.2.0.0
30
+ - rvm: jruby-9.2.5.0
28
31
  gemfile: gemfiles/jruby.gemfile
@@ -1,5 +1,218 @@
1
1
  ## master
2
2
 
3
+ ## 0.3.0.beta1 (2019-03-30)
4
+
5
+ - Added ActiveSupport-based instrumentation. ([@palkan][])
6
+
7
+ See [PR#4](https://github.com/palkan/action_policy/pull/4)
8
+
9
+ - Allow passing authorization context explicitly. ([@palkan][])
10
+
11
+ Closes [#3](https://github.com/palkan/action_policy/issues/3).
12
+
13
+ Now it's possible to override implicit authorization context
14
+ via `context` option:
15
+
16
+ ```ruby
17
+ authorize! target, to: :show?, context: {user: another_user}
18
+ authorized_scope User.all, context: {user: another_user}
19
+ ```
20
+
21
+ - Renamed `#authorized` to `#authorized_scope`. ([@palkan][])
22
+
23
+ **NOTE:** `#authorized` alias is also available.
24
+
25
+ - Added `Policy#pp(rule)` method to print annotated rule source code. ([@palkan][])
26
+
27
+ Example (debugging):
28
+
29
+ ```ruby
30
+ def edit?
31
+ binding.pry # rubocop:disable Lint/Debugger
32
+ (user.name == "John") && (admin? || access_feed?)
33
+ end
34
+ ```
35
+
36
+ ```sh
37
+ pry> pp :edit?
38
+ MyPolicy#edit?
39
+ ↳ (
40
+ user.name == "John" #=> false
41
+ )
42
+ AND
43
+ (
44
+ admin? #=> false
45
+ OR
46
+ access_feed? #=> true
47
+ )
48
+ )
49
+ ```
50
+
51
+ See [PR#63](https://github.com/palkan/action_policy/pull/63)
52
+
53
+ - Added ability to provide additional failure reasons details. ([@palkan][])
54
+
55
+ Example:
56
+
57
+ ```ruby
58
+ class ApplicantPolicy < ApplicationPolicy
59
+ def show?
60
+ allowed_to?(:show?, object.stage)
61
+ end
62
+ end
63
+
64
+ class StagePolicy < ApplicationPolicy
65
+ def show?
66
+ # Add stage title to the failure reason (if any)
67
+ # (could be used by client to show more descriptive message)
68
+ details[:title] = record.title
69
+ # then perform the checks
70
+ user.stages.where(id: record.id).exists?
71
+ end
72
+ end
73
+
74
+ # when accessing the reasons
75
+ p ex.result.reasons.details #=> { stage: [{show?: {title: "Onboarding"}] }
76
+ ```
77
+
78
+ See https://github.com/palkan/action_policy/pull/58
79
+
80
+ - Ruby 2.4+ is required. ([@palkan][])
81
+
82
+ - Added RSpec DSL for writing policy specs. ([@palkan])
83
+
84
+ The goal of this DSL is to reduce the boilerplate when writing
85
+ policies specs.
86
+
87
+ Example:
88
+
89
+ ```ruby
90
+ describe PostPolicy do
91
+ let(:user) { build_stubbed :user }
92
+ let(:record) { build_stubbed :post, draft: false }
93
+
94
+ let(:context) { {user: user} }
95
+
96
+ describe_rule :show? do
97
+ succeed "when post is published"
98
+
99
+ failed "when post is draft" do
100
+ before { post.draft = false }
101
+
102
+ succeed "when user is a manager" do
103
+ before { user.role = "manager" }
104
+ end
105
+ end
106
+ end
107
+ end
108
+ ```
109
+
110
+ - Added I18n support ([@DmitryTsepelev][])
111
+
112
+ Example:
113
+
114
+ ```ruby
115
+ class ApplicationController < ActionController::Base
116
+ rescue_from ActionPolicy::Unauthorized do |ex|
117
+ p ex.result.message #=> "You do not have access to the stage"
118
+ p ex.result.reasons.full_messages #=> ["You do not have access to the stage"]
119
+ end
120
+ end
121
+ ```
122
+
123
+ - Added scope options to scopes. ([@korolvs][])
124
+
125
+ See [#47](https://github.com/palkan/action_policy/pull/47).
126
+
127
+ Example:
128
+ ```ruby
129
+ # users_controller.rb
130
+ class UsersController < ApplicationController
131
+ def index
132
+ @user = authorized(User.all, scope_options: {with_deleted: true})
133
+ end
134
+ end
135
+
136
+ # user_policy.rb
137
+ describe UserPolicy < Application do
138
+ relation_scope do |relation, with_deleted: false|
139
+ rel = some_logic(relation)
140
+ with_deleted ? rel.with_deleted : rel
141
+ end
142
+ end
143
+ ```
144
+
145
+ - Added Symbol lookup to the lookup chain ([@DmitryTsepelev][])
146
+
147
+ For instance, lookup will implicitly use `AdminPolicy` in a following case:
148
+
149
+ ```ruby
150
+ # admin_controller.rb
151
+ class AdminController < ApplicationController
152
+ authorize! :admin, to: :update_settings
153
+ end
154
+ ```
155
+
156
+ - Added testing for scopes. ([@palkan][])
157
+
158
+ Example:
159
+
160
+ ```ruby
161
+ # users_controller.rb
162
+ class UsersController < ApplicationController
163
+ def index
164
+ @user = authorized(User.all)
165
+ end
166
+ end
167
+
168
+ # users_controller_spec.rb
169
+ describe UsersController do
170
+ subject { get :index }
171
+ it "has authorized scope" do
172
+ expect { subject }.to have_authorized_scope(:active_record_relation)
173
+ .with(PostPolicy)
174
+ end
175
+ end
176
+ ```
177
+
178
+ - Added scoping support. ([@palkan][])
179
+
180
+ See [#5](https://github.com/palkan/action_policy/issues/5).
181
+
182
+ By "scoping" we mean an ability to use policies to _scope data_.
183
+
184
+ For example, when you want to _scope_ Active Record collections depending
185
+ on the current user permissions:
186
+
187
+ ```ruby
188
+ class PostsController < ApplicationController
189
+ def index
190
+ @posts = authorized(Post.all)
191
+ end
192
+ end
193
+
194
+ class PostPolicy < ApplicationPolicy
195
+ relation_scope do |relation|
196
+ next relation if user.admin?
197
+ relation.where(user: user)
198
+ end
199
+ end
200
+ ```
201
+
202
+ Action Policy provides a flexible mechanism to apply scopes to anything you want.
203
+
204
+ Read more in [docs](https://actionpolicy.evilmartians.io/).
205
+
206
+ - Added `#implicit_authorization_target`. ([@palkan][]).
207
+
208
+ See [#35](https://github.com/palkan/action_policy/issues/35).
209
+
210
+ Implicit authorization target (defined by `implicit_authorization_target`) is used when no target specified for `authorize!` call.
211
+
212
+ For example, for Rails controllers integration it's just `controller_name.classify.safe_constantize`.
213
+
214
+ - Consider `record#policy_name` when looking up for a policy class. ([@palkan][])
215
+
3
216
  ## 0.2.4 (2018-09-06)
4
217
 
5
218
  - [Fix [#39](https://github.com/palkan/action_policy/issues/39)] Fix configuring cache store in Rails. ([@palkan][])
@@ -24,7 +237,7 @@
24
237
 
25
238
  It could be disabled by setting `ActionPolicy::LookupChain.namespace_cache_enabled = false`. It's enabled by default unless `RACK_ENV` env var is specified and is not equal to `"production"` (e.g. when `RACK_ENV=test` the cache is disabled).
26
239
 
27
- When using Rails it's enabled only in production mode but could be configured through setting the `config.config.action_policy.namespace_cache_enabled` parameter.
240
+ When using Rails it's enabled only in production mode but could be configured through setting the `config.action_policy.namespace_cache_enabled` parameter.
28
241
 
29
242
  - [Fix [#18](https://github.com/palkan/action_policy/issues/18)] Clarify documentation around, and fix the way `resolve_rule` resolves rules and rule aliases when subclasses are involved. ([@brendon][])
30
243
 
@@ -86,3 +299,5 @@
86
299
  [@palkan]: https://github.com/palkan
87
300
  [@ilyasgaraev]: https://github.com/ilyasgaraev
88
301
  [@brendon]: https://github.com/brendon
302
+ [@DmitryTsepelev]: https://github.com/DmitryTsepelev
303
+ [@korolvs]: https://github.com/korolvs
data/Gemfile CHANGED
@@ -6,6 +6,13 @@ gemspec
6
6
 
7
7
  gem "pry-byebug", platform: :mri
8
8
 
9
+ gem "method_source"
10
+ gem "unparser"
11
+
12
+ gem 'sqlite3', "~> 1.3.0", platform: :mri
13
+ gem 'activerecord-jdbcsqlite3-adapter', '~> 50.0', platform: :jruby
14
+ gem 'jdbc-sqlite3', platform: :jruby
15
+
9
16
  local_gemfile = File.join(__dir__, "Gemfile.local")
10
17
 
11
18
  if File.exist?(local_gemfile)
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 Vladimir Dementyev
3
+ Copyright (c) 2018-2019 Vladimir Dementyev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/Rakefile CHANGED
@@ -15,4 +15,14 @@ Rake::TestTask.new(:test) do |t|
15
15
  t.test_files = FileList["test/**/*_test.rb"]
16
16
  end
17
17
 
18
+ namespace :test do
19
+ task :isolated do
20
+ Dir.glob("test/**/*_test.rb").all? do |file|
21
+ sh(Gem.ruby, "-w", "-Ilib:test", file)
22
+ end || raise("Failures")
23
+ end
24
+
25
+ task ci: %w[rubocop test:isolated spec]
26
+ end
27
+
18
28
  task default: [:rubocop, :test, :spec]
@@ -21,13 +21,15 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.required_ruby_version = ">= 2.3.0"
24
+ spec.required_ruby_version = ">= 2.4.0"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.15"
26
+ spec.add_development_dependency "bundler", ">= 1.15"
27
27
  spec.add_development_dependency "minitest", "~> 5.0"
28
28
  spec.add_development_dependency "rake", "~> 10.0"
29
29
  spec.add_development_dependency "rspec", "~> 3.3"
30
- spec.add_development_dependency "rubocop", "~> 0.56.0"
30
+ spec.add_development_dependency "rubocop", "~> 0.65.0"
31
31
  spec.add_development_dependency "rubocop-md", "~> 0.2"
32
+ spec.add_development_dependency "standard", "~> 0.0.36"
32
33
  spec.add_development_dependency "benchmark-ips", "~> 2.7.0"
34
+ spec.add_development_dependency "i18n"
33
35
  end