brakeman 4.10.1 → 5.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +44 -0
  3. data/README.md +11 -2
  4. data/bundle/load.rb +3 -3
  5. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/LICENSE.txt +0 -0
  6. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/NEWS.md +37 -0
  7. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/README.md +2 -14
  8. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml.rb +3 -0
  9. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/attlistdecl.rb +0 -0
  10. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/attribute.rb +0 -0
  11. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/cdata.rb +0 -0
  12. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/child.rb +0 -0
  13. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/comment.rb +0 -0
  14. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/doctype.rb +55 -31
  15. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/document.rb +194 -34
  16. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/attlistdecl.rb +0 -0
  17. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/dtd.rb +0 -0
  18. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/elementdecl.rb +0 -0
  19. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/entitydecl.rb +0 -0
  20. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/dtd/notationdecl.rb +0 -0
  21. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/element.rb +2599 -0
  22. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/encoding.rb +0 -0
  23. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/entity.rb +0 -0
  24. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/formatters/default.rb +0 -0
  25. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/formatters/pretty.rb +0 -0
  26. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/formatters/transitive.rb +0 -0
  27. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/functions.rb +0 -0
  28. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/instruction.rb +0 -0
  29. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/light/node.rb +0 -8
  30. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/namespace.rb +0 -0
  31. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/node.rb +0 -0
  32. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/output.rb +0 -0
  33. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parent.rb +0 -0
  34. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parseexception.rb +0 -0
  35. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/baseparser.rb +139 -39
  36. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/lightparser.rb +0 -0
  37. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/pullparser.rb +0 -0
  38. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/sax2parser.rb +0 -0
  39. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/streamparser.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/treeparser.rb +0 -0
  41. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/ultralightparser.rb +0 -0
  42. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/parsers/xpathparser.rb +25 -11
  43. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/quickpath.rb +0 -0
  44. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/rexml.rb +37 -0
  45. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/sax2listener.rb +0 -0
  46. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/security.rb +0 -0
  47. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/source.rb +0 -0
  48. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/streamlistener.rb +0 -0
  49. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/text.rb +0 -0
  50. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/undefinednamespaceexception.rb +0 -0
  51. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/validation/relaxng.rb +0 -0
  52. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/validation/validation.rb +0 -0
  53. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/validation/validationexception.rb +0 -0
  54. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xmldecl.rb +0 -0
  55. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xmltokens.rb +0 -0
  56. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xpath.rb +0 -0
  57. data/bundle/ruby/2.7.0/gems/{rexml-3.2.4 → rexml-3.2.5}/lib/rexml/xpath_parser.rb +36 -30
  58. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/History.rdoc +25 -0
  59. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/Manifest.txt +2 -0
  60. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/README.rdoc +0 -0
  61. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/compare/normalize.rb +2 -2
  62. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/debugging.md +190 -0
  63. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/rp_extensions.rb +0 -0
  64. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/rp_stringscanner.rb +0 -0
  65. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby20_parser.rb +2550 -2537
  66. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby20_parser.y +9 -1
  67. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby21_parser.rb +7148 -0
  68. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby21_parser.y +9 -1
  69. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby22_parser.rb +7185 -0
  70. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby22_parser.y +9 -1
  71. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby23_parser.rb +2585 -2561
  72. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby23_parser.y +9 -1
  73. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby24_parser.rb +2622 -2607
  74. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby24_parser.y +9 -1
  75. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby25_parser.rb +2612 -2598
  76. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby25_parser.y +9 -1
  77. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby26_parser.rb +2610 -2594
  78. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby26_parser.y +10 -1
  79. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby27_parser.rb +7358 -0
  80. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby27_parser.y +47 -1
  81. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.rb +7358 -0
  82. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.y +2703 -0
  83. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_lexer.rb +19 -0
  84. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_lexer.rex +1 -1
  85. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_lexer.rex.rb +1 -1
  86. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_parser.rb +2 -0
  87. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_parser.yy +57 -1
  88. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_parser_extras.rb +2 -2
  89. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/tools/munge.rb +2 -2
  90. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/tools/ripper.rb +1 -1
  91. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/History.rdoc +12 -0
  92. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/Manifest.txt +0 -0
  93. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/README.rdoc +0 -0
  94. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/composite_sexp_processor.rb +0 -0
  95. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/pt_testcase.rb +2 -2
  96. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/sexp.rb +0 -0
  97. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/sexp_matcher.rb +0 -0
  98. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/sexp_processor.rb +1 -1
  99. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/strict_sexp.rb +0 -0
  100. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/unique.rb +0 -0
  101. data/lib/brakeman.rb +17 -4
  102. data/lib/brakeman/app_tree.rb +36 -3
  103. data/lib/brakeman/checks/base_check.rb +7 -1
  104. data/lib/brakeman/checks/check_execute.rb +1 -0
  105. data/lib/brakeman/checks/check_mass_assignment.rb +4 -6
  106. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -1
  107. data/lib/brakeman/checks/check_sql.rb +1 -1
  108. data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
  109. data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
  110. data/lib/brakeman/file_parser.rb +19 -18
  111. data/lib/brakeman/options.rb +5 -1
  112. data/lib/brakeman/parsers/template_parser.rb +26 -3
  113. data/lib/brakeman/processors/alias_processor.rb +39 -12
  114. data/lib/brakeman/processors/base_processor.rb +4 -4
  115. data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
  116. data/lib/brakeman/processors/lib/rails3_config_processor.rb +16 -16
  117. data/lib/brakeman/processors/lib/rails4_config_processor.rb +2 -1
  118. data/lib/brakeman/report.rb +8 -0
  119. data/lib/brakeman/report/report_base.rb +0 -2
  120. data/lib/brakeman/report/report_csv.rb +37 -60
  121. data/lib/brakeman/report/report_junit.rb +2 -2
  122. data/lib/brakeman/report/report_sarif.rb +1 -1
  123. data/lib/brakeman/report/report_sonar.rb +38 -0
  124. data/lib/brakeman/report/report_tabs.rb +1 -1
  125. data/lib/brakeman/report/report_text.rb +1 -1
  126. data/lib/brakeman/rescanner.rb +7 -5
  127. data/lib/brakeman/scanner.rb +44 -18
  128. data/lib/brakeman/tracker.rb +6 -0
  129. data/lib/brakeman/tracker/config.rb +73 -0
  130. data/lib/brakeman/util.rb +7 -2
  131. data/lib/brakeman/version.rb +1 -1
  132. data/lib/brakeman/warning.rb +10 -2
  133. data/lib/brakeman/warning_codes.rb +2 -0
  134. metadata +103 -98
  135. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/Gemfile +0 -6
  136. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/element.rb +0 -1269
  137. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/rexml.rb +0 -32
  138. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/rexml.gemspec +0 -84
  139. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/debugging.md +0 -57
  140. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby21_parser.rb +0 -7140
  141. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby22_parser.rb +0 -7160
  142. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/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
@@ -0,0 +1,64 @@
1
+ module Brakeman
2
+ class FileTypeDetector < BaseProcessor
3
+ def initialize
4
+ super(nil)
5
+ reset
6
+ end
7
+
8
+ def detect_type(file)
9
+ reset
10
+ process(file.ast)
11
+
12
+ if @file_type.nil?
13
+ @file_type = guess_from_path(file.path.relative)
14
+ end
15
+
16
+ @file_type || :libs
17
+ end
18
+
19
+ MODEL_CLASSES = [
20
+ :'ActiveRecord::Base',
21
+ :ApplicationRecord
22
+ ]
23
+
24
+ def process_class exp
25
+ name = class_name(exp.class_name)
26
+ parent = class_name(exp.parent_name)
27
+
28
+ if name.match(/Controller$/)
29
+ @file_type = :controllers
30
+ return exp
31
+ elsif MODEL_CLASSES.include? parent
32
+ @file_type = :models
33
+ return exp
34
+ end
35
+
36
+ super
37
+ end
38
+
39
+ def guess_from_path path
40
+ case
41
+ when path.include?('app/models')
42
+ :models
43
+ when path.include?('app/controllers')
44
+ :controllers
45
+ when path.include?('config/initializers')
46
+ :initializers
47
+ when path.include?('lib/')
48
+ :libs
49
+ when path.match?(%r{config/environments/(?!production\.rb)$})
50
+ :skip
51
+ when path.match?(%r{environments/production\.rb$})
52
+ :skip
53
+ when path.match?(%r{application\.rb$})
54
+ :skip
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def reset
61
+ @file_type = nil
62
+ end
63
+ end
64
+ end
@@ -57,6 +57,20 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
57
57
  exp
58
58
  end
59
59
 
60
+ #Look for configuration settings that
61
+ #are just a call like
62
+ #
63
+ # config.load_defaults 5.2
64
+ def process_call exp
65
+ return exp unless @inside_config
66
+
67
+ if exp.target == RAILS_CONFIG and exp.first_arg
68
+ @tracker.config.rails[exp.method] = exp.first_arg
69
+ end
70
+
71
+ exp
72
+ end
73
+
60
74
  #Look for configuration settings
61
75
  def process_attrasgn exp
62
76
  return exp unless @inside_config
@@ -71,22 +85,8 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
71
85
  @tracker.config.rails[attribute] = exp.first_arg
72
86
  end
73
87
  elsif include_rails_config? exp
74
- options = get_rails_config exp
75
- level = @tracker.config.rails
76
- options[0..-2].each do |o|
77
- level[o] ||= {}
78
-
79
- option = level[o]
80
-
81
- if not option.is_a? Hash
82
- Brakeman.debug "[Notice] Skipping config setting: #{options.map(&:to_s).join(".")}"
83
- return exp
84
- end
85
-
86
- level = level[o]
87
- end
88
-
89
- level[options.last] = exp.first_arg
88
+ options_path = get_rails_config exp
89
+ @tracker.config.set_rails_config(exp.first_arg, *options_path)
90
90
  end
91
91
 
92
92
  exp
@@ -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
@@ -45,6 +45,9 @@ class Brakeman::Report
45
45
  Brakeman::Report::JUnit
46
46
  when :to_sarif
47
47
  return self.to_sarif
48
+ when :to_sonar
49
+ require_report 'sonar'
50
+ Brakeman::Report::Sonar
48
51
  else
49
52
  raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
50
53
  end
@@ -69,6 +72,11 @@ class Brakeman::Report
69
72
  generate Brakeman::Report::JSON
70
73
  end
71
74
 
75
+ def to_sonar
76
+ require_report 'sonar'
77
+ generate Brakeman::Report::Sonar
78
+ end
79
+
72
80
  def to_table
73
81
  require_report 'table'
74
82
  generate Brakeman::Report::Table
@@ -11,8 +11,6 @@ class Brakeman::Report::Base
11
11
 
12
12
  attr_reader :tracker, :checks
13
13
 
14
- TEXT_CONFIDENCE = Brakeman::Warning::TEXT_CONFIDENCE
15
-
16
14
  def initialize tracker
17
15
  @app_tree = tracker.app_tree
18
16
  @tracker = tracker
@@ -1,72 +1,49 @@
1
1
  require 'csv'
2
- require "brakeman/report/report_table"
3
2
 
4
- class Brakeman::Report::CSV < Brakeman::Report::Table
3
+ class Brakeman::Report::CSV < Brakeman::Report::Base
5
4
  def generate_report
6
- output = csv_header
7
- output << "\nSUMMARY\n"
8
-
9
- output << table_to_csv(generate_overview) << "\n"
10
-
11
- output << table_to_csv(generate_warning_overview) << "\n"
12
-
13
- #Return output early if only summarizing
14
- if tracker.options[:summary_only]
15
- return output
16
- end
17
-
18
- if tracker.options[:report_routes] or tracker.options[:debug]
19
- output << "CONTROLLERS\n"
20
- output << table_to_csv(generate_controllers) << "\n"
21
- end
22
-
23
- if tracker.options[:debug]
24
- output << "TEMPLATES\n\n"
25
- output << table_to_csv(generate_templates) << "\n"
5
+ headers = [
6
+ "Confidence",
7
+ "Warning Type",
8
+ "File",
9
+ "Line",
10
+ "Message",
11
+ "Code",
12
+ "User Input",
13
+ "Check Name",
14
+ "Warning Code",
15
+ "Fingerprint",
16
+ "Link"
17
+ ]
18
+
19
+ rows = tracker.filtered_warnings.sort_by do |w|
20
+ [w.confidence, w.warning_type, w.file, w.line, w.fingerprint]
21
+ end.map do |warning|
22
+ generate_row(headers, warning)
26
23
  end
27
24
 
28
- res = generate_errors
29
- output << "ERRORS\n" << table_to_csv(res) << "\n" if res
30
-
31
- res = generate_warnings
32
- output << "SECURITY WARNINGS\n" << table_to_csv(res) << "\n" if res
25
+ table = CSV::Table.new(rows)
33
26
 
34
- output << "Controller Warnings\n"
35
- res = generate_controller_warnings
36
- output << table_to_csv(res) << "\n" if res
37
-
38
- output << "Model Warnings\n"
39
- res = generate_model_warnings
40
- output << table_to_csv(res) << "\n" if res
41
-
42
- res = generate_template_warnings
43
- output << "Template Warnings\n"
44
- output << table_to_csv(res) << "\n" if res
45
-
46
- output
27
+ table.to_csv
47
28
  end
48
29
 
49
- #Generate header for CSV output
50
- def csv_header
51
- header = CSV.generate_line(["Application Path", "Report Generation Time", "Checks Performed", "Rails Version"])
52
- header << CSV.generate_line([File.expand_path(tracker.app_path), Time.now.to_s, checks.checks_run.sort.join(", "), rails_version])
53
- "BRAKEMAN REPORT\n\n" + header
30
+ def generate_row headers, warning
31
+ CSV::Row.new headers, warning_row(warning)
54
32
  end
55
33
 
56
- # rely on Terminal::Table to build the structure, extract the data out in CSV format
57
- def table_to_csv table
58
- return "" unless table
59
-
60
- Brakeman.load_brakeman_dependency 'terminal-table'
61
- headings = table.headings
62
- if headings.is_a? Array
63
- headings = headings.first
64
- end
65
-
66
- output = CSV.generate_line(headings.cells.map{|cell| cell.to_s.strip})
67
- table.rows.each do |row|
68
- output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip})
69
- end
70
- output
34
+ def warning_row warning
35
+ [
36
+ warning.confidence_name,
37
+ warning.warning_type,
38
+ warning_file(warning),
39
+ warning.line,
40
+ warning.message,
41
+ warning.code && warning.format_code(false),
42
+ warning.user_input && warning.format_user_input(false),
43
+ warning.check_name,
44
+ warning.warning_code,
45
+ warning.fingerprint,
46
+ warning.link,
47
+ ]
71
48
  end
72
49
  end
@@ -47,7 +47,7 @@ class Brakeman::Report::JUnit < Brakeman::Report::Base
47
47
  warning.add_attribute 'brakeman:file', warning_file(w)
48
48
  warning.add_attribute 'brakeman:line', w.line
49
49
  warning.add_attribute 'brakeman:fingerprint', w.fingerprint
50
- warning.add_attribute 'brakeman:confidence', TEXT_CONFIDENCE[w.confidence]
50
+ warning.add_attribute 'brakeman:confidence', w.confidence_name
51
51
  warning.add_attribute 'brakeman:code', w.format_code
52
52
  warning.add_text w.to_s
53
53
  }
@@ -88,7 +88,7 @@ class Brakeman::Report::JUnit < Brakeman::Report::Base
88
88
  failure.add_attribute 'brakeman:fingerprint', warning.fingerprint
89
89
  failure.add_attribute 'brakeman:file', warning_file(warning)
90
90
  failure.add_attribute 'brakeman:line', warning.line
91
- failure.add_attribute 'brakeman:confidence', TEXT_CONFIDENCE[warning.confidence]
91
+ failure.add_attribute 'brakeman:confidence', warning.confidence_name
92
92
  failure.add_attribute 'brakeman:code', warning.format_code
93
93
  failure.add_text warning.to_s
94
94
  }
@@ -27,7 +27,7 @@ class Brakeman::Report::SARIF < Brakeman::Report::Base
27
27
  def rules
28
28
  @rules ||= unique_warnings_by_warning_code.map do |warning|
29
29
  rule_id = render_id warning
30
- check_name = warning.check.gsub(/^Brakeman::Check/, '')
30
+ check_name = warning.check_name
31
31
  check_description = render_message check_descriptions[check_name]
32
32
  {
33
33
  :id => rule_id,
@@ -0,0 +1,38 @@
1
+ class Brakeman::Report::Sonar < Brakeman::Report::Base
2
+ def generate_report
3
+ report_object = {
4
+ issues: all_warnings.map { |warning| issue_json(warning) }
5
+ }
6
+ return JSON.pretty_generate report_object
7
+ end
8
+
9
+ private
10
+
11
+ def issue_json(warning)
12
+ {
13
+ engineId: "Brakeman",
14
+ ruleId: warning.warning_code,
15
+ type: "VULNERABILITY",
16
+ severity: severity_level_for(warning.confidence),
17
+ primaryLocation: {
18
+ message: warning.message,
19
+ filePath: warning.file.relative,
20
+ textRange: {
21
+ "startLine": warning.line || 1,
22
+ "endLine": warning.line || 1,
23
+ }
24
+ },
25
+ effortMinutes: (4 - warning.confidence) * 15
26
+ }
27
+ end
28
+
29
+ def severity_level_for(confidence)
30
+ if confidence == 0
31
+ "CRITICAL"
32
+ elsif confidence == 1
33
+ "MAJOR"
34
+ else
35
+ "MINOR"
36
+ end
37
+ end
38
+ end
@@ -10,7 +10,7 @@ class Brakeman::Report::Tabs < Brakeman::Report::Table
10
10
  self.send(meth).map do |w|
11
11
  line = w.line || 0
12
12
  w.warning_type.gsub!(/[^\w\s]/, ' ')
13
- "#{(w.file.absolute)}\t#{line}\t#{w.warning_type}\t#{category}\t#{w.format_message}\t#{TEXT_CONFIDENCE[w.confidence]}"
13
+ "#{(w.file.absolute)}\t#{line}\t#{w.warning_type}\t#{category}\t#{w.format_message}\t#{w.confidence_name}"
14
14
  end.join "\n"
15
15
 
16
16
  end.join "\n"
@@ -160,7 +160,7 @@ class Brakeman::Report::Text < Brakeman::Report::Base
160
160
  when :category
161
161
  label('Category', w.warning_type.to_s)
162
162
  when :check
163
- label('Check', w.check.gsub(/^Brakeman::Check/, ''))
163
+ label('Check', w.check_name)
164
164
  when :message
165
165
  label('Message', w.message)
166
166
  when :code
@@ -132,10 +132,11 @@ class Brakeman::Rescanner < Brakeman::Scanner
132
132
  template_name = template_path_to_name(path)
133
133
 
134
134
  tracker.reset_template template_name
135
- fp = Brakeman::FileParser.new(tracker)
135
+ fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
136
136
  template_parser = Brakeman::TemplateParser.new(tracker, fp)
137
137
  template_parser.parse_template path, path.read
138
- process_template fp.file_list[:templates].first
138
+ tracker.add_errors(fp.errors)
139
+ process_template fp.file_list.first
139
140
 
140
141
  @processor.process_template_alias tracker.templates[template_name]
141
142
 
@@ -390,9 +391,10 @@ class Brakeman::Rescanner < Brakeman::Scanner
390
391
 
391
392
  def parse_ruby_files list
392
393
  paths = list.select(&:exists?)
393
- file_parser = Brakeman::FileParser.new(tracker)
394
- file_parser.parse_files paths, :rescan
395
- file_parser.file_list[:rescan]
394
+ file_parser = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
395
+ file_parser.parse_files paths
396
+ tracker.add_errors(file_parser.errors)
397
+ file_parser.file_list
396
398
  end
397
399
  end
398
400
 
@@ -7,6 +7,7 @@ begin
7
7
  require 'brakeman/app_tree'
8
8
  require 'brakeman/file_parser'
9
9
  require 'brakeman/parsers/template_parser'
10
+ require 'brakeman/processors/lib/file_type_detector'
10
11
  rescue LoadError => e
11
12
  $stderr.puts e.message
12
13
  $stderr.puts "Please install the appropriate dependency."
@@ -23,7 +24,10 @@ class Brakeman::Scanner
23
24
  @app_tree = Brakeman::AppTree.from_options(options)
24
25
 
25
26
  if (!@app_tree.root || !@app_tree.exists?("app")) && !options[:force_scan]
26
- raise Brakeman::NoApplication, "Please supply the path to a Rails application (looking in #{@app_tree.root})."
27
+ message = "Please supply the path to a Rails application (looking in #{@app_tree.root}).\n" <<
28
+ " Use `--force` to run a scan anyway."
29
+
30
+ raise Brakeman::NoApplication, message
27
31
  end
28
32
 
29
33
  @processor = processor || Brakeman::Processor.new(@app_tree, options)
@@ -43,6 +47,8 @@ class Brakeman::Scanner
43
47
  process_config
44
48
  Brakeman.notify "Parsing files..."
45
49
  parse_files
50
+ Brakeman.notify "Detecting file types..."
51
+ detect_file_types
46
52
  Brakeman.notify "Processing initializers..."
47
53
  process_initializers
48
54
  Brakeman.notify "Processing libs..."
@@ -65,29 +71,47 @@ class Brakeman::Scanner
65
71
  end
66
72
 
67
73
  def parse_files
68
- fp = Brakeman::FileParser.new tracker
69
-
70
- files = {
71
- :initializers => @app_tree.initializer_paths,
72
- :controllers => @app_tree.controller_paths,
73
- :models => @app_tree.model_paths
74
- }
75
-
76
- unless options[:skip_libs]
77
- files[:libs] = @app_tree.lib_paths
78
- end
74
+ fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
79
75
 
80
- files.each do |name, paths|
81
- fp.parse_files paths, name
82
- end
76
+ fp.parse_files tracker.app_tree.ruby_file_paths
83
77
 
84
78
  template_parser = Brakeman::TemplateParser.new(tracker, fp)
85
79
 
86
- fp.read_files(@app_tree.template_paths, :templates) do |path, contents|
80
+ fp.read_files(@app_tree.template_paths) do |path, contents|
87
81
  template_parser.parse_template path, contents
88
82
  end
89
83
 
90
- @file_list = fp.file_list
84
+ # Collect errors raised during parsing
85
+ tracker.add_errors(fp.errors)
86
+
87
+ @parsed_files = fp.file_list
88
+ end
89
+
90
+ def detect_file_types
91
+ @file_list = {
92
+ controllers: [],
93
+ initializers: [],
94
+ libs: [],
95
+ models: [],
96
+ templates: [],
97
+ }
98
+
99
+ detector = Brakeman::FileTypeDetector.new
100
+
101
+ @parsed_files.each do |file|
102
+ if file.is_a? Brakeman::TemplateParser::TemplateFile
103
+ @file_list[:templates] << file
104
+ else
105
+ type = detector.detect_type(file)
106
+ unless type == :skip
107
+ if @file_list[type].nil?
108
+ raise type.to_s
109
+ else
110
+ @file_list[type] << file
111
+ end
112
+ end
113
+ end
114
+ end
91
115
  end
92
116
 
93
117
  #Process config/environment.rb and config/gems.rb
@@ -115,6 +139,8 @@ class Brakeman::Scanner
115
139
  if @app_tree.exists? ".ruby-version"
116
140
  tracker.config.set_ruby_version @app_tree.file_path(".ruby-version").read
117
141
  end
142
+
143
+ tracker.config.load_rails_defaults
118
144
  end
119
145
 
120
146
  def process_config_file file
@@ -325,7 +351,7 @@ class Brakeman::Scanner
325
351
  end
326
352
 
327
353
  def parse_ruby_file file
328
- fp = Brakeman::FileParser.new(self.tracker)
354
+ fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
329
355
  fp.parse_ruby(file.read, file)
330
356
  end
331
357
  end