betterlint 1.0.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 +7 -0
- data/README.md +158 -0
- data/STYLEGUIDE.md +111 -0
- data/config/default.yml +290 -0
- data/lib/rubocop/cop/betterment.rb +15 -0
- data/lib/rubocop/cop/betterment/active_job_performable.rb +40 -0
- data/lib/rubocop/cop/betterment/allowlist_blocklist.rb +35 -0
- data/lib/rubocop/cop/betterment/authorization_in_controller.rb +148 -0
- data/lib/rubocop/cop/betterment/dynamic_params.rb +36 -0
- data/lib/rubocop/cop/betterment/implicit_redirect_type.rb +70 -0
- data/lib/rubocop/cop/betterment/memoization_with_arguments.rb +33 -0
- data/lib/rubocop/cop/betterment/server_error_assertion.rb +63 -0
- data/lib/rubocop/cop/betterment/site_prism_loaded.rb +25 -0
- data/lib/rubocop/cop/betterment/spec_helper_required_outside_spec_dir.rb +38 -0
- data/lib/rubocop/cop/betterment/timeout.rb +19 -0
- data/lib/rubocop/cop/betterment/unsafe_job.rb +33 -0
- data/lib/rubocop/cop/betterment/unscoped_find.rb +87 -0
- data/lib/rubocop/cop/betterment/utils/method_return_table.rb +48 -0
- data/lib/rubocop/cop/betterment/utils/parser.rb +115 -0
- metadata +173 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Betterment
|
4
|
+
class SitePrismLoaded < Cop
|
5
|
+
MSG = 'Use `be_loaded` instead of `be_displayed`'.freeze
|
6
|
+
|
7
|
+
def_node_matcher :be_displayed_call?, <<-PATTERN
|
8
|
+
(send (send nil? :expect _) _ (send nil? :be_displayed))
|
9
|
+
PATTERN
|
10
|
+
|
11
|
+
def on_send(node)
|
12
|
+
return unless be_displayed_call?(node)
|
13
|
+
|
14
|
+
add_offense(node, location: node.children[2].loc.expression)
|
15
|
+
end
|
16
|
+
|
17
|
+
def autocorrect(node)
|
18
|
+
lambda do |corrector|
|
19
|
+
corrector.replace(node.children[2].loc.expression, 'be_loaded')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Betterment
|
4
|
+
# If a file requires spec_helper or rails_helper, make sure
|
5
|
+
# it is located in a spec/ directory.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# # bad
|
9
|
+
# app/models/whatever_spec.rb
|
10
|
+
# require 'rails_helper'
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# spec/models/my_class_spec.rb
|
14
|
+
# require 'rails_helper'
|
15
|
+
class SpecHelperRequiredOutsideSpecDir < Cop
|
16
|
+
MSG = 'Spec helper required outside of a spec/ directory.'.freeze
|
17
|
+
|
18
|
+
def_node_matcher :requires_spec_helper?, <<-PATTERN
|
19
|
+
(send nil? :require
|
20
|
+
(str {"rails_helper" "spec_helper"}))
|
21
|
+
PATTERN
|
22
|
+
|
23
|
+
def on_send(node)
|
24
|
+
add_offense(node) if requires_spec_helper?(node) && !spec_directory?
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def spec_directory?
|
30
|
+
Pathname.new(processed_source.buffer.name)
|
31
|
+
.relative_path_from(Pathname.pwd)
|
32
|
+
.to_s
|
33
|
+
.start_with?("spec#{File::SEPARATOR}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Betterment
|
4
|
+
class Timeout < Cop
|
5
|
+
MSG = 'Using Timeout.timeout without a custom exception can prevent rescue blocks from executing'.freeze
|
6
|
+
|
7
|
+
def_node_matcher :timeout_call?, <<-PATTERN
|
8
|
+
(send (const nil? :Timeout) :timeout _)
|
9
|
+
PATTERN
|
10
|
+
|
11
|
+
def on_send(node)
|
12
|
+
return unless timeout_call?(node)
|
13
|
+
|
14
|
+
add_offense(node)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Betterment
|
4
|
+
class UnsafeJob < Cop
|
5
|
+
attr_accessor :sensitive_params, :class_regex
|
6
|
+
|
7
|
+
MSG = <<~MSG.freeze
|
8
|
+
This job takes a parameter that will end up serialized in plaintext. Do not pass sensitive data as bare arguments into jobs.
|
9
|
+
|
10
|
+
See here for more information on this error:
|
11
|
+
https://github.com/Betterment/betterlint#bettermentunsafejob
|
12
|
+
MSG
|
13
|
+
|
14
|
+
def initialize(config = nil, options = nil)
|
15
|
+
super(config, options)
|
16
|
+
config = @config.for_cop(self)
|
17
|
+
@sensitive_params = config.fetch("sensitive_params", []).map(&:to_sym)
|
18
|
+
@class_regex = Regexp.new config.fetch("class_regex", ".*Job$")
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_def(node)
|
22
|
+
return unless %i(perform initialize).include?(node.method_name)
|
23
|
+
return unless @class_regex.match(node.parent_module_name)
|
24
|
+
|
25
|
+
node.arguments.any? do |argument|
|
26
|
+
name, = *argument
|
27
|
+
add_offense(argument) if @sensitive_params.include?(name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Betterment
|
4
|
+
class UnscopedFind < Cop
|
5
|
+
attr_accessor :unauthenticated_models
|
6
|
+
|
7
|
+
MSG = <<~MSG.freeze
|
8
|
+
Records are being retrieved directly using user input.
|
9
|
+
Please query for the associated record in a way that enforces authorization (e.g. "trust-root chaining").
|
10
|
+
|
11
|
+
INSTEAD OF THIS:
|
12
|
+
Post.find(params[:post_id])
|
13
|
+
|
14
|
+
DO THIS:
|
15
|
+
current_user.posts.find(params[:post_id])
|
16
|
+
|
17
|
+
See here for more information on this error:
|
18
|
+
https://github.com/Betterment/betterlint/blob/main/README.md#bettermentunscopedfind
|
19
|
+
MSG
|
20
|
+
METHOD_PATTERN = /^find_by_(.+?)(!)?$/.freeze
|
21
|
+
FINDS = %i(find find_by find_by! where).freeze
|
22
|
+
|
23
|
+
def_node_matcher :custom_scope_find?, <<-PATTERN
|
24
|
+
(send (send (const ... _) ...) {#{FINDS.map(&:inspect).join(' ')}} ...)
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def_node_matcher :find?, <<-PATTERN
|
28
|
+
(send (const ... _) {#{FINDS.map(&:inspect).join(' ')}} ...)
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
def initialize(config = nil, options = nil)
|
32
|
+
super(config, options)
|
33
|
+
config = @config.for_cop(self)
|
34
|
+
@unauthenticated_models = config.fetch("unauthenticated_models", []).map(&:to_sym)
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_class(node)
|
38
|
+
Utils::MethodReturnTable.populate_index(node)
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_send(node)
|
42
|
+
_, _, *arg_nodes = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
43
|
+
return unless
|
44
|
+
(
|
45
|
+
find?(node) ||
|
46
|
+
custom_scope_find?(node) ||
|
47
|
+
static_method_name(node.method_name)
|
48
|
+
) && !@unauthenticated_models.include?(Utils::Parser.get_root_token(node))
|
49
|
+
|
50
|
+
add_offense(node) if find_param_arg(arg_nodes)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def find_param_arg(arg_nodes)
|
56
|
+
return unless arg_nodes
|
57
|
+
|
58
|
+
arg_nodes.find do |arg|
|
59
|
+
if arg.hash_type?
|
60
|
+
arg.children.each do |pair|
|
61
|
+
_key, value = *pair.children
|
62
|
+
return arg if uses_params?(value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
uses_params?(arg)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def uses_params?(node)
|
71
|
+
root = Utils::Parser.get_root_token(node)
|
72
|
+
root == :params || Array(Utils::MethodReturnTable.get_method(root)).find do |x|
|
73
|
+
Utils::Parser.get_root_token(x) == :params
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# yoinked from Rails/DynamicFindBy
|
78
|
+
def static_method_name(method_name)
|
79
|
+
match = METHOD_PATTERN.match(method_name)
|
80
|
+
return nil unless match
|
81
|
+
|
82
|
+
match[2] ? 'find_by!' : 'find_by'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Utils
|
4
|
+
module MethodReturnTable
|
5
|
+
class << self
|
6
|
+
def populate_index(node)
|
7
|
+
raise "not a class" unless node.class_type?
|
8
|
+
|
9
|
+
get_methods_for_class(node).each do |method|
|
10
|
+
track_method(method.method_name, Utils::Parser.get_return_values(method))
|
11
|
+
end
|
12
|
+
|
13
|
+
node.descendants.each do |descendant|
|
14
|
+
lhs, rhs = *descendant
|
15
|
+
next unless descendant.equals_asgn? && (descendant.type != :casgn) && rhs&.send_type?
|
16
|
+
|
17
|
+
track_method(lhs, [rhs])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def indexed_methods
|
22
|
+
@indexed_methods ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_method(method_name)
|
26
|
+
indexed_methods[method_name]
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_method?(method_name)
|
30
|
+
indexed_methods.include?(method_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def track_method(method_name, returns)
|
36
|
+
indexed_methods[method_name] = returns
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_methods_for_class(node)
|
40
|
+
return [] unless node.children && node.class_type?
|
41
|
+
|
42
|
+
node.descendants.select(&:def_type?)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module Utils
|
4
|
+
module Parser
|
5
|
+
def self.get_root_token(node) # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
|
6
|
+
return nil unless node
|
7
|
+
|
8
|
+
return get_root_token(node.receiver) if node.receiver
|
9
|
+
|
10
|
+
# rubocop:disable InternalAffairs/NodeDestructuring
|
11
|
+
if node.send_type?
|
12
|
+
name = node.method_name
|
13
|
+
elsif node.variable?
|
14
|
+
name, = *node
|
15
|
+
elsif node.literal?
|
16
|
+
_, name = *node
|
17
|
+
elsif node.const_type?
|
18
|
+
name = node.const_name.to_sym
|
19
|
+
elsif node.sym_type?
|
20
|
+
name = node.value
|
21
|
+
elsif node.self_type?
|
22
|
+
name = :self
|
23
|
+
elsif node.block_pass_type?
|
24
|
+
name, = *node.children
|
25
|
+
else
|
26
|
+
name = nil
|
27
|
+
end
|
28
|
+
# rubocop:enable InternalAffairs/NodeDestructuring
|
29
|
+
|
30
|
+
name
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.get_return_values(node) # rubocop:disable Metrics/AbcSize
|
34
|
+
return [] unless node
|
35
|
+
return explicit_returns(node) + get_return_values(node.body) if node.def_type?
|
36
|
+
return [node] if node.literal? || node.variable?
|
37
|
+
|
38
|
+
case node.type
|
39
|
+
when :begin
|
40
|
+
get_return_values(node.children.last)
|
41
|
+
when :block
|
42
|
+
get_return_values(node.body)
|
43
|
+
when :if
|
44
|
+
if_rets = get_return_values(node.if_branch)
|
45
|
+
else_rets = get_return_values(node.else_branch)
|
46
|
+
if_rets + else_rets
|
47
|
+
when :case
|
48
|
+
cases = []
|
49
|
+
node.each_when do |block|
|
50
|
+
cases += get_return_values(block.body)
|
51
|
+
end
|
52
|
+
|
53
|
+
cases + get_return_values(node.else_branch)
|
54
|
+
when :send
|
55
|
+
[node]
|
56
|
+
else
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.explicit_returns(node)
|
62
|
+
node.descendants.select(&:return_type?).map { |x|
|
63
|
+
x&.children&.first
|
64
|
+
}.compact
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.params_from_arguments(arguments) # rubocop:disable Metrics/PerceivedComplexity
|
68
|
+
parameter_names = []
|
69
|
+
|
70
|
+
arguments.each do |arg|
|
71
|
+
if arg.hash_type?
|
72
|
+
arg.children.each do |pair|
|
73
|
+
value = pair.value
|
74
|
+
parameter_names << value.value if value.sym_type? || value.str_type?
|
75
|
+
end
|
76
|
+
elsif arg.sym_type? || arg.str_type?
|
77
|
+
parameter_names << arg.value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
parameter_names
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.get_extracted_parameters(node, param_aliases: []) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
85
|
+
return [] unless node.send_type?
|
86
|
+
|
87
|
+
parameter_names = []
|
88
|
+
param_aliases << :params
|
89
|
+
|
90
|
+
if node.method?(:[]) && param_aliases.include?(get_root_token(node))
|
91
|
+
return node.arguments.select { |x|
|
92
|
+
x.sym_type? || x.str_type?
|
93
|
+
}.map(&:value)
|
94
|
+
end
|
95
|
+
|
96
|
+
children = node.descendants.select do |child|
|
97
|
+
child.send_type? && param_aliases.include?(child.method_name)
|
98
|
+
end
|
99
|
+
|
100
|
+
children.each do |child|
|
101
|
+
ancestors = child.ancestors.select do |ancestor|
|
102
|
+
ancestor.send_type? && ancestor.method?(:permit)
|
103
|
+
end
|
104
|
+
|
105
|
+
ancestors.each do |ancestor|
|
106
|
+
parameter_names += params_from_arguments(ancestor.arguments)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
parameter_names.map(&:to_sym)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: betterlint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Development
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubocop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop-performance
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '10.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '10.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec-rails
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Betterment rubocop configuration
|
126
|
+
email:
|
127
|
+
- development@betterment.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- README.md
|
133
|
+
- STYLEGUIDE.md
|
134
|
+
- config/default.yml
|
135
|
+
- lib/rubocop/cop/betterment.rb
|
136
|
+
- lib/rubocop/cop/betterment/active_job_performable.rb
|
137
|
+
- lib/rubocop/cop/betterment/allowlist_blocklist.rb
|
138
|
+
- lib/rubocop/cop/betterment/authorization_in_controller.rb
|
139
|
+
- lib/rubocop/cop/betterment/dynamic_params.rb
|
140
|
+
- lib/rubocop/cop/betterment/implicit_redirect_type.rb
|
141
|
+
- lib/rubocop/cop/betterment/memoization_with_arguments.rb
|
142
|
+
- lib/rubocop/cop/betterment/server_error_assertion.rb
|
143
|
+
- lib/rubocop/cop/betterment/site_prism_loaded.rb
|
144
|
+
- lib/rubocop/cop/betterment/spec_helper_required_outside_spec_dir.rb
|
145
|
+
- lib/rubocop/cop/betterment/timeout.rb
|
146
|
+
- lib/rubocop/cop/betterment/unsafe_job.rb
|
147
|
+
- lib/rubocop/cop/betterment/unscoped_find.rb
|
148
|
+
- lib/rubocop/cop/betterment/utils/method_return_table.rb
|
149
|
+
- lib/rubocop/cop/betterment/utils/parser.rb
|
150
|
+
homepage:
|
151
|
+
licenses:
|
152
|
+
- MIT
|
153
|
+
metadata: {}
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options: []
|
156
|
+
require_paths:
|
157
|
+
- lib
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '2.4'
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
requirements: []
|
169
|
+
rubygems_version: 3.2.3
|
170
|
+
signing_key:
|
171
|
+
specification_version: 4
|
172
|
+
summary: Betterment rubocop configuration
|
173
|
+
test_files: []
|