rubocop-github 0.13.0 → 0.16.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -2
- data/STYLEGUIDE.md +27 -11
- data/config/_default_shared.yml +329 -0
- data/config/_rails_shared.yml +120 -0
- data/config/default.yml +2 -328
- data/config/default_deprecated.yml +4 -0
- data/config/default_edge.yml +4 -0
- data/config/rails.yml +2 -122
- data/config/rails_deprecated.yml +7 -0
- data/config/rails_edge.yml +4 -0
- data/lib/rubocop/cop/github.rb +1 -0
- data/lib/rubocop/cop/github/insecure_hash_algorithm.rb +139 -0
- data/lib/rubocop/cop/github/rails_controller_render_action_symbol.rb +2 -2
- data/lib/rubocop/cop/github/rails_controller_render_literal.rb +32 -21
- data/lib/rubocop/cop/github/rails_controller_render_paths_exist.rb +3 -3
- data/lib/rubocop/cop/github/rails_controller_render_shorthand.rb +1 -1
- data/lib/rubocop/cop/github/rails_render_inline.rb +1 -1
- data/lib/rubocop/cop/github/rails_render_object_collection.rb +1 -1
- data/lib/rubocop/cop/github/rails_view_render_literal.rb +26 -21
- data/lib/rubocop/cop/github/rails_view_render_paths_exist.rb +3 -3
- data/lib/rubocop/cop/github/rails_view_render_shorthand.rb +1 -1
- data/lib/rubocop/cop/github/render_literal_helpers.rb +55 -0
- metadata +36 -15
data/lib/rubocop/cop/github.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rubocop/cop/github/insecure_hash_algorithm"
|
3
4
|
require "rubocop/cop/github/rails_application_record"
|
4
5
|
require "rubocop/cop/github/rails_controller_render_action_symbol"
|
5
6
|
require "rubocop/cop/github/rails_controller_render_literal"
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module GitHub
|
8
|
+
class InsecureHashAlgorithm < Cop
|
9
|
+
MSG = "This hash function is not allowed"
|
10
|
+
UUID_V3_MSG = "uuid_v3 uses MD5, which is not allowed"
|
11
|
+
UUID_V5_MSG = "uuid_v5 uses SHA1, which is not allowed"
|
12
|
+
|
13
|
+
# Matches constants like these:
|
14
|
+
# Digest::MD5
|
15
|
+
# OpenSSL::Digest::MD5
|
16
|
+
def_node_matcher :insecure_const?, <<-PATTERN
|
17
|
+
(const (const _ :Digest) #insecure_algorithm?)
|
18
|
+
PATTERN
|
19
|
+
|
20
|
+
# Matches calls like these:
|
21
|
+
# Digest.new('md5')
|
22
|
+
# Digest.hexdigest('md5', 'str')
|
23
|
+
# OpenSSL::Digest.new('md5')
|
24
|
+
# OpenSSL::Digest.hexdigest('md5', 'str')
|
25
|
+
# OpenSSL::Digest::Digest.new('md5')
|
26
|
+
# OpenSSL::Digest::Digest.hexdigest('md5', 'str')
|
27
|
+
# OpenSSL::Digest::Digest.new(:MD5)
|
28
|
+
# OpenSSL::Digest::Digest.hexdigest(:MD5, 'str')
|
29
|
+
def_node_matcher :insecure_digest?, <<-PATTERN
|
30
|
+
(send
|
31
|
+
(const _ {:Digest :HMAC})
|
32
|
+
#not_just_encoding?
|
33
|
+
#insecure_algorithm?
|
34
|
+
...)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
# Matches calls like "Digest(:MD5)".
|
38
|
+
def_node_matcher :insecure_hash_lookup?, <<-PATTERN
|
39
|
+
(send _ :Digest #insecure_algorithm?)
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
# Matches calls like "OpenSSL::HMAC.new(secret, hash)"
|
43
|
+
def_node_matcher :openssl_hmac_new?, <<-PATTERN
|
44
|
+
(send (const (const _ :OpenSSL) :HMAC) :new ...)
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
# Matches calls like "OpenSSL::HMAC.new(secret, 'sha1')"
|
48
|
+
def_node_matcher :openssl_hmac_new_insecure?, <<-PATTERN
|
49
|
+
(send (const (const _ :OpenSSL) :HMAC) :new _ #insecure_algorithm?)
|
50
|
+
PATTERN
|
51
|
+
|
52
|
+
# Matches Rails's Digest::UUID.
|
53
|
+
def_node_matcher :digest_uuid?, <<-PATTERN
|
54
|
+
(const (const _ :Digest) :UUID)
|
55
|
+
PATTERN
|
56
|
+
|
57
|
+
def_node_matcher :uuid_v3?, <<-PATTERN
|
58
|
+
(send (const _ :UUID) :uuid_v3 ...)
|
59
|
+
PATTERN
|
60
|
+
|
61
|
+
def_node_matcher :uuid_v5?, <<-PATTERN
|
62
|
+
(send (const _ :UUID) :uuid_v5 ...)
|
63
|
+
PATTERN
|
64
|
+
|
65
|
+
def insecure_algorithm?(val)
|
66
|
+
return false if val == :Digest # Don't match "Digest::Digest".
|
67
|
+
case alg_name(val)
|
68
|
+
when *allowed_hash_functions
|
69
|
+
false
|
70
|
+
when Symbol
|
71
|
+
# can't figure this one out, it's nil or a var or const.
|
72
|
+
false
|
73
|
+
else
|
74
|
+
true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def not_just_encoding?(val)
|
79
|
+
!just_encoding?(val)
|
80
|
+
end
|
81
|
+
|
82
|
+
def just_encoding?(val)
|
83
|
+
val == :hexencode || val == :bubblebabble
|
84
|
+
end
|
85
|
+
|
86
|
+
# Built-in hash functions are listed in these docs:
|
87
|
+
# https://ruby-doc.org/stdlib-2.7.0/libdoc/digest/rdoc/Digest.html
|
88
|
+
# https://ruby-doc.org/stdlib-2.7.0/libdoc/openssl/rdoc/OpenSSL/Digest.html
|
89
|
+
DEFAULT_ALLOWED = %w[
|
90
|
+
SHA256
|
91
|
+
SHA384
|
92
|
+
SHA512
|
93
|
+
].freeze
|
94
|
+
|
95
|
+
def allowed_hash_functions
|
96
|
+
@allowed_algorithms ||= cop_config.fetch("Allowed", DEFAULT_ALLOWED).map(&:downcase)
|
97
|
+
end
|
98
|
+
|
99
|
+
def alg_name(val)
|
100
|
+
return :nil if val.nil?
|
101
|
+
return val.to_s.downcase unless val.is_a?(RuboCop::AST::Node)
|
102
|
+
case val.type
|
103
|
+
when :sym, :str
|
104
|
+
val.children.first.to_s.downcase
|
105
|
+
else
|
106
|
+
val.type
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def on_const(const_node)
|
111
|
+
if insecure_const?(const_node) && !digest_uuid?(const_node)
|
112
|
+
add_offense(const_node, message: MSG)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def on_send(send_node)
|
117
|
+
case
|
118
|
+
when uuid_v3?(send_node)
|
119
|
+
unless allowed_hash_functions.include?("md5")
|
120
|
+
add_offense(send_node, message: UUID_V3_MSG)
|
121
|
+
end
|
122
|
+
when uuid_v5?(send_node)
|
123
|
+
unless allowed_hash_functions.include?("sha1")
|
124
|
+
add_offense(send_node, message: UUID_V5_MSG)
|
125
|
+
end
|
126
|
+
when openssl_hmac_new?(send_node)
|
127
|
+
if openssl_hmac_new_insecure?(send_node)
|
128
|
+
add_offense(send_node, message: MSG)
|
129
|
+
end
|
130
|
+
when insecure_digest?(send_node)
|
131
|
+
add_offense(send_node, message: MSG)
|
132
|
+
when insecure_hash_lookup?(send_node)
|
133
|
+
add_offense(send_node, message: MSG)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -9,11 +9,11 @@ module RuboCop
|
|
9
9
|
MSG = "Prefer `render` with string instead of symbol"
|
10
10
|
|
11
11
|
def_node_matcher :render_sym?, <<-PATTERN
|
12
|
-
(send nil? :render $(sym _))
|
12
|
+
(send nil? {:render :render_to_string} $(sym _))
|
13
13
|
PATTERN
|
14
14
|
|
15
15
|
def_node_matcher :render_with_options?, <<-PATTERN
|
16
|
-
(send nil? :render (hash $...))
|
16
|
+
(send nil? {:render :render_to_string} (hash $...))
|
17
17
|
PATTERN
|
18
18
|
|
19
19
|
def_node_matcher :action_key?, <<-PATTERN
|
@@ -1,32 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rubocop"
|
4
|
+
require "rubocop/cop/github/render_literal_helpers"
|
4
5
|
|
5
6
|
module RuboCop
|
6
7
|
module Cop
|
7
8
|
module GitHub
|
8
9
|
class RailsControllerRenderLiteral < Cop
|
9
|
-
|
10
|
+
include RenderLiteralHelpers
|
10
11
|
|
11
|
-
|
12
|
-
({str sym true false nil?} ...)
|
13
|
-
PATTERN
|
14
|
-
|
15
|
-
def_node_matcher :render?, <<-PATTERN
|
16
|
-
(send nil? :render ...)
|
17
|
-
PATTERN
|
18
|
-
|
19
|
-
def_node_matcher :render_literal?, <<-PATTERN
|
20
|
-
(send nil? :render ({str sym} $_) $...)
|
21
|
-
PATTERN
|
22
|
-
|
23
|
-
def_node_matcher :render_const?, <<-PATTERN
|
24
|
-
(send nil? :render (const _ _) ...)
|
25
|
-
PATTERN
|
26
|
-
|
27
|
-
def_node_matcher :render_with_options?, <<-PATTERN
|
28
|
-
(send nil? :render (hash $...))
|
29
|
-
PATTERN
|
12
|
+
MSG = "render must be used with a string literal or an instance of a Class"
|
30
13
|
|
31
14
|
def_node_matcher :ignore_key?, <<-PATTERN
|
32
15
|
(pair (sym {
|
@@ -64,10 +47,16 @@ module RuboCop
|
|
64
47
|
}) ...)
|
65
48
|
PATTERN
|
66
49
|
|
50
|
+
def_node_matcher :render_const?, <<-PATTERN
|
51
|
+
(send nil? {:render :render_to_string} (const _ _) ...)
|
52
|
+
PATTERN
|
53
|
+
|
67
54
|
def on_send(node)
|
68
55
|
return unless render?(node)
|
69
56
|
|
70
|
-
if
|
57
|
+
return if render_view_component?(node) || render_const?(node)
|
58
|
+
|
59
|
+
if render_literal?(node)
|
71
60
|
elsif option_pairs = render_with_options?(node)
|
72
61
|
option_pairs = option_pairs.reject { |pair| options_key?(pair) }
|
73
62
|
|
@@ -78,18 +67,40 @@ module RuboCop
|
|
78
67
|
if template_node = option_pairs.map { |pair| template_key?(pair) }.compact.first
|
79
68
|
if !literal?(template_node)
|
80
69
|
add_offense(node, location: :expression)
|
70
|
+
return
|
81
71
|
end
|
82
72
|
else
|
83
73
|
add_offense(node, location: :expression)
|
74
|
+
return
|
84
75
|
end
|
85
76
|
|
86
77
|
if layout_node = option_pairs.map { |pair| layout_key?(pair) }.compact.first
|
87
78
|
if !literal?(layout_node)
|
88
79
|
add_offense(node, location: :expression)
|
80
|
+
return
|
89
81
|
end
|
90
82
|
end
|
91
83
|
else
|
92
84
|
add_offense(node, location: :expression)
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
88
|
+
if render_literal?(node)
|
89
|
+
option_hash = node.arguments[1]
|
90
|
+
if option_hash && !option_hash.hash_type?
|
91
|
+
add_offense(node, location: :expression)
|
92
|
+
return
|
93
|
+
end
|
94
|
+
option_pairs = option_hash && option_hash.pairs
|
95
|
+
else
|
96
|
+
option_pairs = node.arguments[0].pairs
|
97
|
+
end
|
98
|
+
|
99
|
+
if option_pairs
|
100
|
+
locals = option_pairs.map { |pair| locals_key?(pair) }.compact.first
|
101
|
+
if locals && (!locals.hash_type? || !hash_with_literal_keys?(locals))
|
102
|
+
add_offense(node, location: :expression)
|
103
|
+
end
|
93
104
|
end
|
94
105
|
end
|
95
106
|
end
|
@@ -7,15 +7,15 @@ module RuboCop
|
|
7
7
|
module GitHub
|
8
8
|
class RailsControllerRenderPathsExist < Cop
|
9
9
|
def_node_matcher :render?, <<-PATTERN
|
10
|
-
(send nil? :render $...)
|
10
|
+
(send nil? {:render :render_to_string} $...)
|
11
11
|
PATTERN
|
12
12
|
|
13
13
|
def_node_matcher :render_str?, <<-PATTERN
|
14
|
-
(send nil? :render $({str sym} $_) ...)
|
14
|
+
(send nil? {:render :render_to_string} $({str sym} $_) ...)
|
15
15
|
PATTERN
|
16
16
|
|
17
17
|
def_node_matcher :render_options?, <<-PATTERN
|
18
|
-
(send nil? :render (hash $...))
|
18
|
+
(send nil? {:render :render_to_string} (hash $...))
|
19
19
|
PATTERN
|
20
20
|
|
21
21
|
def_node_matcher :render_key?, <<-PATTERN
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
MSG = "Prefer `render` template shorthand"
|
10
10
|
|
11
11
|
def_node_matcher :render_with_options?, <<-PATTERN
|
12
|
-
(send nil? :render (hash $...))
|
12
|
+
(send nil? {:render :render_to_string} (hash $...))
|
13
13
|
PATTERN
|
14
14
|
|
15
15
|
def_node_matcher :action_key?, <<-PATTERN
|
@@ -1,32 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rubocop"
|
4
|
+
require "rubocop/cop/github/render_literal_helpers"
|
4
5
|
|
5
6
|
module RuboCop
|
6
7
|
module Cop
|
7
8
|
module GitHub
|
8
9
|
class RailsViewRenderLiteral < Cop
|
9
|
-
|
10
|
+
include RenderLiteralHelpers
|
10
11
|
|
11
|
-
|
12
|
-
({str sym true false nil?} ...)
|
13
|
-
PATTERN
|
14
|
-
|
15
|
-
def_node_matcher :render?, <<-PATTERN
|
16
|
-
(send nil? :render $...)
|
17
|
-
PATTERN
|
18
|
-
|
19
|
-
def_node_matcher :render_literal?, <<-PATTERN
|
20
|
-
(send nil? :render ({str sym} $_) $...)
|
21
|
-
PATTERN
|
22
|
-
|
23
|
-
def_node_matcher :render_const?, <<-PATTERN
|
24
|
-
(send nil? :render (const _ _) ...)
|
25
|
-
PATTERN
|
26
|
-
|
27
|
-
def_node_matcher :render_with_options?, <<-PATTERN
|
28
|
-
(send nil? :render (hash $...) ...)
|
29
|
-
PATTERN
|
12
|
+
MSG = "render must be used with a literal template and use literals for locals keys"
|
30
13
|
|
31
14
|
def_node_matcher :ignore_key?, <<-PATTERN
|
32
15
|
(pair (sym {
|
@@ -46,7 +29,10 @@ module RuboCop
|
|
46
29
|
def on_send(node)
|
47
30
|
return unless render?(node)
|
48
31
|
|
49
|
-
|
32
|
+
# Ignore "component"-style renders
|
33
|
+
return if render_view_component?(node)
|
34
|
+
|
35
|
+
if render_literal?(node)
|
50
36
|
elsif option_pairs = render_with_options?(node)
|
51
37
|
if option_pairs.any? { |pair| ignore_key?(pair) }
|
52
38
|
return
|
@@ -55,12 +41,31 @@ module RuboCop
|
|
55
41
|
if partial_node = option_pairs.map { |pair| partial_key?(pair) }.compact.first
|
56
42
|
if !literal?(partial_node)
|
57
43
|
add_offense(node, location: :expression)
|
44
|
+
return
|
58
45
|
end
|
59
46
|
else
|
60
47
|
add_offense(node, location: :expression)
|
48
|
+
return
|
61
49
|
end
|
62
50
|
else
|
63
51
|
add_offense(node, location: :expression)
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
if render_literal?(node) && node.arguments.count > 1
|
56
|
+
locals = node.arguments[1]
|
57
|
+
elsif options_pairs = render_with_options?(node)
|
58
|
+
locals = option_pairs.map { |pair| locals_key?(pair) }.compact.first
|
59
|
+
end
|
60
|
+
|
61
|
+
if locals
|
62
|
+
if locals.hash_type?
|
63
|
+
if !hash_with_literal_keys?(locals)
|
64
|
+
add_offense(node, location: :expression)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
add_offense(node, location: :expression)
|
68
|
+
end
|
64
69
|
end
|
65
70
|
end
|
66
71
|
end
|
@@ -7,15 +7,15 @@ module RuboCop
|
|
7
7
|
module GitHub
|
8
8
|
class RailsViewRenderPathsExist < Cop
|
9
9
|
def_node_matcher :render?, <<-PATTERN
|
10
|
-
(send nil? :render $...)
|
10
|
+
(send nil? {:render :render_to_string} $...)
|
11
11
|
PATTERN
|
12
12
|
|
13
13
|
def_node_matcher :render_str?, <<-PATTERN
|
14
|
-
(send nil? :render $(str $_) ...)
|
14
|
+
(send nil? {:render :render_to_string} $(str $_) ...)
|
15
15
|
PATTERN
|
16
16
|
|
17
17
|
def_node_matcher :render_options?, <<-PATTERN
|
18
|
-
(send nil? :render (hash $...))
|
18
|
+
(send nil? {:render :render_to_string} (hash $...))
|
19
19
|
PATTERN
|
20
20
|
|
21
21
|
def_node_matcher :partial_key?, <<-PATTERN
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
MSG = "Prefer `render` partial shorthand"
|
10
10
|
|
11
11
|
def_node_matcher :render_with_options?, <<-PATTERN
|
12
|
-
(send nil? :render (hash $...))
|
12
|
+
(send nil? {:render :render_to_string} (hash $...))
|
13
13
|
PATTERN
|
14
14
|
|
15
15
|
def_node_matcher :partial_key?, <<-PATTERN
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module GitHub
|
8
|
+
module RenderLiteralHelpers
|
9
|
+
extend NodePattern::Macros
|
10
|
+
|
11
|
+
def_node_matcher :literal?, <<-PATTERN
|
12
|
+
({str sym true false nil?} ...)
|
13
|
+
PATTERN
|
14
|
+
|
15
|
+
def_node_matcher :render?, <<-PATTERN
|
16
|
+
(send nil? {:render :render_to_string} ...)
|
17
|
+
PATTERN
|
18
|
+
|
19
|
+
def_node_matcher :render_literal?, <<-PATTERN
|
20
|
+
(send nil? {:render :render_to_string} ({str sym} $_) $...)
|
21
|
+
PATTERN
|
22
|
+
|
23
|
+
def_node_matcher :render_with_options?, <<-PATTERN
|
24
|
+
(send nil? {:render :render_to_string} (hash $...) ...)
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def_node_matcher :render_view_component_instance?, <<-PATTERN
|
28
|
+
(send nil? {:render :render_to_string} (send _ :new ...) ...)
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
def_node_matcher :render_view_component_instance_with_content?, <<-PATTERN
|
32
|
+
(send nil? {:render :render_to_string} (send (send _ :new ...) `:with_content ...))
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def_node_matcher :render_view_component_collection?, <<-PATTERN
|
36
|
+
(send nil? {:render :render_to_string} (send _ :with_collection ...) ...)
|
37
|
+
PATTERN
|
38
|
+
|
39
|
+
def_node_matcher :locals_key?, <<-PATTERN
|
40
|
+
(pair (sym :locals) $_)
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def hash_with_literal_keys?(hash)
|
44
|
+
hash.pairs.all? { |pair| literal?(pair.key) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def render_view_component?(node)
|
48
|
+
render_view_component_instance_with_content?(node) ||
|
49
|
+
render_view_component_instance?(node) ||
|
50
|
+
render_view_component_collection?(node)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|