betterlint 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +41 -0
- data/config/default.yml +26 -0
- data/lib/rubocop/cop/betterment/active_job_performable.rb +1 -1
- data/lib/rubocop/cop/betterment/dynamic_params.rb +1 -1
- data/lib/rubocop/cop/betterment/implicit_redirect_type.rb +2 -2
- data/lib/rubocop/cop/betterment/memoization_with_arguments.rb +3 -3
- data/lib/rubocop/cop/betterment/non_standard_actions.rb +74 -0
- data/lib/rubocop/cop/betterment.rb +1 -0
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 530a4f9e133d2b476275f42d7f58050eab86379908d1d7b1ebc0ac56c7c680f5
|
4
|
+
data.tar.gz: 497ef95c882dae58db33bf6b7d02c28a63909968f6a751a0ed9a29c97d12aa83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 150b06a5b965394c1c7f00b95c7f3d1bb78e58855d300fb3041f90ad828fc023ca6e0cca02faad01274d58b3d5263bbf05acf337691ce5b89e98482596f30241
|
7
|
+
data.tar.gz: 2524c76c7a7ea7101f3987f79e31270fe0e51091aabf1f8bc229b9854285757e01b4c335e09be348a5f850f7b2f5b1fe16f18d4ff0d72eda94496cc1a54a0b46
|
data/README.md
CHANGED
@@ -156,3 +156,44 @@ Betterment/UnsafeJob:
|
|
156
156
|
```
|
157
157
|
|
158
158
|
It may make sense to consult your application's values for `Rails.application.config.filter_parameters`; if the application is filtering specific parameters from being logged, it might be a good idea to prevent these values from being stored in plaintext in a database as well.
|
159
|
+
|
160
|
+
### Betterment/NonStandardActions
|
161
|
+
|
162
|
+
This cop looks at Rails route files and flags routes that go to non-standard controller actions.
|
163
|
+
The 7 standard controller actions (index, show, new, edit, create, update, destroy) are well defined,
|
164
|
+
which allow for policies and middleware that can be applied to any controller.
|
165
|
+
For example, if we want a user role to only be able to view but not modify,
|
166
|
+
we can blanket deny access to create, update, and destroy actions and have it work in most use cases.
|
167
|
+
|
168
|
+
Custom actions require explicit configuration to work with these sorts of middleware,
|
169
|
+
so we prefer to use new controllers instead. For example, a resourceful route with a custom action like this:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
Rails.application.routes.draw do
|
173
|
+
resources :alerts, only: [:index, :summary]
|
174
|
+
end
|
175
|
+
```
|
176
|
+
|
177
|
+
This can instead by written with an additional controller:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
Rails.application.routes.draw do
|
181
|
+
resources :alerts, only: :index # AlertsController#index
|
182
|
+
namespace :alerts do
|
183
|
+
resource :summary, only: :show #Alerts::SummariesController#show
|
184
|
+
end
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
By default this will look only in `config/routes.rb` and will use the standard 7 actions.
|
189
|
+
These values can be configured:
|
190
|
+
|
191
|
+
```yaml
|
192
|
+
Betterment/NonStandardActions:
|
193
|
+
AdditionalAllowedActions:
|
194
|
+
- update_all
|
195
|
+
- destroy_all
|
196
|
+
Include:
|
197
|
+
- 'config/routes.rb'
|
198
|
+
- 'config/other_routes.rb'
|
199
|
+
```
|
data/config/default.yml
CHANGED
@@ -20,6 +20,9 @@ AllCops:
|
|
20
20
|
DisplayStyleGuide: true
|
21
21
|
DisplayCopNames: true
|
22
22
|
|
23
|
+
Betterment:
|
24
|
+
StyleGuideBaseURL: https://github.com/Betterment/betterlint
|
25
|
+
|
23
26
|
Betterment/ServerErrorAssertion:
|
24
27
|
Description: 'Detects assertions on 5XX HTTP statuses.'
|
25
28
|
Include:
|
@@ -27,20 +30,43 @@ Betterment/ServerErrorAssertion:
|
|
27
30
|
|
28
31
|
Betterment/AuthorizationInController:
|
29
32
|
Description: 'Detects unsafe handling of id-like parameters in controllers.'
|
33
|
+
StyleGuide: '#bettermentauthorizationincontroller'
|
30
34
|
Enabled: false
|
31
35
|
|
32
36
|
Betterment/UnsafeJob:
|
33
37
|
Enabled: false
|
38
|
+
StyleGuide: '#bettermentunsafejob'
|
34
39
|
sensitive_params:
|
35
40
|
- password
|
36
41
|
- social_security_number
|
37
42
|
- ssn
|
38
43
|
|
44
|
+
Betterment/UnscopedFind:
|
45
|
+
StyleGuide: '#bettermentunscopedfind'
|
46
|
+
|
47
|
+
Betterment/DynamicParams:
|
48
|
+
StyleGuide: '#bettermentdynamicparams'
|
49
|
+
|
39
50
|
Betterment/SitePrismLoaded:
|
40
51
|
Include:
|
41
52
|
- 'spec/features/**/*_spec.rb'
|
42
53
|
- 'spec/system/**/*_spec.rb'
|
43
54
|
|
55
|
+
Betterment/NonStandardActions:
|
56
|
+
Description: 'Detects non-standard controller actions.'
|
57
|
+
StyleGuide: '#bettermentnonstandardactions'
|
58
|
+
AdditionalAllowedActions: []
|
59
|
+
StandardActions:
|
60
|
+
- index
|
61
|
+
- show
|
62
|
+
- new
|
63
|
+
- edit
|
64
|
+
- create
|
65
|
+
- update
|
66
|
+
- destroy
|
67
|
+
Include:
|
68
|
+
- 'config/routes.rb'
|
69
|
+
|
44
70
|
Layout/ParameterAlignment:
|
45
71
|
Enabled: false
|
46
72
|
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
return unless arg_nodes
|
28
28
|
|
29
29
|
arg_nodes.find do |arg|
|
30
|
-
arg.array_type? && find_dynamic_param(arg.values) || !arg.literal? && !arg.const_type?
|
30
|
+
(arg.array_type? && find_dynamic_param(arg.values)) || (!arg.literal? && !arg.const_type?)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
def on_block(node)
|
47
47
|
return unless routes_file?
|
48
48
|
|
49
|
-
if block_form_with_options(node) { |options| options.none?
|
49
|
+
if block_form_with_options(node) { |options| options.none? { |n| valid_status_option?(n) } } || block_form_without_options?(node)
|
50
50
|
add_offense(node)
|
51
51
|
end
|
52
52
|
end
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
def on_send(node)
|
55
55
|
return unless routes_file?
|
56
56
|
|
57
|
-
if arg_form_with_options(node) { |options| options.none?
|
57
|
+
if arg_form_with_options(node) { |options| options.none? { |n| valid_status_option?(n) } } || arg_form_without_options?(node)
|
58
58
|
add_offense(node)
|
59
59
|
end
|
60
60
|
end
|
@@ -3,8 +3,8 @@ module RuboCop
|
|
3
3
|
module Betterment
|
4
4
|
class MemoizationWithArguments < Cop
|
5
5
|
MSG = 'Memoized method `%<method>s` accepts arguments, ' \
|
6
|
-
|
7
|
-
|
6
|
+
'which may cause it to return a stale result. ' \
|
7
|
+
'Remove memoization or refactor to remove arguments.'.freeze
|
8
8
|
|
9
9
|
def self.node_pattern
|
10
10
|
memo_assign = '(or_asgn $(ivasgn _) _)'
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
21
21
|
|
22
22
|
def on_def(node)
|
23
23
|
(method_name, ivar_assign) = memoized?(node)
|
24
|
-
return if ivar_assign.nil? || node.arguments.length.zero?
|
24
|
+
return if ivar_assign.nil? || node.arguments.length.zero? || method_name == :initialize
|
25
25
|
|
26
26
|
msg = format(MSG, method: method_name)
|
27
27
|
add_offense(node, location: ivar_assign.source_range, message: msg)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Betterment
|
4
|
+
class NonStandardActions < Cop
|
5
|
+
MSG_GENERAL = 'Use a new controller instead of custom actions.'.freeze
|
6
|
+
MSG_RESOURCE_ONLY = "Resource route refers to a non-standard action in it's 'only:' param. #{MSG_GENERAL}".freeze
|
7
|
+
MSG_ROUTE_TO = "Route goes to a non-standard controller action. #{MSG_GENERAL}".freeze
|
8
|
+
|
9
|
+
# @!method routes?(node)
|
10
|
+
def_node_matcher :routes?, <<-PATTERN
|
11
|
+
(block (send (send (send (const nil? :Rails) :application) :routes) :draw) ...)
|
12
|
+
PATTERN
|
13
|
+
|
14
|
+
# @!method resource_with_only(node)
|
15
|
+
def_node_matcher :resource_with_only, <<-PATTERN
|
16
|
+
(send nil? {:resource :resources} _ (hash <(pair (sym :only) {(array (sym $_)*) (sym $_*)} ) ...> ))
|
17
|
+
PATTERN
|
18
|
+
|
19
|
+
def not_to_or_action?(sym)
|
20
|
+
!%i(to action).include?(sym)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @!method route_to(node)
|
24
|
+
def_node_matcher :route_to, <<~PATTERN
|
25
|
+
(send nil? {:match :get :post :put :patch :delete} ({str sym} $_) (hash {
|
26
|
+
<(pair (sym ${:to :action}) ({str sym} $_)) ...>
|
27
|
+
(pair (sym $#not_to_or_action?) $_)*
|
28
|
+
})?)
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
def on_block(node)
|
32
|
+
if routes?(node)
|
33
|
+
node.each_descendant(:send) do |descendant_node|
|
34
|
+
check_resource_with_only(descendant_node) || check_raw_route(descendant_node)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def check_resource_with_only(node)
|
42
|
+
resource_only = resource_with_only(node)
|
43
|
+
if resource_only && resource_only.any? { |action| !allowed_action?(action) }
|
44
|
+
add_offense(node, message: MSG_RESOURCE_ONLY)
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_raw_route(node)
|
50
|
+
route = route_to(node)
|
51
|
+
if route
|
52
|
+
(path, param, value) = route
|
53
|
+
action = case param
|
54
|
+
when :to then value.first.split('#').last
|
55
|
+
when :action then value.first
|
56
|
+
else path
|
57
|
+
end
|
58
|
+
add_offense(node, message: MSG_ROUTE_TO) unless allowed_action?(action)
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# NOTE: The InternalAffairs/UndefinedConfig rule seems to have a bug where it can't fine these configs in config/default.yml
|
64
|
+
def allowed_actions
|
65
|
+
@allowed_actions ||= cop_config['StandardActions'] + cop_config['AdditionalAllowedActions'] # rubocop:disable InternalAffairs/UndefinedConfig
|
66
|
+
end
|
67
|
+
|
68
|
+
def allowed_action?(action)
|
69
|
+
allowed_actions.include?(action.to_s)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -7,6 +7,7 @@ require 'rubocop/cop/betterment/unscoped_find'
|
|
7
7
|
require 'rubocop/cop/betterment/unsafe_job'
|
8
8
|
require 'rubocop/cop/betterment/timeout'
|
9
9
|
require 'rubocop/cop/betterment/memoization_with_arguments'
|
10
|
+
require 'rubocop/cop/betterment/non_standard_actions'
|
10
11
|
require 'rubocop/cop/betterment/site_prism_loaded'
|
11
12
|
require 'rubocop/cop/betterment/spec_helper_required_outside_spec_dir'
|
12
13
|
require 'rubocop/cop/betterment/implicit_redirect_type'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: betterlint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Development
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -98,16 +98,16 @@ dependencies:
|
|
98
98
|
name: rake
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 12.3.3
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 12.3.3
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rspec-rails
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +139,7 @@ files:
|
|
139
139
|
- lib/rubocop/cop/betterment/dynamic_params.rb
|
140
140
|
- lib/rubocop/cop/betterment/implicit_redirect_type.rb
|
141
141
|
- lib/rubocop/cop/betterment/memoization_with_arguments.rb
|
142
|
+
- lib/rubocop/cop/betterment/non_standard_actions.rb
|
142
143
|
- lib/rubocop/cop/betterment/server_error_assertion.rb
|
143
144
|
- lib/rubocop/cop/betterment/site_prism_loaded.rb
|
144
145
|
- lib/rubocop/cop/betterment/spec_helper_required_outside_spec_dir.rb
|
@@ -150,7 +151,8 @@ files:
|
|
150
151
|
homepage:
|
151
152
|
licenses:
|
152
153
|
- MIT
|
153
|
-
metadata:
|
154
|
+
metadata:
|
155
|
+
rubygems_mfa_required: 'true'
|
154
156
|
post_install_message:
|
155
157
|
rdoc_options: []
|
156
158
|
require_paths:
|
@@ -159,14 +161,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
161
|
requirements:
|
160
162
|
- - ">="
|
161
163
|
- !ruby/object:Gem::Version
|
162
|
-
version: '2.
|
164
|
+
version: '2.6'
|
163
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
166
|
requirements:
|
165
167
|
- - ">="
|
166
168
|
- !ruby/object:Gem::Version
|
167
169
|
version: '0'
|
168
170
|
requirements: []
|
169
|
-
rubygems_version: 3.
|
171
|
+
rubygems_version: 3.3.7
|
170
172
|
signing_key:
|
171
173
|
specification_version: 4
|
172
174
|
summary: Betterment rubocop configuration
|