brakeman-lib 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,483 @@
1
+ require 'brakeman/scanner'
2
+ require 'brakeman/util'
3
+ require 'brakeman/differ'
4
+
5
+ #Class for rescanning changed files after an initial scan
6
+ class Brakeman::Rescanner < Brakeman::Scanner
7
+ include Brakeman::Util
8
+ KNOWN_TEMPLATE_EXTENSIONS = Brakeman::TemplateParser::KNOWN_TEMPLATE_EXTENSIONS
9
+ SCAN_ORDER = [:config, :gemfile, :initializer, :lib, :routes, :template,
10
+ :model, :controller]
11
+
12
+ #Create new Rescanner to scan changed files
13
+ def initialize options, processor, changed_files
14
+ super(options, processor)
15
+
16
+ @paths = changed_files.map {|f| @app_tree.expand_path(f) }
17
+ @old_results = tracker.filtered_warnings #Old warnings from previous scan
18
+ @changes = nil #True if files had to be rescanned
19
+ @reindex = Set.new
20
+ end
21
+
22
+ #Runs checks.
23
+ #Will rescan files if they have not already been scanned
24
+ def recheck
25
+ rescan if @changes.nil?
26
+
27
+ tracker.run_checks if @changes
28
+
29
+ Brakeman::RescanReport.new @old_results, tracker
30
+ end
31
+
32
+ #Rescans changed files
33
+ def rescan
34
+ tracker.template_cache.clear
35
+
36
+ paths_by_type = {}
37
+
38
+ SCAN_ORDER.each do |type|
39
+ paths_by_type[type] = []
40
+ end
41
+
42
+ @paths.each do |path|
43
+ type = file_type(path)
44
+ paths_by_type[type] << path unless type == :unknown
45
+ end
46
+
47
+ @changes = false
48
+
49
+ SCAN_ORDER.each do |type|
50
+ paths_by_type[type].each do |path|
51
+ Brakeman.debug "Rescanning #{path} as #{type}"
52
+
53
+ if rescan_file path, type
54
+ @changes = true
55
+ end
56
+ end
57
+ end
58
+
59
+ if @changes and not @reindex.empty?
60
+ tracker.reindex_call_sites @reindex
61
+ end
62
+
63
+ self
64
+ end
65
+
66
+ #Rescans a single file
67
+ def rescan_file path, type = nil
68
+ type ||= file_type path
69
+
70
+ unless @app_tree.path_exists?(path)
71
+ return rescan_deleted_file path, type
72
+ end
73
+
74
+ case type
75
+ when :controller
76
+ rescan_controller path
77
+ when :template
78
+ rescan_template path
79
+ when :model
80
+ rescan_model path
81
+ when :lib
82
+ rescan_lib path
83
+ when :config
84
+ process_config
85
+ when :initializer
86
+ rescan_initializer path
87
+ when :routes
88
+ rescan_routes
89
+ when :gemfile
90
+ if tracker.config.has_gem? :rails_xss and tracker.config.escape_html?
91
+ tracker.config.escape_html = false
92
+ end
93
+
94
+ process_gems
95
+ else
96
+ return false #Nothing to do, file hopefully does not need to be rescanned
97
+ end
98
+
99
+ true
100
+ end
101
+
102
+ def rescan_controller path
103
+ controller = tracker.reset_controller path
104
+ paths = controller.nil? ? [path] : controller.files
105
+ parse_ruby_files(paths).each do |astfile|
106
+ process_controller astfile
107
+ end
108
+
109
+ #Process data flow and template rendering
110
+ #from the controller
111
+ tracker.controllers.each do |name, controller|
112
+ if controller.files.include?(path)
113
+ tracker.templates.each do |template_name, template|
114
+ next unless template.render_path
115
+ if template.render_path.include_controller? name
116
+ tracker.reset_template template_name
117
+ end
118
+ end
119
+
120
+ controller.src.each do |file, src|
121
+ @processor.process_controller_alias controller.name, src, nil, file
122
+ end
123
+ end
124
+ end
125
+
126
+ @reindex << :templates << :controllers
127
+ end
128
+
129
+ def rescan_template path
130
+ return unless path.match KNOWN_TEMPLATE_EXTENSIONS and @app_tree.path_exists?(path)
131
+
132
+ template_name = template_path_to_name(path)
133
+
134
+ tracker.reset_template template_name
135
+ fp = Brakeman::FileParser.new(tracker, @app_tree)
136
+ template_parser = Brakeman::TemplateParser.new(tracker, fp)
137
+ template_parser.parse_template path, @app_tree.read_path(path)
138
+ process_template fp.file_list[:templates].first
139
+
140
+ @processor.process_template_alias tracker.templates[template_name]
141
+
142
+ rescan = Set.new
143
+
144
+ #Search for processed template and process it.
145
+ #Search for rendered versions of template and re-render (if necessary)
146
+ tracker.templates.each do |name, template|
147
+ if template.file == path or template.file.nil?
148
+ next unless template.render_path and template.name.to_sym == template_name.to_sym
149
+
150
+ template.render_path.each do |from|
151
+ case from[:type]
152
+ when :template
153
+ rescan << [:template, from[:name]]
154
+ when :controller
155
+ rescan << [:controller, from[:class], from[:method]]
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ rescan.each do |r|
162
+ if r[0] == :controller
163
+ controller = tracker.controllers[r[1]]
164
+
165
+ controller.src.each do |file, src|
166
+ unless @paths.include? file
167
+ @processor.process_controller_alias controller.name, src, r[2], file
168
+ end
169
+ end
170
+ elsif r[0] == :template
171
+ template = tracker.templates[r[1]]
172
+
173
+ rescan_template template.file
174
+ end
175
+ end
176
+
177
+ @reindex << :templates
178
+ end
179
+
180
+ def rescan_model path
181
+ num_models = tracker.models.length
182
+ model = tracker.reset_model path
183
+ paths = model.nil? ? [path] : model.files
184
+ parse_ruby_files(paths).each do |astfile|
185
+ process_model astfile.path, astfile.ast
186
+ end
187
+
188
+ #Only need to rescan other things if a model is added or removed
189
+ if num_models != tracker.models.length
190
+ process_template_data_flows
191
+ process_controller_data_flows
192
+ @reindex << :templates << :controllers
193
+ end
194
+
195
+ @reindex << :models
196
+ end
197
+
198
+ def rescan_lib path
199
+ lib = tracker.reset_lib path
200
+ paths = lib.nil? ? [path] : lib.files
201
+ parse_ruby_files(paths).each do |astfile|
202
+ process_lib astfile
203
+ end
204
+
205
+ lib = nil
206
+
207
+ tracker.libs.each do |name, library|
208
+ if library.files.include?(path)
209
+ lib = library
210
+ break
211
+ end
212
+ end
213
+
214
+ rescan_mixin lib if lib
215
+ end
216
+
217
+ def rescan_routes
218
+ # Routes affect which controller methods are treated as actions
219
+ # which affects which templates are rendered, so routes, controllers,
220
+ # and templates rendered from controllers must be rescanned
221
+ tracker.reset_routes
222
+ tracker.reset_templates :only_rendered => true
223
+ process_routes
224
+ process_controller_data_flows
225
+ @reindex << :controllers << :templates
226
+ end
227
+
228
+ def rescan_initializer path
229
+ parse_ruby_files([path]).each do |astfile|
230
+ process_initializer astfile
231
+ end
232
+ end
233
+
234
+ #Handle rescanning when a file is deleted
235
+ def rescan_deleted_file path, type
236
+ case type
237
+ when :controller
238
+ rescan_controller path
239
+ when :template
240
+ rescan_deleted_template path
241
+ when :model
242
+ rescan_model path
243
+ when :lib
244
+ rescan_deleted_lib path
245
+ when :initializer
246
+ rescan_deleted_initializer path
247
+ else
248
+ if remove_deleted_file path
249
+ return true
250
+ else
251
+ Brakeman.notify "Ignoring deleted file: #{path}"
252
+ end
253
+ end
254
+
255
+ true
256
+ end
257
+
258
+ def rescan_deleted_template path
259
+ return unless path.match KNOWN_TEMPLATE_EXTENSIONS
260
+
261
+ template_name = template_path_to_name(path)
262
+
263
+ #Remove template
264
+ tracker.reset_template template_name
265
+
266
+ rendered_from_controller = /^#{template_name}\.(.+Controller)#(.+)/
267
+ rendered_from_view = /^#{template_name}\.Template:(.+)/
268
+
269
+ #Remove any rendered versions, or partials rendered from it
270
+ tracker.templates.delete_if do |name, template|
271
+ template.file == path or template.name.to_sym == template_name.to_sym
272
+ end
273
+ end
274
+
275
+ def rescan_deleted_lib path
276
+ deleted_lib = nil
277
+
278
+ tracker.libs.delete_if do |name, lib|
279
+ if lib.files.include?(path)
280
+ deleted_lib = lib
281
+ true
282
+ end
283
+ end
284
+
285
+ rescan_mixin deleted_lib if deleted_lib
286
+ end
287
+
288
+ def rescan_deleted_initializer path
289
+ tracker.initializers.delete Pathname.new(path).basename.to_s
290
+ end
291
+
292
+ #Check controllers, templates, models and libs for data from file
293
+ #and delete it.
294
+ def remove_deleted_file path
295
+ deleted = false
296
+
297
+ [:controllers, :models, :libs].each do |collection|
298
+ tracker.send(collection).delete_if do |name, data|
299
+ if data.files.include?(path)
300
+ deleted = true
301
+ true
302
+ end
303
+ end
304
+ end
305
+
306
+ tracker.templates.delete_if do |name, data|
307
+ if data.file == path
308
+ deleted = true
309
+ true
310
+ end
311
+ end
312
+
313
+ deleted
314
+ end
315
+
316
+ #Guess at what kind of file the path contains
317
+ def file_type path
318
+ case path
319
+ when /\/app\/controllers/
320
+ :controller
321
+ when /\/app\/views/
322
+ :template
323
+ when /\/app\/models/
324
+ :model
325
+ when /\/lib/
326
+ :lib
327
+ when /\/config\/initializers/
328
+ :initializer
329
+ when /config\/routes\.rb/
330
+ :routes
331
+ when /\/config\/.+\.(rb|yml)/
332
+ :config
333
+ when /Gemfile|gems\./
334
+ :gemfile
335
+ else
336
+ :unknown
337
+ end
338
+ end
339
+
340
+ def rescan_mixin lib
341
+ method_names = []
342
+
343
+ lib.each_method do |name, meth|
344
+ method_names << name
345
+ end
346
+
347
+ to_rescan = []
348
+
349
+ #Rescan controllers that mixed in library
350
+ tracker.controllers.each do |name, controller|
351
+ if controller.includes.include? lib.name
352
+ controller.files.each do |path|
353
+ unless @paths.include? path
354
+ to_rescan << path
355
+ end
356
+ end
357
+ end
358
+ end
359
+
360
+ to_rescan.each do |controller|
361
+ tracker.reset_controller controller
362
+ rescan_file controller
363
+ end
364
+
365
+ to_rescan = []
366
+
367
+ #Check if a method from this mixin was used to render a template.
368
+ #This is not precise, because a different controller might have the
369
+ #same method...
370
+ tracker.templates.each do |name, template|
371
+ next unless template.render_path
372
+
373
+ if template.render_path.include_any_method? method_names
374
+ name.to_s.match /^([^.]+)/
375
+
376
+ original = tracker.templates[$1.to_sym]
377
+
378
+ if original
379
+ to_rescan << [name, original.file]
380
+ end
381
+ end
382
+ end
383
+
384
+ to_rescan.each do |template|
385
+ tracker.reset_template template[0]
386
+ rescan_file template[1]
387
+ end
388
+ end
389
+
390
+ def parse_ruby_files list
391
+ paths = list.select { |path| @app_tree.path_exists? path }
392
+ file_parser = Brakeman::FileParser.new(tracker, @app_tree)
393
+ file_parser.parse_files paths, :rescan
394
+ file_parser.file_list[:rescan]
395
+ end
396
+ end
397
+
398
+ #Class to make reporting of rescan results simpler to deal with
399
+ class Brakeman::RescanReport
400
+ include Brakeman::Util
401
+ attr_reader :old_results, :new_results
402
+
403
+ def initialize old_results, tracker
404
+ @tracker = tracker
405
+ @old_results = old_results
406
+ @all_warnings = nil
407
+ @diff = nil
408
+ end
409
+
410
+ #Returns true if any warnings were found (new or old)
411
+ def any_warnings?
412
+ not all_warnings.empty?
413
+ end
414
+
415
+ #Returns an array of all warnings found
416
+ def all_warnings
417
+ @all_warnings ||= @tracker.filtered_warnings
418
+ end
419
+
420
+ #Returns an array of warnings which were in the old report but are not in the
421
+ #new report after rescanning
422
+ def fixed_warnings
423
+ diff[:fixed]
424
+ end
425
+
426
+ #Returns an array of warnings which were in the new report but were not in
427
+ #the old report
428
+ def new_warnings
429
+ diff[:new]
430
+ end
431
+
432
+ #Returns true if there are any new or fixed warnings
433
+ def warnings_changed?
434
+ not (diff[:new].empty? and diff[:fixed].empty?)
435
+ end
436
+
437
+ #Returns a hash of arrays for :new and :fixed warnings
438
+ def diff
439
+ @diff ||= Brakeman::Differ.new(all_warnings, @old_results).diff
440
+ end
441
+
442
+ #Returns an array of warnings which were in the old report and the new report
443
+ def existing_warnings
444
+ @old ||= all_warnings.select do |w|
445
+ not new_warnings.include? w
446
+ end
447
+ end
448
+
449
+ #Output total, fixed, and new warnings
450
+ def to_s(verbose = false)
451
+ Brakeman.load_brakeman_dependency 'terminal-table'
452
+
453
+ if !verbose
454
+ <<-OUTPUT
455
+ Total warnings: #{all_warnings.length}
456
+ Fixed warnings: #{fixed_warnings.length}
457
+ New warnings: #{new_warnings.length}
458
+ OUTPUT
459
+ else
460
+ #Eventually move this to different method, or make default to_s
461
+ out = ""
462
+
463
+ {:fixed => fixed_warnings, :new => new_warnings, :existing => existing_warnings}.each do |warning_type, warnings|
464
+ if warnings.length > 0
465
+ out << "#{warning_type.to_s.titleize} warnings: #{warnings.length}\n"
466
+
467
+ table = Terminal::Table.new(:headings => ["Confidence", "Class", "Method", "Warning Type", "Message"]) do |t|
468
+ warnings.sort_by { |w| w.confidence}.each do |warning|
469
+ w = warning.to_row
470
+
471
+ w["Confidence"] = Brakeman::Report::TEXT_CONFIDENCE[w["Confidence"]]
472
+
473
+ t << [w["Confidence"], w["Class"], w["Method"], w["Warning Type"], w["Message"]]
474
+ end
475
+ end
476
+ out << truncate_table(table.to_s)
477
+ end
478
+ end
479
+
480
+ out
481
+ end
482
+ end
483
+ end