rubocop-github 0.12.0 → 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ inherit_from: _default_shared.yml
2
+
3
+ require:
4
+ - rubocop-performance
data/config/rails.yml CHANGED
@@ -1,118 +1,2 @@
1
- Rails:
2
- Enabled: true
3
-
4
- Rails/FindEach:
5
- Enabled: false
6
-
7
- Rails/OutputSafety:
8
- Enabled: true
9
-
10
- Rails/PluralizationGrammar:
11
- Enabled: true
12
-
13
- Rails/RequestReferer:
14
- Enabled: true
15
- EnforcedStyle: referrer
16
-
17
- Rails/ScopeArgs:
18
- Enabled: true
19
-
20
- Rails/UniqBeforePluck:
21
- Enabled: true
22
-
23
- GitHub/RailsApplicationRecord:
24
- Enabled: true
25
-
26
- GitHub/RailsControllerRenderActionSymbol:
27
- Enabled: true
28
- Include:
29
- - 'app/controllers/**/*.rb'
30
-
31
- GitHub/RailsControllerRenderLiteral:
32
- Enabled: true
33
- StyleGuide: https://github.com/github/rubocop-github/blob/master/guides/rails-render-literal.md
34
- Include:
35
- - 'app/controllers/**/*.rb'
36
-
37
- GitHub/RailsControllerRenderPathsExist:
38
- Enabled: true
39
- ViewPath:
40
- - 'app/views'
41
- Include:
42
- - 'app/controllers/**/*.rb'
43
-
44
- GitHub/RailsControllerRenderShorthand:
45
- Enabled: true
46
- StyleGuide: https://github.com/github/rubocop-github/blob/master/guides/rails-controller-render-shorthand.md
47
- Include:
48
- - 'app/controllers/**/*.rb'
49
-
50
- GitHub/RailsRenderInline:
51
- Enabled: true
52
- StyleGuide: https://github.com/github/rubocop-github/blob/master/guides/rails-controller-render-inline.md
53
- Include:
54
- - 'app/controllers/**/*.rb'
55
- - 'app/helpers/**/*.rb'
56
- - 'app/view_models/**/*.rb'
57
- - 'app/views/**/*.erb'
58
-
59
- GitHub/RailsRenderObjectCollection:
60
- Enabled: false
61
-
62
- GitHub/RailsViewRenderLiteral:
63
- Enabled: true
64
- StyleGuide: https://github.com/github/rubocop-github/blob/master/guides/rails-render-literal.md
65
- Include:
66
- - 'app/helpers/**/*.rb'
67
- - 'app/view_models/**/*.rb'
68
- - 'app/views/**/*.erb'
69
-
70
- GitHub/RailsViewRenderPathsExist:
71
- Enabled: true
72
- ViewPath:
73
- - 'app/views'
74
- Include:
75
- - 'app/helpers/**/*.rb'
76
- - 'app/view_models/**/*.rb'
77
- - 'app/views/**/*.erb'
78
-
79
- GitHub/RailsViewRenderShorthand:
80
- Enabled: true
81
- Include:
82
- - 'app/helpers/**/*.rb'
83
- - 'app/view_models/**/*.rb'
84
- - 'app/views/**/*.erb'
85
-
86
- # Exclude Rails ERB files from incompatible cops
87
-
88
- Layout/BlockAlignment:
89
- Exclude:
90
- - 'app/views/**/*.erb'
91
-
92
- Style/For:
93
- Exclude:
94
- - 'app/views/**/*.erb'
95
-
96
- Style/OneLineConditional:
97
- Exclude:
98
- - 'app/views/**/*.erb'
99
-
100
- Style/Semicolon:
101
- Exclude:
102
- - 'app/views/**/*.erb'
103
-
104
- Layout/SpaceInsideParens:
105
- Exclude:
106
- - 'app/views/**/*.erb'
107
-
108
- Style/StringLiterals:
109
- Exclude:
110
- - 'app/views/**/*.erb'
111
-
112
- Layout/TrailingBlankLines:
113
- Exclude:
114
- - 'app/views/**/*.erb'
115
-
116
- Layout/TrailingWhitespace:
117
- Exclude:
118
- - 'app/views/**/*.erb'
1
+ # Inherit from rails_deprecated until 1.0
2
+ inherit_from: rails_deprecated.yml
@@ -0,0 +1,7 @@
1
+ inherit_from: _rails_shared.yml
2
+
3
+ Rails:
4
+ Enabled: true
5
+
6
+ Rails/FindEach:
7
+ Enabled: false
@@ -0,0 +1,4 @@
1
+ inherit_from: _rails_shared.yml
2
+
3
+ require:
4
+ - rubocop-rails
@@ -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,28 +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
- MSG = "render must be used with a string literal"
10
+ include RenderLiteralHelpers
10
11
 
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 ...)
17
- PATTERN
18
-
19
- def_node_matcher :render_literal?, <<-PATTERN
20
- (send nil? :render ({str sym} $_) $...)
21
- PATTERN
22
-
23
- def_node_matcher :render_with_options?, <<-PATTERN
24
- (send nil? :render (hash $...))
25
- PATTERN
12
+ MSG = "render must be used with a string literal or an instance of a Class"
26
13
 
27
14
  def_node_matcher :ignore_key?, <<-PATTERN
28
15
  (pair (sym {
@@ -60,9 +47,15 @@ module RuboCop
60
47
  }) ...)
61
48
  PATTERN
62
49
 
50
+ def_node_matcher :render_const?, <<-PATTERN
51
+ (send nil? {:render :render_to_string} (const _ _) ...)
52
+ PATTERN
53
+
63
54
  def on_send(node)
64
55
  return unless render?(node)
65
56
 
57
+ return if render_view_component?(node) || render_const?(node)
58
+
66
59
  if render_literal?(node)
67
60
  elsif option_pairs = render_with_options?(node)
68
61
  option_pairs = option_pairs.reject { |pair| options_key?(pair) }
@@ -74,18 +67,40 @@ module RuboCop
74
67
  if template_node = option_pairs.map { |pair| template_key?(pair) }.compact.first
75
68
  if !literal?(template_node)
76
69
  add_offense(node, location: :expression)
70
+ return
77
71
  end
78
72
  else
79
73
  add_offense(node, location: :expression)
74
+ return
80
75
  end
81
76
 
82
77
  if layout_node = option_pairs.map { |pair| layout_key?(pair) }.compact.first
83
78
  if !literal?(layout_node)
84
79
  add_offense(node, location: :expression)
80
+ return
85
81
  end
86
82
  end
87
83
  else
88
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
89
104
  end
90
105
  end
91
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
@@ -9,7 +9,7 @@ module RuboCop
9
9
  MSG = "Avoid `render inline:`"
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 :inline_key?, <<-PATTERN
@@ -9,7 +9,7 @@ module RuboCop
9
9
  MSG = "Avoid `render object:`"
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
@@ -1,28 +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
- MSG = "render must be used with a string literal"
10
+ include RenderLiteralHelpers
10
11
 
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 $...)
17
- PATTERN
18
-
19
- def_node_matcher :render_literal?, <<-PATTERN
20
- (send nil? :render ({str sym} $_) $...)
21
- PATTERN
22
-
23
- def_node_matcher :render_with_options?, <<-PATTERN
24
- (send nil? :render (hash $...) ...)
25
- PATTERN
12
+ MSG = "render must be used with a literal template and use literals for locals keys"
26
13
 
27
14
  def_node_matcher :ignore_key?, <<-PATTERN
28
15
  (pair (sym {
@@ -33,6 +20,7 @@ module RuboCop
33
20
  def_node_matcher :partial_key?, <<-PATTERN
34
21
  (pair (sym {
35
22
  :file
23
+ :template
36
24
  :layout
37
25
  :partial
38
26
  }) $_)
@@ -41,6 +29,9 @@ module RuboCop
41
29
  def on_send(node)
42
30
  return unless render?(node)
43
31
 
32
+ # Ignore "component"-style renders
33
+ return if render_view_component?(node)
34
+
44
35
  if render_literal?(node)
45
36
  elsif option_pairs = render_with_options?(node)
46
37
  if option_pairs.any? { |pair| ignore_key?(pair) }
@@ -50,12 +41,31 @@ module RuboCop
50
41
  if partial_node = option_pairs.map { |pair| partial_key?(pair) }.compact.first
51
42
  if !literal?(partial_node)
52
43
  add_offense(node, location: :expression)
44
+ return
53
45
  end
54
46
  else
55
47
  add_offense(node, location: :expression)
48
+ return
56
49
  end
57
50
  else
58
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
59
69
  end
60
70
  end
61
71
  end