brakeman-lib 4.3.1 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +24 -1
  3. data/README.md +35 -6
  4. data/bin/brakeman +2 -0
  5. data/lib/brakeman.rb +5 -3
  6. data/lib/brakeman/app_tree.rb +15 -1
  7. data/lib/brakeman/call_index.rb +7 -4
  8. data/lib/brakeman/checks.rb +16 -8
  9. data/lib/brakeman/checks/base_check.rb +2 -19
  10. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +1 -1
  11. data/lib/brakeman/checks/check_content_tag.rb +4 -4
  12. data/lib/brakeman/checks/check_create_with.rb +1 -1
  13. data/lib/brakeman/checks/check_cross_site_scripting.rb +3 -3
  14. data/lib/brakeman/checks/check_default_routes.rb +3 -3
  15. data/lib/brakeman/checks/check_deserialize.rb +1 -1
  16. data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
  17. data/lib/brakeman/checks/check_digest_dos.rb +4 -4
  18. data/lib/brakeman/checks/check_escape_function.rb +1 -1
  19. data/lib/brakeman/checks/check_execute.rb +5 -4
  20. data/lib/brakeman/checks/check_file_access.rb +13 -3
  21. data/lib/brakeman/checks/check_file_disclosure.rb +1 -1
  22. data/lib/brakeman/checks/check_filter_skipping.rb +1 -1
  23. data/lib/brakeman/checks/check_forgery_setting.rb +3 -3
  24. data/lib/brakeman/checks/check_header_dos.rb +3 -3
  25. data/lib/brakeman/checks/check_i18n_xss.rb +3 -3
  26. data/lib/brakeman/checks/check_jruby_xml.rb +1 -1
  27. data/lib/brakeman/checks/check_json_encoding.rb +3 -3
  28. data/lib/brakeman/checks/check_json_parsing.rb +8 -11
  29. data/lib/brakeman/checks/check_link_to.rb +3 -3
  30. data/lib/brakeman/checks/check_link_to_href.rb +2 -2
  31. data/lib/brakeman/checks/check_mail_to.rb +3 -3
  32. data/lib/brakeman/checks/check_mime_type_dos.rb +1 -1
  33. data/lib/brakeman/checks/check_model_attributes.rb +4 -4
  34. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  35. data/lib/brakeman/checks/check_nested_attributes.rb +3 -3
  36. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +1 -1
  37. data/lib/brakeman/checks/check_number_to_currency.rb +4 -4
  38. data/lib/brakeman/checks/check_quote_table_name.rb +2 -2
  39. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  40. data/lib/brakeman/checks/check_render.rb +2 -2
  41. data/lib/brakeman/checks/check_render_dos.rb +1 -1
  42. data/lib/brakeman/checks/check_render_inline.rb +1 -1
  43. data/lib/brakeman/checks/check_response_splitting.rb +1 -1
  44. data/lib/brakeman/checks/check_route_dos.rb +1 -1
  45. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +1 -1
  46. data/lib/brakeman/checks/check_sanitize_methods.rb +3 -3
  47. data/lib/brakeman/checks/check_secrets.rb +1 -1
  48. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  49. data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
  50. data/lib/brakeman/checks/check_session_manipulation.rb +1 -1
  51. data/lib/brakeman/checks/check_session_settings.rb +1 -1
  52. data/lib/brakeman/checks/check_simple_format.rb +2 -2
  53. data/lib/brakeman/checks/check_single_quotes.rb +14 -10
  54. data/lib/brakeman/checks/check_skip_before_filter.rb +2 -2
  55. data/lib/brakeman/checks/check_sprockets_path_traversal.rb +39 -0
  56. data/lib/brakeman/checks/check_sql.rb +1 -1
  57. data/lib/brakeman/checks/check_sql_cves.rb +2 -2
  58. data/lib/brakeman/checks/check_strip_tags.rb +10 -8
  59. data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
  60. data/lib/brakeman/checks/check_symbol_dos_cve.rb +1 -1
  61. data/lib/brakeman/checks/check_translate_bug.rb +7 -7
  62. data/lib/brakeman/checks/check_unsafe_reflection.rb +1 -1
  63. data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
  64. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  65. data/lib/brakeman/checks/check_weak_hash.rb +18 -19
  66. data/lib/brakeman/checks/check_xml_dos.rb +1 -1
  67. data/lib/brakeman/checks/check_yaml_parsing.rb +1 -1
  68. data/lib/brakeman/format/style.css +8 -0
  69. data/lib/brakeman/messages.rb +220 -0
  70. data/lib/brakeman/options.rb +13 -0
  71. data/lib/brakeman/parsers/template_parser.rb +2 -2
  72. data/lib/brakeman/processors/alias_processor.rb +7 -0
  73. data/lib/brakeman/processors/config_processor.rb +4 -1
  74. data/lib/brakeman/processors/gem_processor.rb +30 -2
  75. data/lib/brakeman/processors/lib/call_conversion_helper.rb +2 -1
  76. data/lib/brakeman/processors/lib/rails3_route_processor.rb +0 -2
  77. data/lib/brakeman/processors/lib/rails4_config_processor.rb +18 -0
  78. data/lib/brakeman/processors/lib/render_helper.rb +5 -0
  79. data/lib/brakeman/processors/lib/render_path.rb +15 -0
  80. data/lib/brakeman/processors/library_processor.rb +1 -1
  81. data/lib/brakeman/report/report_base.rb +17 -161
  82. data/lib/brakeman/report/report_csv.rb +17 -0
  83. data/lib/brakeman/report/report_html.rb +34 -31
  84. data/lib/brakeman/report/report_json.rb +21 -0
  85. data/lib/brakeman/report/report_markdown.rb +13 -6
  86. data/lib/brakeman/report/report_table.rb +157 -0
  87. data/lib/brakeman/report/report_tabs.rb +3 -1
  88. data/lib/brakeman/report/report_text.rb +16 -0
  89. data/lib/brakeman/scanner.rb +5 -1
  90. data/lib/brakeman/tracker/config.rb +1 -1
  91. data/lib/brakeman/util.rb +0 -17
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +9 -4
  94. data/lib/brakeman/warning_codes.rb +1 -0
  95. metadata +13 -10
@@ -13,7 +13,7 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
13
13
  @alias_processor = Brakeman::AliasProcessor.new tracker
14
14
  @current_module = nil
15
15
  @current_class = nil
16
- @intializer_env = nil
16
+ @initializer_env = nil
17
17
  end
18
18
 
19
19
  def process_library src, file_name = nil
@@ -22,18 +22,25 @@ class Brakeman::Report::Base
22
22
  @warnings_summary = nil
23
23
  end
24
24
 
25
- #Generate table of how many warnings of each warning type were reported
26
- def generate_warning_overview
27
- types = warnings_summary.keys
28
- types.delete :high_confidence
29
- values = types.sort.collect{|warning_type| [warning_type, warnings_summary[warning_type]] }
30
- locals = {:types => types, :warnings_summary => warnings_summary}
25
+ #Return summary of warnings in hash and store in @warnings_summary
26
+ def warnings_summary
27
+ return @warnings_summary if @warnings_summary
28
+
29
+ summary = Hash.new(0)
30
+ high_confidence_warnings = 0
31
+
32
+ [all_warnings].each do |warnings|
33
+ warnings.each do |warning|
34
+ summary[warning.warning_type.to_s] += 1
35
+ high_confidence_warnings += 1 if warning.confidence == 0
36
+ end
37
+ end
31
38
 
32
- render_array('warning_overview', ['Warning Type', 'Total'], values, locals)
39
+ summary[:high_confidence] = high_confidence_warnings
40
+ @warnings_summary = summary
33
41
  end
34
42
 
35
- #Generate table of controllers and routes found for those controllers
36
- def generate_controllers
43
+ def controller_information
37
44
  controller_rows = []
38
45
 
39
46
  tracker.controllers.keys.map{|k| k.to_s}.sort.each do |name|
@@ -67,148 +74,7 @@ class Brakeman::Report::Base
67
74
  }
68
75
  end
69
76
 
70
- cols = ['Name', 'Parent', 'Includes', 'Routes']
71
-
72
- locals = {:controller_rows => controller_rows}
73
- values = controller_rows.collect{|row| row.values_at(*cols) }
74
- render_array('controller_overview', cols, values, locals)
75
- end
76
-
77
- #Generate table of errors or return nil if no errors
78
- def generate_errors
79
- values = tracker.errors.collect{|error| [error[:error], error[:backtrace][0]]}
80
- render_array('error_overview', ['Error', 'Location'], values, {:tracker => tracker})
81
- end
82
-
83
- def generate_obsolete
84
- values = tracker.unused_fingerprints.collect{|fingerprint| [fingerprint] }
85
- render_array('obsolete_ignore_entries', ['fingerprint'], values, {:tracker => tracker})
86
- end
87
-
88
- def generate_warnings
89
- render_warnings generic_warnings,
90
- :warning,
91
- 'security_warnings',
92
- ["Confidence", "Class", "Method", "Warning Type", "Message"],
93
- 'Class'
94
- end
95
-
96
- #Generate table of template warnings or return nil if no warnings
97
- def generate_template_warnings
98
- render_warnings template_warnings,
99
- :template,
100
- 'view_warnings',
101
- ['Confidence', 'Template', 'Warning Type', 'Message'],
102
- 'Template'
103
-
104
- end
105
-
106
- #Generate table of model warnings or return nil if no warnings
107
- def generate_model_warnings
108
- render_warnings model_warnings,
109
- :model,
110
- 'model_warnings',
111
- ['Confidence', 'Model', 'Warning Type', 'Message'],
112
- 'Model'
113
- end
114
-
115
- #Generate table of controller warnings or nil if no warnings
116
- def generate_controller_warnings
117
- render_warnings controller_warnings,
118
- :controller,
119
- 'controller_warnings',
120
- ['Confidence', 'Controller', 'Warning Type', 'Message'],
121
- 'Controller'
122
- end
123
-
124
- def generate_ignored_warnings
125
- render_warnings ignored_warnings,
126
- :ignored,
127
- 'ignored_warnings',
128
- ['Confidence', 'Warning Type', 'File', 'Message'],
129
- 'Warning Type'
130
- end
131
-
132
- def render_warnings warnings, type, template, cols, sort_col
133
- unless warnings.empty?
134
- rows = sort(convert_to_rows(warnings, type), sort_col)
135
-
136
- values = rows.collect { |row| row.values_at(*cols) }
137
-
138
- locals = { :warnings => rows }
139
-
140
- render_array(template, cols, values, locals)
141
- else
142
- nil
143
- end
144
- end
145
-
146
- def convert_to_rows warnings, type = :warning
147
- warnings.map do |warning|
148
- w = warning.to_row type
149
-
150
- case type
151
- when :warning
152
- convert_warning w, warning
153
- when :template
154
- convert_template_warning w, warning
155
- when :model
156
- convert_model_warning w, warning
157
- when :controller
158
- convert_controller_warning w, warning
159
- when :ignored
160
- convert_ignored_warning w, warning
161
- end
162
- end
163
- end
164
-
165
- def convert_warning warning, original
166
- warning["Confidence"] = TEXT_CONFIDENCE[warning["Confidence"]]
167
- warning["Message"] = text_message original, warning["Message"]
168
- warning
169
- end
170
-
171
- def convert_template_warning warning, original
172
- convert_warning warning, original
173
- end
174
-
175
- def convert_model_warning warning, original
176
- convert_warning warning, original
177
- end
178
-
179
- def convert_controller_warning warning, original
180
- convert_warning warning, original
181
- end
182
-
183
- def convert_ignored_warning warning, original
184
- convert_warning warning, original
185
- end
186
-
187
- def sort rows, sort_col
188
- stabilizer = 0
189
- rows.sort_by do |row|
190
- stabilizer += 1
191
-
192
- row.values_at("Confidence", "Warning Type", sort_col) << stabilizer
193
- end
194
- end
195
-
196
- #Return summary of warnings in hash and store in @warnings_summary
197
- def warnings_summary
198
- return @warnings_summary if @warnings_summary
199
-
200
- summary = Hash.new(0)
201
- high_confidence_warnings = 0
202
-
203
- [all_warnings].each do |warnings|
204
- warnings.each do |warning|
205
- summary[warning.warning_type.to_s] += 1
206
- high_confidence_warnings += 1 if warning.confidence == 0
207
- end
208
- end
209
-
210
- summary[:high_confidence] = high_confidence_warnings
211
- @warnings_summary = summary
77
+ controller_rows
212
78
  end
213
79
 
214
80
  def all_warnings
@@ -279,14 +145,4 @@ class Brakeman::Report::Base
279
145
  "Unknown"
280
146
  end
281
147
  end
282
-
283
- #Escape warning message and highlight user input in text output
284
- def text_message warning, message
285
- if @highlight_user_input and warning.user_input
286
- user_input = warning.format_user_input
287
- message.gsub(user_input, "+#{user_input}+")
288
- else
289
- message
290
- end
291
- end
292
148
  end
@@ -52,4 +52,21 @@ class Brakeman::Report::CSV < Brakeman::Report::Table
52
52
  header << CSV.generate_line([File.expand_path(tracker.app_path), Time.now.to_s, checks.checks_run.sort.join(", "), rails_version])
53
53
  "BRAKEMAN REPORT\n\n" + header
54
54
  end
55
+
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
71
+ end
55
72
  end
@@ -1,9 +1,10 @@
1
1
  require 'cgi'
2
+ require 'brakeman/report/report_table.rb'
2
3
 
3
- class Brakeman::Report::HTML < Brakeman::Report::Base
4
+ class Brakeman::Report::HTML < Brakeman::Report::Table
4
5
  HTML_CONFIDENCE = [ "<span class='high-confidence'>High</span>",
5
- "<span class='med-confidence'>Medium</span>",
6
- "<span class='weak-confidence'>Weak</span>" ]
6
+ "<span class='med-confidence'>Medium</span>",
7
+ "<span class='weak-confidence'>Weak</span>" ]
7
8
 
8
9
  def initialize *args
9
10
  super
@@ -66,20 +67,18 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
66
67
  end
67
68
 
68
69
  def convert_warning warning, original
69
- warning["Confidence"] = HTML_CONFIDENCE[warning["Confidence"]]
70
+ warning["Confidence"] = HTML_CONFIDENCE[original.confidence]
70
71
  warning["Message"] = with_context original, warning["Message"]
71
72
  warning["Warning Type"] = with_link original, warning["Warning Type"]
72
73
  warning
73
74
  end
74
75
 
75
76
  def with_link warning, message
76
- "<a rel=\"no-referrer\" href=\"#{warning.link}\">#{message}</a>"
77
+ "<a rel=\"noreferrer\" href=\"#{warning.link}\">#{message}</a>"
77
78
  end
78
79
 
79
80
  def convert_template_warning warning, original
80
- warning["Confidence"] = HTML_CONFIDENCE[warning["Confidence"]]
81
- warning["Message"] = with_context original, warning["Message"]
82
- warning["Warning Type"] = with_link original, warning["Warning Type"]
81
+ warning = convert_warning warning, original
83
82
  warning["Called From"] = original.called_from
84
83
  warning["Template Name"] = original.template.name
85
84
  warning
@@ -113,29 +112,16 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
113
112
 
114
113
  #Generate HTML for warnings, including context show/hidden via Javascript
115
114
  def with_context warning, message
115
+ @element_id += 1
116
116
  context = context_for(@app_tree, warning)
117
- full_message = nil
118
-
119
- if tracker.options[:message_limit] and tracker.options[:message_limit] > 0 and message.length > tracker.options[:message_limit]
120
- full_message = html_message(warning, message)
121
- message = message[0..tracker.options[:message_limit]] << "..."
122
- end
123
-
124
117
  message = html_message(warning, message)
125
- return message if context.empty? and not full_message
126
118
 
127
- @element_id += 1
128
119
  code_id = "context#@element_id"
129
120
  message_id = "message#@element_id"
130
121
  full_message_id = "full_message#@element_id"
131
122
  alt = false
132
123
  output = "<div class='warning_message' onClick=\"toggle('#{code_id}');toggle('#{message_id}');toggle('#{full_message_id}')\" >" <<
133
- if full_message
134
- "<span id='#{message_id}' style='display:block' >#{message}</span>" <<
135
- "<span id='#{full_message_id}' style='display:none'>#{full_message}</span>"
136
- else
137
- message
138
- end <<
124
+ message <<
139
125
  "<table id='#{code_id}' class='context' style='display:none'>" <<
140
126
  "<caption>#{CGI.escapeHTML warning_file(warning) || ''}</caption>"
141
127
 
@@ -199,18 +185,35 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
199
185
 
200
186
  #Escape warning message and highlight user input in HTML output
201
187
  def html_message warning, message
202
- message = CGI.escapeHTML(message)
188
+ message = message.to_html
203
189
 
204
190
  if warning.file
205
- github_url = github_url warning.file, warning.line
206
- message.gsub!(/(near line \d+)/, "<a href=\"#{github_url}\" target='_blank'>\\1</a>") if github_url
191
+ if github_url = github_url(warning.file, warning.line)
192
+ message << " <a href=\"#{github_url}\" target='_blank'>near line #{warning.line}</a>"
193
+ elsif warning.line
194
+ message << " near line #{warning.line}"
195
+ end
207
196
  end
208
197
 
209
- if @highlight_user_input and warning.user_input
210
- user_input = CGI.escapeHTML(warning.format_user_input)
211
- message.gsub!(user_input, "<span class=\"user_input\">#{user_input}</span>")
212
- end
198
+ if warning.code
199
+ code = warning.format_with_user_input do |_, user_input|
200
+ "[BMP_UI]#{user_input}[/BMP_UI]"
201
+ end
202
+
203
+ code = "<span class=\"code\">#{CGI.escapeHTML(code).gsub("[BMP_UI]", "<span class=\"user_input\">").gsub("[/BMP_UI]", "</span>")}</span>"
204
+ full_message = "#{message}: #{code}"
213
205
 
214
- message
206
+ if warning.code.mass > 20
207
+ message_id = "message#@element_id"
208
+ full_message_id = "full_message#@element_id"
209
+
210
+ "<span id='#{message_id}' style='display:block'>#{message}: ...</span>" <<
211
+ "<span id='#{full_message_id}' style='display:none'>#{full_message}</span>"
212
+ else
213
+ full_message
214
+ end
215
+ else
216
+ message
217
+ end
215
218
  end
216
219
  end
@@ -38,8 +38,29 @@ class Brakeman::Report::JSON < Brakeman::Report::Base
38
38
  def convert_to_hashes warnings
39
39
  warnings.map do |w|
40
40
  hash = w.to_hash
41
+ hash[:render_path] = convert_render_path hash[:render_path]
41
42
  hash[:file] = warning_file w
43
+
42
44
  hash
43
45
  end.sort_by { |w| "#{w[:fingerprint]}#{w[:line]}" }
44
46
  end
47
+
48
+ def convert_render_path render_path
49
+ return unless render_path and not @tracker.options[:absolute_paths]
50
+
51
+ render_path.map do |r|
52
+ r = r.dup
53
+
54
+ if r[:file]
55
+ r[:file] = relative_path(r[:file])
56
+ end
57
+
58
+ if r[:rendered] and r[:rendered][:file]
59
+ r[:rendered] = r[:rendered].dup
60
+ r[:rendered][:file] = relative_path(r[:rendered][:file])
61
+ end
62
+
63
+ r
64
+ end
65
+ end
45
66
  end
@@ -92,16 +92,23 @@ class Brakeman::Report::Markdown < Brakeman::Report::Table
92
92
 
93
93
  # Escape and code format warning message
94
94
  def markdown_message warning, message
95
+ message = message.to_s
96
+
95
97
  if warning.file
96
98
  github_url = github_url warning.file, warning.line
97
- message.gsub!(/(near line \d+)/, "[\\1](#{github_url})") if github_url
99
+
100
+ if github_url
101
+ message << " near line [#{warning.line}](#{github_url})"
102
+ elsif warning.line
103
+ message << " near line #{warning.line}"
104
+ end
98
105
  end
106
+
99
107
  if warning.code
100
- code = warning.format_code
101
- message.gsub(code, "`#{code.gsub('`','``').gsub(/\A``|``\z/, '` `')}`")
102
- else
103
- message
108
+ code = warning.format_code.gsub('`','``').gsub(/\A``|``\z/, '` `')
109
+ message << ": `#{code}`"
104
110
  end
105
- end
106
111
 
112
+ message
113
+ end
107
114
  end
@@ -62,6 +62,96 @@ class Brakeman::Report::Table < Brakeman::Report::Base
62
62
  end
63
63
  end
64
64
 
65
+ #Generate table of how many warnings of each warning type were reported
66
+ def generate_warning_overview
67
+ types = warnings_summary.keys
68
+ types.delete :high_confidence
69
+ values = types.sort.collect{|warning_type| [warning_type, warnings_summary[warning_type]] }
70
+ locals = {:types => types, :warnings_summary => warnings_summary}
71
+
72
+ render_array('warning_overview', ['Warning Type', 'Total'], values, locals)
73
+ end
74
+
75
+ #Generate table of controllers and routes found for those controllers
76
+ def generate_controllers
77
+ controller_rows = controller_information
78
+
79
+ cols = ['Name', 'Parent', 'Includes', 'Routes']
80
+
81
+ locals = {:controller_rows => controller_rows}
82
+ values = controller_rows.collect{|row| row.values_at(*cols) }
83
+ render_array('controller_overview', cols, values, locals)
84
+ end
85
+
86
+ #Generate table of errors or return nil if no errors
87
+ def generate_errors
88
+ values = tracker.errors.collect{|error| [error[:error], error[:backtrace][0]]}
89
+ render_array('error_overview', ['Error', 'Location'], values, {:tracker => tracker})
90
+ end
91
+
92
+ def generate_obsolete
93
+ values = tracker.unused_fingerprints.collect{|fingerprint| [fingerprint] }
94
+ render_array('obsolete_ignore_entries', ['fingerprint'], values, {:tracker => tracker})
95
+ end
96
+
97
+ def generate_warnings
98
+ render_warnings generic_warnings,
99
+ :warning,
100
+ 'security_warnings',
101
+ ["Confidence", "Class", "Method", "Warning Type", "Message"],
102
+ 'Class'
103
+ end
104
+
105
+ #Generate table of template warnings or return nil if no warnings
106
+ def generate_template_warnings
107
+ render_warnings template_warnings,
108
+ :template,
109
+ 'view_warnings',
110
+ ['Confidence', 'Template', 'Warning Type', 'Message'],
111
+ 'Template'
112
+
113
+ end
114
+
115
+ #Generate table of model warnings or return nil if no warnings
116
+ def generate_model_warnings
117
+ render_warnings model_warnings,
118
+ :model,
119
+ 'model_warnings',
120
+ ['Confidence', 'Model', 'Warning Type', 'Message'],
121
+ 'Model'
122
+ end
123
+
124
+ #Generate table of controller warnings or nil if no warnings
125
+ def generate_controller_warnings
126
+ render_warnings controller_warnings,
127
+ :controller,
128
+ 'controller_warnings',
129
+ ['Confidence', 'Controller', 'Warning Type', 'Message'],
130
+ 'Controller'
131
+ end
132
+
133
+ def generate_ignored_warnings
134
+ render_warnings ignored_warnings,
135
+ :ignored,
136
+ 'ignored_warnings',
137
+ ['Confidence', 'Warning Type', 'File', 'Message'],
138
+ 'Warning Type'
139
+ end
140
+
141
+ def render_warnings warnings, type, template, cols, sort_col
142
+ unless warnings.empty?
143
+ rows = sort(convert_to_rows(warnings, type), sort_col)
144
+
145
+ values = rows.collect { |row| row.values_at(*cols) }
146
+
147
+ locals = { :warnings => rows }
148
+
149
+ render_array(template, cols, values, locals)
150
+ else
151
+ nil
152
+ end
153
+ end
154
+
65
155
  #Generate listings of templates and their output
66
156
  def generate_templates
67
157
  out_processor = Brakeman::OutputProcessor.new
@@ -92,6 +182,44 @@ class Brakeman::Report::Table < Brakeman::Report::Base
92
182
  output
93
183
  end
94
184
 
185
+ def convert_to_rows warnings, type = :warning
186
+ warnings.map do |warning|
187
+ w = warning.to_row type
188
+
189
+ case type
190
+ when :warning
191
+ convert_warning w, warning
192
+ when :ignored
193
+ convert_ignored_warning w, warning
194
+ when :template
195
+ convert_template_warning w, warning
196
+ else
197
+ convert_warning w, warning
198
+ end
199
+ end
200
+ end
201
+
202
+ def convert_warning warning, original
203
+ warning
204
+ end
205
+
206
+ def convert_ignored_warning warning, original
207
+ convert_warning warning, original
208
+ end
209
+
210
+ def convert_template_warning warning, original
211
+ convert_warning warning, original
212
+ end
213
+
214
+ def sort rows, sort_col
215
+ stabilizer = 0
216
+ rows.sort_by do |row|
217
+ stabilizer += 1
218
+
219
+ row.values_at("Confidence", "Warning Type", sort_col) << stabilizer
220
+ end
221
+ end
222
+
95
223
  def render_array template, headings, value_array, locals
96
224
  return if value_array.empty?
97
225
 
@@ -100,6 +228,35 @@ class Brakeman::Report::Table < Brakeman::Report::Base
100
228
  end
101
229
  end
102
230
 
231
+ def convert_warning warning, original
232
+ warning["Message"] = text_message original, warning["Message"]
233
+
234
+ warning
235
+ end
236
+
237
+ #Escape warning message and highlight user input in text output
238
+ def text_message warning, message
239
+ message = message.to_s
240
+
241
+ if warning.line
242
+ message << " near line #{warning.line}"
243
+ end
244
+
245
+ if warning.code
246
+ if @highlight_user_input and warning.user_input
247
+ code = warning.format_with_user_input do |user_input, user_input_string|
248
+ "+#{user_input_string}+"
249
+ end
250
+ else
251
+ code = warning.format_code
252
+ end
253
+
254
+ message << ": #{code}"
255
+ end
256
+
257
+ message
258
+ end
259
+
103
260
  #Generate header for text output
104
261
  def text_header
105
262
  <<-HEADER