brakeman 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +46 -0
  3. data/README.md +10 -1
  4. data/bundle/load.rb +4 -3
  5. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/MIT-LICENSE.txt +20 -0
  6. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel.rb +523 -0
  7. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel/processor_count.rb +42 -0
  8. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel/version.rb +3 -0
  9. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/LICENSE.txt +0 -0
  10. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/NEWS.md +37 -0
  11. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/README.md +2 -14
  12. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml.rb +3 -0
  13. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/attlistdecl.rb +0 -0
  14. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/attribute.rb +0 -0
  15. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/cdata.rb +0 -0
  16. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/child.rb +0 -0
  17. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/comment.rb +0 -0
  18. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/doctype.rb +55 -31
  19. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/document.rb +194 -34
  20. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/attlistdecl.rb +0 -0
  21. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/dtd.rb +0 -0
  22. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/elementdecl.rb +0 -0
  23. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/entitydecl.rb +0 -0
  24. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/notationdecl.rb +0 -0
  25. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/element.rb +2599 -0
  26. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/encoding.rb +0 -0
  27. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/entity.rb +0 -0
  28. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/formatters/default.rb +0 -0
  29. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/formatters/pretty.rb +0 -0
  30. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/formatters/transitive.rb +0 -0
  31. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/functions.rb +0 -0
  32. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/instruction.rb +0 -0
  33. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/light/node.rb +0 -8
  34. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/namespace.rb +0 -0
  35. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/node.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/output.rb +0 -0
  37. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parent.rb +0 -0
  38. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parseexception.rb +0 -0
  39. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/baseparser.rb +139 -39
  40. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/lightparser.rb +0 -0
  41. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/pullparser.rb +0 -0
  42. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/sax2parser.rb +0 -0
  43. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/streamparser.rb +0 -0
  44. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/treeparser.rb +0 -0
  45. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/ultralightparser.rb +0 -0
  46. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/xpathparser.rb +25 -11
  47. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/quickpath.rb +0 -0
  48. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/rexml.rb +37 -0
  49. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/sax2listener.rb +0 -0
  50. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/security.rb +0 -0
  51. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/source.rb +0 -0
  52. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/streamlistener.rb +0 -0
  53. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/text.rb +0 -0
  54. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/undefinednamespaceexception.rb +0 -0
  55. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/validation/relaxng.rb +0 -0
  56. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/validation/validation.rb +0 -0
  57. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/validation/validationexception.rb +0 -0
  58. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xmldecl.rb +0 -0
  59. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xmltokens.rb +0 -0
  60. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xpath.rb +0 -0
  61. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xpath_parser.rb +36 -30
  62. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/History.rdoc +19 -0
  63. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/Manifest.txt +2 -0
  64. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/README.rdoc +0 -0
  65. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/compare/normalize.rb +2 -2
  66. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/debugging.md +190 -0
  67. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/rp_extensions.rb +0 -0
  68. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/rp_stringscanner.rb +0 -0
  69. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby20_parser.rb +2550 -2537
  70. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby20_parser.y +9 -1
  71. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby21_parser.rb +7148 -0
  72. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby21_parser.y +9 -1
  73. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby22_parser.rb +7185 -0
  74. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby22_parser.y +9 -1
  75. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby23_parser.rb +2585 -2561
  76. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby23_parser.y +9 -1
  77. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby24_parser.rb +2622 -2607
  78. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby24_parser.y +9 -1
  79. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby25_parser.rb +2612 -2598
  80. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby25_parser.y +9 -1
  81. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby26_parser.rb +2610 -2594
  82. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby26_parser.y +10 -1
  83. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby27_parser.rb +7358 -0
  84. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby27_parser.y +47 -1
  85. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.rb +7358 -0
  86. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.y +2703 -0
  87. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_lexer.rb +19 -0
  88. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_lexer.rex +1 -1
  89. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_lexer.rex.rb +1 -1
  90. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_parser.rb +2 -0
  91. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_parser.yy +57 -1
  92. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_parser_extras.rb +2 -2
  93. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/tools/munge.rb +2 -2
  94. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/tools/ripper.rb +1 -1
  95. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/History.rdoc +6 -0
  96. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/Manifest.txt +0 -0
  97. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/README.rdoc +0 -0
  98. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/composite_sexp_processor.rb +0 -0
  99. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/pt_testcase.rb +2 -2
  100. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/sexp.rb +0 -0
  101. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/sexp_matcher.rb +0 -0
  102. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/sexp_processor.rb +1 -1
  103. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/strict_sexp.rb +0 -0
  104. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/unique.rb +0 -0
  105. data/lib/brakeman.rb +23 -8
  106. data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
  107. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  108. data/lib/brakeman/checks/check_execute.rb +10 -0
  109. data/lib/brakeman/checks/check_mass_assignment.rb +4 -6
  110. data/lib/brakeman/checks/check_render.rb +15 -1
  111. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -1
  112. data/lib/brakeman/checks/check_sql.rb +58 -8
  113. data/lib/brakeman/checks/check_verb_confusion.rb +1 -1
  114. data/lib/brakeman/commandline.rb +1 -1
  115. data/lib/brakeman/file_parser.rb +45 -15
  116. data/lib/brakeman/options.rb +7 -2
  117. data/lib/brakeman/parsers/template_parser.rb +24 -0
  118. data/lib/brakeman/processors/alias_processor.rb +105 -18
  119. data/lib/brakeman/processors/base_processor.rb +4 -4
  120. data/lib/brakeman/processors/controller_alias_processor.rb +6 -43
  121. data/lib/brakeman/processors/lib/call_conversion_helper.rb +10 -6
  122. data/lib/brakeman/processors/lib/rails4_config_processor.rb +2 -1
  123. data/lib/brakeman/processors/library_processor.rb +9 -0
  124. data/lib/brakeman/processors/model_processor.rb +31 -0
  125. data/lib/brakeman/report.rb +4 -1
  126. data/lib/brakeman/report/ignore/config.rb +4 -4
  127. data/lib/brakeman/report/ignore/interactive.rb +1 -1
  128. data/lib/brakeman/report/report_github.rb +31 -0
  129. data/lib/brakeman/report/report_sarif.rb +21 -2
  130. data/lib/brakeman/rescanner.rb +1 -1
  131. data/lib/brakeman/scanner.rb +4 -1
  132. data/lib/brakeman/tracker.rb +33 -4
  133. data/lib/brakeman/tracker/collection.rb +57 -7
  134. data/lib/brakeman/tracker/method_info.rb +70 -0
  135. data/lib/brakeman/util.rb +34 -18
  136. data/lib/brakeman/version.rb +1 -1
  137. data/lib/ruby_parser/bm_sexp.rb +14 -0
  138. metadata +104 -97
  139. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/Gemfile +0 -6
  140. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/element.rb +0 -1269
  141. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/rexml.rb +0 -32
  142. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/rexml.gemspec +0 -84
  143. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/debugging.md +0 -57
  144. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby21_parser.rb +0 -7140
  145. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby22_parser.rb +0 -7160
  146. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby27_parser.rb +0 -7224
@@ -8,7 +8,7 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
8
8
  include Brakeman::SafeCallHelper
9
9
  include Brakeman::Util
10
10
 
11
- IGNORE = Sexp.new :ignore
11
+ IGNORE = Sexp.new(:ignore).line(0)
12
12
 
13
13
  #Return a new Processor.
14
14
  def initialize tracker
@@ -216,7 +216,7 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
216
216
  #
217
217
  #And also :layout for inside templates
218
218
  def find_render_type call, in_view = false
219
- rest = Sexp.new(:hash)
219
+ rest = Sexp.new(:hash).line(call.line)
220
220
  type = nil
221
221
  value = nil
222
222
  first_arg = call.first_arg
@@ -236,7 +236,7 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
236
236
  end
237
237
  elsif first_arg.is_a? Symbol or first_arg.is_a? String
238
238
  type = :action
239
- value = Sexp.new(:lit, first_arg.to_sym)
239
+ value = Sexp.new(:lit, first_arg.to_sym).line(call.line)
240
240
  elsif first_arg.nil?
241
241
  type = :default
242
242
  elsif not hash? first_arg
@@ -293,6 +293,6 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
293
293
  @tracker.processor.process_template(template_name, ast, type, nil, @current_file)
294
294
  @tracker.processor.process_template_alias(@tracker.templates[template_name])
295
295
 
296
- return s(:lit, template_name), options
296
+ return s(:lit, template_name).line(value.line), options
297
297
  end
298
298
  end
@@ -51,7 +51,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
51
51
  #Need to process the method like it was in a controller in order
52
52
  #to get the renders set
53
53
  processor = Brakeman::ControllerProcessor.new(@tracker, mixin.file)
54
- method = mixin.get_method(name)[:src].deep_clone
54
+ method = mixin.get_method(name).src.deep_clone
55
55
 
56
56
  if node_type? method, :defn
57
57
  method = processor.process_defn method
@@ -143,16 +143,16 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
143
143
  #Basically, adds any instance variable assignments to the environment.
144
144
  #TODO: method arguments?
145
145
  def process_before_filter name
146
- filter = find_method name, @current_class
146
+ filter = tracker.find_method name, @current_class
147
147
 
148
148
  if filter.nil?
149
149
  Brakeman.debug "[Notice] Could not find filter #{name}"
150
150
  return
151
151
  end
152
152
 
153
- method = filter[:method]
153
+ method = filter.src
154
154
 
155
- if ivars = @tracker.filter_cache[[filter[:controller], name]]
155
+ if ivars = @tracker.filter_cache[[filter.owner, name]]
156
156
  ivars.each do |variable, value|
157
157
  env[variable] = value
158
158
  end
@@ -162,7 +162,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
162
162
 
163
163
  ivars = processor.only_ivars(:include_request_vars).all
164
164
 
165
- @tracker.filter_cache[[filter[:controller], name]] = ivars
165
+ @tracker.filter_cache[[filter.owner, name]] = ivars
166
166
 
167
167
  ivars.each do |variable, value|
168
168
  env[variable] = value
@@ -182,7 +182,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
182
182
  # method as the line number
183
183
  if line.nil? and controller = @tracker.controllers[@current_class]
184
184
  if meth = controller.get_method(@current_method)
185
- if line = meth[:src] && meth[:src].last && meth[:src].last.line
185
+ if line = meth.src && meth.src.last && meth.src.last.line
186
186
  line += 1
187
187
  else
188
188
  line = 1
@@ -241,41 +241,4 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
241
241
  []
242
242
  end
243
243
  end
244
-
245
- #Finds a method in the given class or a parent class
246
- #
247
- #Returns nil if the method could not be found.
248
- #
249
- #If found, returns hash table with controller name and method sexp.
250
- def find_method method_name, klass
251
- return nil if sexp? method_name
252
- method_name = method_name.to_sym
253
-
254
- if method = @method_cache[method_name]
255
- return method
256
- end
257
-
258
- controller = @tracker.controllers[klass]
259
- controller ||= @tracker.libs[klass]
260
-
261
- if klass and controller
262
- method = controller.get_method method_name
263
-
264
- if method.nil?
265
- controller.includes.each do |included|
266
- method = find_method method_name, included
267
- if method
268
- @method_cache[method_name] = method
269
- return method
270
- end
271
- end
272
-
273
- @method_cache[method_name] = find_method method_name, controller.parent
274
- else
275
- @method_cache[method_name] = { :controller => controller.name, :method => method[:src] }
276
- end
277
- else
278
- nil
279
- end
280
- end
281
244
  end
@@ -1,11 +1,5 @@
1
1
  module Brakeman
2
2
  module CallConversionHelper
3
- def all_literals? exp, expected_type = :array
4
- node_type? exp, expected_type and
5
- exp.length > 1 and
6
- exp.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
7
- end
8
-
9
3
  # Join two array literals into one.
10
4
  def join_arrays lhs, rhs, original_exp = nil
11
5
  if array? lhs and array? rhs
@@ -76,6 +70,8 @@ module Brakeman
76
70
 
77
71
  #Have to do this because first element is :array and we have to skip it
78
72
  array[1..-1][index] or original_exp
73
+ elsif all_literals? array
74
+ safe_literal(array.line)
79
75
  else
80
76
  original_exp
81
77
  end
@@ -92,5 +88,13 @@ module Brakeman
92
88
  original_exp
93
89
  end
94
90
  end
91
+
92
+ def hash_values_at hash, keys
93
+ values = keys.map do |key|
94
+ process_hash_access hash, key
95
+ end
96
+
97
+ Sexp.new(:array).concat(values).line(hash.line)
98
+ end
95
99
  end
96
100
  end
@@ -2,10 +2,11 @@ require 'brakeman/processors/lib/rails3_config_processor'
2
2
 
3
3
  class Brakeman::Rails4ConfigProcessor < Brakeman::Rails3ConfigProcessor
4
4
  APPLICATION_CONFIG = s(:call, s(:call, s(:const, :Rails), :application), :configure)
5
+ ALT_APPLICATION_CONFIG = s(:call, s(:call, s(:colon3, :Rails), :application), :configure)
5
6
 
6
7
  # Look for Rails.application.configure do ... end
7
8
  def process_iter exp
8
- if exp.block_call == APPLICATION_CONFIG
9
+ if exp.block_call == APPLICATION_CONFIG or exp.block_call == ALT_APPLICATION_CONFIG
9
10
  @inside_config = true
10
11
  process exp.block if sexp? exp.block
11
12
  @inside_config = false
@@ -54,6 +54,15 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
54
54
 
55
55
  def process_call exp
56
56
  if process_call_defn? exp
57
+ exp
58
+ elsif @current_method.nil? and exp.target.nil? and (@current_class or @current_module)
59
+ # Methods called inside class / module
60
+ case exp.method
61
+ when :include
62
+ module_name = class_name(exp.first_arg)
63
+ (@current_class || @current_module).add_include module_name
64
+ end
65
+
57
66
  exp
58
67
  else
59
68
  process_default exp
@@ -73,6 +73,8 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
73
73
  @current_class.set_attr_accessible exp
74
74
  when :attr_protected
75
75
  @current_class.set_attr_protected exp
76
+ when :enum
77
+ add_enum_method exp
76
78
  else
77
79
  if @current_class
78
80
  @current_class.add_option method, exp
@@ -87,4 +89,33 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
87
89
  call
88
90
  end
89
91
  end
92
+
93
+ def add_enum_method call
94
+ arg = call.first_arg
95
+ return unless hash? arg
96
+
97
+ enum_name = arg[1].value # first key
98
+ enums = arg[2] # first value
99
+ enums_name = pluralize(enum_name.to_s).to_sym
100
+
101
+ call_line = call.line
102
+
103
+ if hash? enums
104
+ enum_values = enums
105
+ elsif array? enums
106
+ # Build hash for enum values like Rails does
107
+ enum_values = s(:hash).line(call_line)
108
+
109
+ enums.each_sexp.with_index do |v, index|
110
+ enum_values << v
111
+ enum_values << s(:lit, index).line(call_line)
112
+ end
113
+ end
114
+
115
+ enum_method = s(:defn, enum_name, s(:args), safe_literal(call_line))
116
+ enums_method = s(:defs, s(:self), enums_name, s(:args), enum_values)
117
+
118
+ @current_class.add_method :public, enum_name, enum_method, @current_file
119
+ @current_class.add_method :public, enums_name, enums_method, @current_file
120
+ end
90
121
  end
@@ -6,7 +6,7 @@ require 'brakeman/report/report_base'
6
6
  class Brakeman::Report
7
7
  attr_reader :tracker
8
8
 
9
- VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate, :to_plain, :to_text, :to_junit]
9
+ VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate, :to_plain, :to_text, :to_junit, :to_github]
10
10
 
11
11
  def initialize tracker
12
12
  @app_tree = tracker.app_tree
@@ -48,6 +48,9 @@ class Brakeman::Report
48
48
  when :to_sonar
49
49
  require_report 'sonar'
50
50
  Brakeman::Report::Sonar
51
+ when :to_github
52
+ require_report 'github'
53
+ Brakeman::Report::Github
51
54
  else
52
55
  raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
53
56
  end
@@ -100,14 +100,14 @@ module Brakeman
100
100
 
101
101
  # Read configuration to file
102
102
  def read_from_file file = @file
103
- if File.exist? file
103
+ if File.exist? file.absolute
104
104
  begin
105
105
  @already_ignored = JSON.parse(File.read(file), :symbolize_names => true)[:ignored_warnings]
106
106
  rescue => e
107
- raise e, "\nError[#{e.class}] while reading brakeman ignore file: #{file}\n"
107
+ raise e, "\nError[#{e.class}] while reading brakeman ignore file: #{file.relative}\n"
108
108
  end
109
109
  else
110
- Brakeman.notify "[Notice] Could not find ignore configuration in #{file}"
110
+ Brakeman.notify "[Notice] Could not find ignore configuration in #{file.relative}"
111
111
  @already_ignored = []
112
112
  end
113
113
 
@@ -134,7 +134,7 @@ module Brakeman
134
134
  :brakeman_version => Brakeman::Version
135
135
  }
136
136
 
137
- File.open file, "w" do |f|
137
+ File.open file.absolute, "w" do |f|
138
138
  f.puts JSON.pretty_generate(output)
139
139
  end
140
140
  end
@@ -62,7 +62,7 @@ module Brakeman
62
62
  process_warnings
63
63
  end
64
64
 
65
- m.choice "Hide previously ignored warnings" do
65
+ m.choice "Inspect new warnings" do
66
66
  @skip_ignored = true
67
67
  pre_show_help
68
68
  process_warnings
@@ -0,0 +1,31 @@
1
+ # Github Actions Formatter
2
+ # Formats warnings as workflow commands to create annotations in GitHub UI
3
+ class Brakeman::Report::Github < Brakeman::Report::Base
4
+ def generate_report
5
+ # @see https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
6
+ errors.concat(warnings).join("\n")
7
+ end
8
+
9
+ def warnings
10
+ all_warnings
11
+ .map { |warning| "::warning file=#{warning_file(warning)},line=#{warning.line}::#{warning.message}" }
12
+ end
13
+
14
+ def errors
15
+ tracker.errors.map do |error|
16
+ if error[:exception].is_a?(Racc::ParseError)
17
+ # app/services/balance.rb:4 :: parse error on value "..." (tDOT3)
18
+ file, line = error[:exception].message.split(':').map(&:strip)[0,2]
19
+ "::error file=#{file},line=#{line}::#{clean_message(error[:error])}"
20
+ else
21
+ "::error ::#{clean_message(error[:error])}"
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def clean_message(msg)
29
+ msg.gsub('::','').squeeze(' ')
30
+ end
31
+ end
@@ -48,7 +48,7 @@ class Brakeman::Report::SARIF < Brakeman::Report::Base
48
48
  end
49
49
 
50
50
  def results
51
- @results ||= all_warnings.map do |warning|
51
+ @results ||= tracker.checks.all_warnings.map do |warning|
52
52
  rule_id = render_id warning
53
53
  result_level = infer_level warning
54
54
  message_text = render_message warning.message.to_s
@@ -72,6 +72,23 @@ class Brakeman::Report::SARIF < Brakeman::Report::Base
72
72
  ],
73
73
  }
74
74
 
75
+ if @ignore_filter && @ignore_filter.ignored?(warning)
76
+ result[:suppressions] = [
77
+ {
78
+ :kind => 'external',
79
+ :justification => @ignore_filter.note_for(warning),
80
+ :location => {
81
+ :physicalLocation => {
82
+ :artifactLocation => {
83
+ :uri => @ignore_filter.file.relative,
84
+ :uriBaseId => '%SRCROOT%',
85
+ },
86
+ },
87
+ },
88
+ }
89
+ ]
90
+ end
91
+
75
92
  result
76
93
  end
77
94
  end
@@ -85,7 +102,7 @@ class Brakeman::Report::SARIF < Brakeman::Report::Base
85
102
 
86
103
  # Returns a de-duplicated set of warnings, used to generate rules
87
104
  def unique_warnings_by_warning_code
88
- @unique_warnings_by_warning_code ||= all_warnings.uniq { |w| w.warning_code }
105
+ @unique_warnings_by_warning_code ||= tracker.checks.all_warnings.uniq { |w| w.warning_code }
89
106
  end
90
107
 
91
108
  def render_id warning
@@ -94,6 +111,8 @@ class Brakeman::Report::SARIF < Brakeman::Report::Base
94
111
  end
95
112
 
96
113
  def render_message message
114
+ return message if message.nil?
115
+
97
116
  # Ensure message ends with a period
98
117
  if message.end_with? "."
99
118
  message
@@ -391,7 +391,7 @@ class Brakeman::Rescanner < Brakeman::Scanner
391
391
 
392
392
  def parse_ruby_files list
393
393
  paths = list.select(&:exists?)
394
- file_parser = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
394
+ file_parser = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout], tracker.options[:parallel_checks])
395
395
  file_parser.parse_files paths
396
396
  tracker.add_errors(file_parser.errors)
397
397
  file_parser.file_list
@@ -71,7 +71,7 @@ class Brakeman::Scanner
71
71
  end
72
72
 
73
73
  def parse_files
74
- fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
74
+ fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout], tracker.options[:parallel_checks])
75
75
 
76
76
  fp.parse_files tracker.app_tree.ruby_file_paths
77
77
 
@@ -353,6 +353,9 @@ class Brakeman::Scanner
353
353
  def parse_ruby_file file
354
354
  fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
355
355
  fp.parse_ruby(file.read, file)
356
+ rescue Exception => e
357
+ tracker.error(e)
358
+ nil
356
359
  end
357
360
  end
358
361
 
@@ -35,6 +35,7 @@ class Brakeman::Tracker
35
35
  #class they are.
36
36
  @models = {}
37
37
  @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, @app_tree.file_path("NOT_REAL.rb"), nil, self)
38
+ @method_cache = {}
38
39
  @routes = {}
39
40
  @initializers = {}
40
41
  @errors = []
@@ -99,8 +100,8 @@ class Brakeman::Tracker
99
100
  classes.each do |set|
100
101
  set.each do |set_name, collection|
101
102
  collection.each_method do |method_name, definition|
102
- src = definition[:src]
103
- yield src, set_name, method_name, definition[:file]
103
+ src = definition.src
104
+ yield src, set_name, method_name, definition.file
104
105
  end
105
106
  end
106
107
  end
@@ -220,6 +221,34 @@ class Brakeman::Tracker
220
221
  nil
221
222
  end
222
223
 
224
+ def find_method method_name, class_name, method_type = :instance
225
+ return nil unless method_name.is_a? Symbol
226
+
227
+ klass = find_class(class_name)
228
+ return nil unless klass
229
+
230
+ cache_key = [klass, method_name, method_type]
231
+
232
+ if method = @method_cache[cache_key]
233
+ return method
234
+ end
235
+
236
+ if method = klass.get_method(method_name, method_type)
237
+ return method
238
+ else
239
+ # Check modules included for method definition
240
+ # TODO: only for instance methods, otherwise check extends!
241
+ klass.includes.each do |included_name|
242
+ if method = find_method(method_name, included_name, method_type)
243
+ return (@method_cache[cache_key] = method)
244
+ end
245
+ end
246
+
247
+ # Not in any included modules, check the parent
248
+ @method_cache[cache_key] = find_method(method_name, klass.parent)
249
+ end
250
+ end
251
+
223
252
  def index_call_sites
224
253
  finder = Brakeman::FindAllCalls.new self
225
254
 
@@ -285,8 +314,8 @@ class Brakeman::Tracker
285
314
  method_sets.each do |set|
286
315
  set.each do |set_name, info|
287
316
  info.each_method do |method_name, definition|
288
- src = definition[:src]
289
- finder.process_source src, :class => set_name, :method => method_name, :file => definition[:file]
317
+ src = definition.src
318
+ finder.process_source src, :class => set_name, :method => method_name, :file => definition.file
290
319
  end
291
320
  end
292
321
  end