brakeman 4.8.0 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +39 -1
  3. data/README.md +12 -4
  4. data/bundle/load.rb +4 -4
  5. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/History.rdoc +35 -0
  6. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/Manifest.txt +2 -0
  7. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/README.rdoc +0 -0
  8. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/compare/normalize.rb +43 -3
  9. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/debugging.md +57 -0
  10. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/rp_extensions.rb +0 -0
  11. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/rp_stringscanner.rb +0 -0
  12. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby20_parser.rb +7062 -0
  13. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby20_parser.y +91 -58
  14. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby21_parser.rb +2603 -2576
  15. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby21_parser.y +91 -58
  16. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby22_parser.rb +7160 -0
  17. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby22_parser.y +91 -58
  18. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby23_parser.rb +7175 -0
  19. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby23_parser.y +91 -58
  20. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby24_parser.rb +7204 -0
  21. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby24_parser.y +91 -58
  22. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2/lib/ruby23_parser.rb → ruby_parser-3.15.0/lib/ruby25_parser.rb} +2867 -2826
  23. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby25_parser.y +91 -58
  24. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2/lib/ruby25_parser.rb → ruby_parser-3.15.0/lib/ruby26_parser.rb} +2432 -2383
  25. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby26_parser.y +91 -58
  26. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2/lib/ruby24_parser.rb → ruby_parser-3.15.0/lib/ruby27_parser.rb} +2432 -2383
  27. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby27_parser.y +2657 -0
  28. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby_lexer.rb +72 -40
  29. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby_lexer.rex +5 -6
  30. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby_lexer.rex.rb +6 -8
  31. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby_parser.rb +2 -0
  32. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby_parser.yy +93 -58
  33. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/lib/ruby_parser_extras.rb +49 -16
  34. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/tools/munge.rb +9 -4
  35. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.0}/tools/ripper.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/History.rdoc +12 -0
  37. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/Manifest.txt +0 -0
  38. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/README.rdoc +0 -0
  39. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/composite_sexp_processor.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/pt_testcase.rb +2 -2
  41. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/sexp.rb +0 -0
  42. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/sexp_matcher.rb +4 -7
  43. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/sexp_processor.rb +1 -1
  44. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/strict_sexp.rb +0 -0
  45. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.14.1 → sexp_processor-4.15.1}/lib/unique.rb +0 -0
  46. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/CHANGES +4 -0
  47. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/Gemfile +12 -13
  48. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/LICENSE +0 -0
  49. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/README.jp.md +0 -0
  50. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/README.md +0 -0
  51. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim.rb +0 -0
  52. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/code_attributes.rb +0 -0
  53. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/command.rb +13 -13
  54. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/controls.rb +0 -0
  55. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/do_inserter.rb +0 -0
  56. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/embedded.rb +0 -0
  57. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/end_inserter.rb +0 -0
  58. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/engine.rb +0 -0
  59. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/erb_converter.rb +0 -0
  60. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/filter.rb +0 -0
  61. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/grammar.rb +0 -0
  62. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/include.rb +0 -0
  63. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/interpolation.rb +0 -0
  64. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/logic_less.rb +0 -0
  65. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/logic_less/context.rb +0 -0
  66. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/logic_less/filter.rb +0 -0
  67. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/parser.rb +1 -1
  68. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/smart.rb +0 -0
  69. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/smart/escaper.rb +0 -0
  70. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/smart/filter.rb +0 -0
  71. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/smart/parser.rb +0 -0
  72. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/splat/builder.rb +0 -0
  73. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/splat/filter.rb +0 -0
  74. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/template.rb +0 -0
  75. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/translator.rb +0 -0
  76. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/lib/slim/version.rb +1 -1
  77. data/bundle/ruby/2.7.0/gems/{slim-4.0.1 → slim-4.1.0}/slim.gemspec +0 -0
  78. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/CHANGELOG.md +4 -0
  79. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/MIT-LICENSE.txt +0 -0
  80. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/README.md +1 -1
  81. data/bundle/ruby/2.7.0/gems/unicode-display_width-1.7.0/data/display_width.marshal.gz +0 -0
  82. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/lib/unicode/display_width.rb +0 -0
  83. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/lib/unicode/display_width/constants.rb +2 -2
  84. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/lib/unicode/display_width/index.rb +0 -0
  85. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/lib/unicode/display_width/no_string_ext.rb +0 -0
  86. data/bundle/ruby/2.7.0/gems/{unicode-display_width-1.6.1 → unicode-display_width-1.7.0}/lib/unicode/display_width/string_ext.rb +0 -0
  87. data/lib/brakeman.rb +20 -0
  88. data/lib/brakeman/checks/base_check.rb +1 -1
  89. data/lib/brakeman/checks/check_basic_auth.rb +2 -0
  90. data/lib/brakeman/checks/check_csrf_token_forgery_cve.rb +28 -0
  91. data/lib/brakeman/checks/check_deserialize.rb +21 -1
  92. data/lib/brakeman/checks/check_json_entity_escape.rb +38 -0
  93. data/lib/brakeman/checks/check_mass_assignment.rb +33 -3
  94. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  95. data/lib/brakeman/checks/check_model_attributes.rb +1 -1
  96. data/lib/brakeman/checks/check_page_caching_cve.rb +37 -0
  97. data/lib/brakeman/checks/check_permit_attributes.rb +1 -1
  98. data/lib/brakeman/checks/check_skip_before_filter.rb +4 -4
  99. data/lib/brakeman/checks/check_sql.rb +1 -1
  100. data/lib/brakeman/checks/check_template_injection.rb +32 -0
  101. data/lib/brakeman/commandline.rb +25 -1
  102. data/lib/brakeman/options.rb +21 -1
  103. data/lib/brakeman/processors/alias_processor.rb +2 -3
  104. data/lib/brakeman/processors/lib/call_conversion_helper.rb +1 -1
  105. data/lib/brakeman/processors/lib/find_all_calls.rb +28 -13
  106. data/lib/brakeman/processors/lib/render_helper.rb +3 -1
  107. data/lib/brakeman/report.rb +7 -0
  108. data/lib/brakeman/report/ignore/config.rb +4 -0
  109. data/lib/brakeman/report/report_sarif.rb +114 -0
  110. data/lib/brakeman/report/report_text.rb +37 -16
  111. data/lib/brakeman/scanner.rb +4 -1
  112. data/lib/brakeman/tracker.rb +3 -1
  113. data/lib/brakeman/tracker/config.rb +6 -4
  114. data/lib/brakeman/tracker/constants.rb +8 -7
  115. data/lib/brakeman/util.rb +16 -0
  116. data/lib/brakeman/version.rb +1 -1
  117. data/lib/brakeman/warning_codes.rb +7 -0
  118. metadata +89 -82
  119. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/debugging.md +0 -18
  120. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/lib/ruby20_parser.rb +0 -7042
  121. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/lib/ruby22_parser.rb +0 -7146
  122. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/lib/ruby26_parser.rb +0 -7195
  123. data/bundle/ruby/2.7.0/gems/unicode-display_width-1.6.1/data/display_width.marshal.gz +0 -0
@@ -67,6 +67,10 @@ module Brakeman::Options
67
67
  options[:ensure_latest] = true
68
68
  end
69
69
 
70
+ opts.on "--ensure-ignore-notes", "Fail when an ignored warnings does not include a note" do
71
+ options[:ensure_ignore_notes] = true
72
+ end
73
+
70
74
  opts.on "-3", "--rails3", "Force Rails 3 mode" do
71
75
  options[:rails3] = true
72
76
  end
@@ -225,7 +229,7 @@ module Brakeman::Options
225
229
 
226
230
  opts.on "-f",
227
231
  "--format TYPE",
228
- [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit],
232
+ [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif],
229
233
  "Specify output formats. Default is text" do |type|
230
234
 
231
235
  type = "s" if type == :text
@@ -301,6 +305,22 @@ module Brakeman::Options
301
305
  options[:github_repo] = repo
302
306
  end
303
307
 
308
+ opts.on "--text-fields field1,field2,etc.", Array, "Specify fields for text report format" do |format|
309
+ valid_options = [:category, :category_id, :check, :code, :confidence, :file, :fingerprint, :line, :link, :message, :render_path]
310
+
311
+ options[:text_fields] = format.map(&:to_sym)
312
+
313
+ if options[:text_fields] == [:all]
314
+ options[:text_fields] = valid_options
315
+ else
316
+ invalid_options = (options[:text_fields] - valid_options)
317
+
318
+ unless invalid_options.empty?
319
+ raise OptionParser::ParseError, "\nInvalid format options: #{invalid_options.inspect}"
320
+ end
321
+ end
322
+ end
323
+
304
324
  opts.on "-w",
305
325
  "--confidence-level LEVEL",
306
326
  ["1", "2", "3"],
@@ -82,7 +82,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
82
82
  def replace exp, int = 0
83
83
  return exp if int > 3
84
84
 
85
-
86
85
  if replacement = env[exp] and not duplicate? replacement
87
86
  replace(replacement.deep_clone(exp.line), int + 1)
88
87
  elsif tracker and replacement = tracker.constant_lookup(exp) and not duplicate? replacement
@@ -731,14 +730,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
731
730
  def array_include_all_literals? exp
732
731
  call? exp and
733
732
  exp.method == :include? and
734
- all_literals? exp.target
733
+ (all_literals? exp.target or dir_glob? exp.target)
735
734
  end
736
735
 
737
736
  def array_detect_all_literals? exp
738
737
  call? exp and
739
738
  [:detect, :find].include? exp.method and
740
739
  exp.first_arg.nil? and
741
- all_literals? exp.target
740
+ (all_literals? exp.target or dir_glob? exp.target)
742
741
  end
743
742
 
744
743
  #Sets @inside_if = true
@@ -10,7 +10,7 @@ module Brakeman
10
10
  def join_arrays lhs, rhs, original_exp = nil
11
11
  if array? lhs and array? rhs
12
12
  result = Sexp.new(:array)
13
- result.line(lhs.line || rhs.line)
13
+ result.line(lhs.line || rhs.line || 1)
14
14
  result.concat lhs[1..-1]
15
15
  result.concat rhs[1..-1]
16
16
  result
@@ -20,6 +20,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
20
20
  @current_template = opts[:template]
21
21
  @current_file = opts[:file]
22
22
  @current_call = nil
23
+ @full_call = nil
23
24
  process exp
24
25
  end
25
26
 
@@ -89,7 +90,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
89
90
  #Calls to render() are converted to s(:render, ...) but we would
90
91
  #like them in the call cache still for speed
91
92
  def process_render exp
92
- process exp.last if sexp? exp.last
93
+ process_all exp
93
94
 
94
95
  add_simple_call :render, exp
95
96
 
@@ -137,7 +138,8 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
137
138
  :call => exp,
138
139
  :nested => false,
139
140
  :location => make_location,
140
- :parent => @current_call }.freeze
141
+ :parent => @current_call,
142
+ :full_call => @full_call }.freeze
141
143
  end
142
144
 
143
145
  #Gets the target of a call as a Symbol
@@ -214,34 +216,47 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
214
216
  #Return info hash for a call Sexp
215
217
  def create_call_hash exp
216
218
  target = get_target exp.target
217
-
218
- if call? target or node_type? target, :dxstr # need to index `` even if target of a call
219
- already_in_target = @in_target
220
- @in_target = true
221
- process target
222
- @in_target = already_in_target
223
-
224
- target = get_target(target, :include_calls)
225
- end
219
+ target_symbol = get_target(target, :include_calls)
226
220
 
227
221
  method = exp.method
228
222
 
229
223
  call_hash = {
230
- :target => target,
224
+ :target => target_symbol,
231
225
  :method => method,
232
226
  :call => exp,
233
227
  :nested => @in_target,
234
228
  :chain => get_chain(exp),
235
229
  :location => make_location,
236
- :parent => @current_call
230
+ :parent => @current_call,
231
+ :full_call => @full_call
237
232
  }
238
233
 
234
+ unless @in_target
235
+ @full_call = call_hash
236
+ end
237
+
238
+ # Process up the call chain
239
+ if call? target or node_type? target, :dxstr # need to index `` even if target of a call
240
+ already_in_target = @in_target
241
+ @in_target = true
242
+ process target
243
+ @in_target = already_in_target
244
+ end
245
+
246
+ # Process call arguments
247
+ # but add the current call as the 'parent'
248
+ # to any calls in the arguments
239
249
  old_parent = @current_call
240
250
  @current_call = call_hash
241
251
 
252
+ # Do not set @full_call when processing arguments
253
+ old_full_call = @full_call
254
+ @full_call = nil
255
+
242
256
  process_call_args exp
243
257
 
244
258
  @current_call = old_parent
259
+ @full_call = old_full_call
245
260
 
246
261
  call_hash
247
262
  end
@@ -98,7 +98,9 @@ module Brakeman::RenderHelper
98
98
 
99
99
  if hash? options[:locals]
100
100
  hash_iterate options[:locals] do |key, value|
101
- template_env[Sexp.new(:call, nil, key.value)] = value
101
+ if symbol? key
102
+ template_env[Sexp.new(:call, nil, key.value)] = value
103
+ end
102
104
  end
103
105
  end
104
106
 
@@ -43,6 +43,8 @@ class Brakeman::Report
43
43
  when :to_junit
44
44
  require_report 'junit'
45
45
  Brakeman::Report::JUnit
46
+ when :to_sarif
47
+ return self.to_sarif
46
48
  else
47
49
  raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
48
50
  end
@@ -85,6 +87,11 @@ class Brakeman::Report
85
87
  alias to_plain to_text
86
88
  alias to_s to_text
87
89
 
90
+ def to_sarif
91
+ require_report 'sarif'
92
+ generate Brakeman::Report::SARIF
93
+ end
94
+
88
95
  def generate reporter
89
96
  reporter.new(@tracker).generate_report
90
97
  end
@@ -94,6 +94,10 @@ module Brakeman
94
94
  end
95
95
  end
96
96
 
97
+ def already_ignored_entries_with_empty_notes
98
+ @already_ignored.select { |i| i if i[:note].strip.empty? }
99
+ end
100
+
97
101
  # Read configuration to file
98
102
  def read_from_file file = @file
99
103
  if File.exist? file
@@ -0,0 +1,114 @@
1
+ class Brakeman::Report::SARIF < Brakeman::Report::Base
2
+ def generate_report
3
+ sarif_log = {
4
+ :version => '2.1.0',
5
+ :$schema => 'https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json',
6
+ :runs => runs,
7
+ }
8
+ JSON.pretty_generate sarif_log
9
+ end
10
+
11
+ def runs
12
+ [
13
+ {
14
+ :tool => {
15
+ :driver => {
16
+ :name => 'Brakeman',
17
+ :informationUri => 'https://brakemanscanner.org',
18
+ :semanticVersion => Brakeman::Version,
19
+ :rules => rules,
20
+ },
21
+ },
22
+ :results => results,
23
+ },
24
+ ]
25
+ end
26
+
27
+ def rules
28
+ @rules ||= unique_warnings_by_warning_code.map do |warning|
29
+ rule_id = render_id warning
30
+ check_name = warning.check.gsub(/^Brakeman::Check/, '')
31
+ check_description = render_message check_descriptions[check_name]
32
+ {
33
+ :id => rule_id,
34
+ :name => "#{check_name}/#{warning.warning_type}",
35
+ :fullDescription => {
36
+ :text => check_description,
37
+ },
38
+ :helpUri => warning.link,
39
+ :help => {
40
+ :text => "More info: #{warning.link}.",
41
+ :markdown => "[More info](#{warning.link}).",
42
+ },
43
+ :properties => {
44
+ :tags => [check_name],
45
+ },
46
+ }
47
+ end
48
+ end
49
+
50
+ def results
51
+ @results ||= all_warnings.map do |warning|
52
+ rule_id = render_id warning
53
+ result_level = infer_level warning
54
+ message_text = render_message warning.message.to_s
55
+ result = {
56
+ :ruleId => rule_id,
57
+ :ruleIndex => rules.index { |r| r[:id] == rule_id },
58
+ :level => result_level,
59
+ :message => {
60
+ :text => message_text,
61
+ },
62
+ :locations => [
63
+ :physicalLocation => {
64
+ :artifactLocation => {
65
+ :uri => warning.file.relative,
66
+ :uriBaseId => '%SRCROOT%',
67
+ },
68
+ :region => {
69
+ :startLine => warning.line.is_a?(Integer) ? warning.line : 1,
70
+ },
71
+ },
72
+ ],
73
+ }
74
+
75
+ result
76
+ end
77
+ end
78
+
79
+ # Returns a hash of all check descriptions, keyed by check namne
80
+ def check_descriptions
81
+ @check_descriptions ||= Brakeman::Checks.checks.map do |check|
82
+ [check.name.gsub(/^Check/, ''), check.description]
83
+ end.to_h
84
+ end
85
+
86
+ # Returns a de-duplicated set of warnings, used to generate rules
87
+ def unique_warnings_by_warning_code
88
+ @unique_warnings_by_warning_code ||= all_warnings.uniq { |w| w.warning_code }
89
+ end
90
+
91
+ def render_id warning
92
+ # Include alpha prefix to provide 'compiler error' appearance
93
+ "BRAKE#{'%04d' % warning.warning_code}" # 46 becomes BRAKE0046, for example
94
+ end
95
+
96
+ def render_message message
97
+ # Ensure message ends with a period
98
+ if message.end_with? "."
99
+ message
100
+ else
101
+ "#{message}."
102
+ end
103
+ end
104
+
105
+ def infer_level warning
106
+ # Infer result level from warning confidence
107
+ @@levels_from_confidence ||= Hash.new('warning').update({
108
+ 0 => 'error', # 0 represents 'high confidence', which we infer as 'error'
109
+ 1 => 'warning', # 1 represents 'medium confidence' which we infer as 'warning'
110
+ 2 => 'note', # 2 represents 'weak, or low, confidence', which we infer as 'note'
111
+ })
112
+ @@levels_from_confidence[warning.confidence]
113
+ end
114
+ end
@@ -145,24 +145,45 @@ class Brakeman::Report::Text < Brakeman::Report::Base
145
145
  end
146
146
 
147
147
  def output_warning w
148
- out = [
149
- label('Confidence', confidence(w.confidence)),
150
- label('Category', w.warning_type.to_s),
151
- label('Check', w.check.gsub(/^Brakeman::Check/, '')),
148
+ text_format = tracker.options[:text_fields] ||
149
+ [:confidence, :category, :check, :message, :code, :file, :line]
150
+
151
+ text_format.map do |option|
152
+ format_line(w, option)
153
+ end.compact
154
+ end
155
+
156
+ def format_line w, option
157
+ case option
158
+ when :confidence
159
+ label('Confidence', confidence(w.confidence))
160
+ when :category
161
+ label('Category', w.warning_type.to_s)
162
+ when :check
163
+ label('Check', w.check.gsub(/^Brakeman::Check/, ''))
164
+ when :message
152
165
  label('Message', w.message)
153
- ]
154
-
155
- if w.code
156
- out << label('Code', format_code(w))
157
- end
158
-
159
- out << label('File', warning_file(w))
160
-
161
- if w.line
162
- out << label('Line', w.line)
166
+ when :code
167
+ if w.code
168
+ label('Code', format_code(w))
169
+ end
170
+ when :file
171
+ label('File', warning_file(w))
172
+ when :line
173
+ if w.line
174
+ label('Line', w.line)
175
+ end
176
+ when :link
177
+ label('Link', w.link)
178
+ when :fingerprint
179
+ label('Fingerprint', w.fingerprint)
180
+ when :category_id
181
+ label('Category ID', w.warning_code)
182
+ when :render_path
183
+ if w.called_from
184
+ label('Render Path', w.called_from.join(" > "))
185
+ end
163
186
  end
164
-
165
- out
166
187
  end
167
188
 
168
189
  def double_space title, values
@@ -94,11 +94,14 @@ class Brakeman::Scanner
94
94
  #
95
95
  #Stores parsed information in tracker.config
96
96
  def process_config
97
+ # Sometimes folks like to put constants in environment.rb
98
+ # so let's always process it even for newer Rails versions
99
+ process_config_file "environment.rb"
100
+
97
101
  if options[:rails3] or options[:rails4] or options[:rails5] or options[:rails6]
98
102
  process_config_file "application.rb"
99
103
  process_config_file "environments/production.rb"
100
104
  else
101
- process_config_file "environment.rb"
102
105
  process_config_file "gems.rb"
103
106
  end
104
107
 
@@ -198,8 +198,10 @@ class Brakeman::Tracker
198
198
  @constants.add name, value, context unless @options[:disable_constant_tracking]
199
199
  end
200
200
 
201
+ # This method does not return all constants at this time,
202
+ # just ones with "simple" values.
201
203
  def constant_lookup name
202
- @constants.get_literal name unless @options[:disable_constant_tracking]
204
+ @constants.get_simple_value name unless @options[:disable_constant_tracking]
203
205
  end
204
206
 
205
207
  def find_class name
@@ -54,7 +54,7 @@ module Brakeman
54
54
  end
55
55
 
56
56
  def gem_version name
57
- extract_version @gems.dig(name, :version)
57
+ extract_version @gems.dig(name.to_sym, :version)
58
58
  end
59
59
 
60
60
  def add_gem name, version, file, line
@@ -67,11 +67,11 @@ module Brakeman
67
67
  end
68
68
 
69
69
  def has_gem? name
70
- !!@gems[name]
70
+ !!@gems[name.to_sym]
71
71
  end
72
72
 
73
73
  def get_gem name
74
- @gems[name]
74
+ @gems[name.to_sym]
75
75
  end
76
76
 
77
77
  def set_rails_version version = nil
@@ -79,7 +79,9 @@ module Brakeman
79
79
  # Only used by Rails2ConfigProcessor right now
80
80
  extract_version(version)
81
81
  else
82
- gem_version(:rails) || gem_version(:railties)
82
+ gem_version(:rails) ||
83
+ gem_version(:railties) ||
84
+ gem_version(:activerecord)
83
85
  end
84
86
 
85
87
  if version
@@ -1,7 +1,10 @@
1
1
  require 'brakeman/processors/output_processor'
2
+ require 'brakeman/util'
2
3
 
3
4
  module Brakeman
4
5
  class Constant
6
+ include Brakeman::Util
7
+
5
8
  attr_reader :name, :name_array, :file, :value, :context
6
9
 
7
10
  def initialize name, value, context = {}
@@ -107,13 +110,11 @@ module Brakeman
107
110
  @constants[base_name] << Constant.new(name, value, context)
108
111
  end
109
112
 
110
- LITERALS = [:lit, :false, :str, :true, :array, :hash]
111
- def literal? exp
112
- exp.is_a? Sexp and LITERALS.include? exp.node_type
113
- end
114
-
115
- def get_literal name
116
- if x = self[name] and literal? x
113
+ # Returns constant values that are not too complicated.
114
+ # Right now that means literal values (string, array, etc.)
115
+ # or calls on Dir.glob(..).whatever.
116
+ def get_simple_value name
117
+ if x = self[name] and (literal? x or dir_glob? x)
117
118
  x
118
119
  else
119
120
  nil