brakeman 1.1.0 → 1.2.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.
- data/bin/brakeman +32 -173
- data/lib/brakeman.rb +47 -25
- data/lib/brakeman/call_index.rb +37 -1
- data/lib/brakeman/checks.rb +17 -0
- data/lib/brakeman/checks/base_check.rb +5 -1
- data/lib/brakeman/checks/check_cross_site_scripting.rb +18 -22
- data/lib/brakeman/checks/check_execute.rb +11 -24
- data/lib/brakeman/checks/check_render.rb +15 -26
- data/lib/brakeman/checks/check_sql.rb +48 -3
- data/lib/brakeman/options.rb +204 -0
- data/lib/brakeman/processor.rb +2 -2
- data/lib/brakeman/processors/controller_alias_processor.rb +9 -1
- data/lib/brakeman/processors/lib/find_all_calls.rb +36 -0
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +1 -0
- data/lib/brakeman/processors/model_processor.rb +1 -1
- data/lib/brakeman/report.rb +36 -122
- data/lib/brakeman/rescanner.rb +247 -0
- data/lib/brakeman/scanner.rb +94 -76
- data/lib/brakeman/tracker.rb +103 -2
- data/lib/brakeman/util.rb +106 -0
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +26 -11
- metadata +5 -3
@@ -65,6 +65,42 @@ class Brakeman::FindAllCalls < Brakeman::BaseProcessor
|
|
65
65
|
exp
|
66
66
|
end
|
67
67
|
|
68
|
+
#Calls to render() are converted to s(:render, ...) but we would
|
69
|
+
#like them in the call cache still for speed
|
70
|
+
def process_render exp
|
71
|
+
process exp[-1] if sexp? exp[-1]
|
72
|
+
|
73
|
+
call = { :target => nil, :method => :render, :call => exp, :nested => false }
|
74
|
+
|
75
|
+
if @current_template
|
76
|
+
call[:location] = [:template, @current_template]
|
77
|
+
else
|
78
|
+
call[:location] = [:class, @current_class, @current_method]
|
79
|
+
end
|
80
|
+
|
81
|
+
@calls << call
|
82
|
+
|
83
|
+
exp
|
84
|
+
end
|
85
|
+
|
86
|
+
#Technically, `` is call to Kernel#`
|
87
|
+
#But we just need them in the call cache for speed
|
88
|
+
def process_dxstr exp
|
89
|
+
process exp[-1] if sexp? exp[-1]
|
90
|
+
|
91
|
+
call = { :target => nil, :method => :`, :call => exp, :nested => false }
|
92
|
+
|
93
|
+
if @current_template
|
94
|
+
call[:location] = [:template, @current_template]
|
95
|
+
else
|
96
|
+
call[:location] = [:class, @current_class, @current_method]
|
97
|
+
end
|
98
|
+
|
99
|
+
@calls << call
|
100
|
+
|
101
|
+
exp
|
102
|
+
end
|
103
|
+
|
68
104
|
#Process an assignment like a call
|
69
105
|
def process_attrasgn exp
|
70
106
|
process_call exp
|
data/lib/brakeman/report.rb
CHANGED
@@ -36,7 +36,7 @@ class Brakeman::Report
|
|
36
36
|
end
|
37
37
|
|
38
38
|
#Generate summary table of what was parsed
|
39
|
-
def generate_overview
|
39
|
+
def generate_overview html = false
|
40
40
|
templates = Set.new(@tracker.templates.map {|k,v| v[:name].to_s[/[^.]+/]}).length
|
41
41
|
warnings = checks.warnings.length +
|
42
42
|
checks.controller_warnings.length +
|
@@ -49,7 +49,7 @@ class Brakeman::Report
|
|
49
49
|
unless tracker.options[:output_format] == :to_csv
|
50
50
|
summary = warnings_summary
|
51
51
|
|
52
|
-
if
|
52
|
+
if html
|
53
53
|
warnings = "#{warnings} <span class='high-confidence'>(#{summary[:high_confidence]})</span>"
|
54
54
|
else
|
55
55
|
warnings = "#{warnings} (#{summary[:high_confidence]})"
|
@@ -77,7 +77,7 @@ class Brakeman::Report
|
|
77
77
|
end
|
78
78
|
|
79
79
|
#Generate table of errors or return nil if no errors
|
80
|
-
def generate_errors
|
80
|
+
def generate_errors html = false
|
81
81
|
unless tracker.errors.empty?
|
82
82
|
table = Ruport::Data::Table(["Error", "Location"])
|
83
83
|
|
@@ -85,7 +85,7 @@ class Brakeman::Report
|
|
85
85
|
tracker.errors.each do |w|
|
86
86
|
p w if tracker.options[:debug]
|
87
87
|
|
88
|
-
if
|
88
|
+
if html
|
89
89
|
w[:error] = CGI.escapeHTML w[:error]
|
90
90
|
end
|
91
91
|
|
@@ -99,13 +99,13 @@ class Brakeman::Report
|
|
99
99
|
end
|
100
100
|
|
101
101
|
#Generate table of general security warnings
|
102
|
-
def generate_warnings
|
102
|
+
def generate_warnings html = false
|
103
103
|
table = Ruport::Data::Table(["Confidence", "Class", "Method", "Warning Type", "Message"])
|
104
104
|
checks.warnings.each do |warning|
|
105
105
|
next if warning.confidence > tracker.options[:min_confidence]
|
106
106
|
w = warning.to_row
|
107
107
|
|
108
|
-
if
|
108
|
+
if html
|
109
109
|
w["Confidence"] = HTML_CONFIDENCE[w["Confidence"]]
|
110
110
|
w["Message"] = with_context warning, w["Message"]
|
111
111
|
else
|
@@ -128,14 +128,14 @@ class Brakeman::Report
|
|
128
128
|
end
|
129
129
|
|
130
130
|
#Generate table of template warnings or return nil if no warnings
|
131
|
-
def generate_template_warnings
|
131
|
+
def generate_template_warnings html = false
|
132
132
|
unless checks.template_warnings.empty?
|
133
133
|
table = Ruport::Data::Table(["Confidence", "Template", "Warning Type", "Message"])
|
134
134
|
checks.template_warnings.each do |warning|
|
135
135
|
next if warning.confidence > tracker.options[:min_confidence]
|
136
136
|
w = warning.to_row :template
|
137
137
|
|
138
|
-
if
|
138
|
+
if html
|
139
139
|
w["Confidence"] = HTML_CONFIDENCE[w["Confidence"]]
|
140
140
|
w["Message"] = with_context warning, w["Message"]
|
141
141
|
else
|
@@ -159,14 +159,14 @@ class Brakeman::Report
|
|
159
159
|
end
|
160
160
|
|
161
161
|
#Generate table of model warnings or return nil if no warnings
|
162
|
-
def generate_model_warnings
|
162
|
+
def generate_model_warnings html = false
|
163
163
|
unless checks.model_warnings.empty?
|
164
164
|
table = Ruport::Data::Table(["Confidence", "Model", "Warning Type", "Message"])
|
165
165
|
checks.model_warnings.each do |warning|
|
166
166
|
next if warning.confidence > tracker.options[:min_confidence]
|
167
167
|
w = warning.to_row :model
|
168
168
|
|
169
|
-
if
|
169
|
+
if html
|
170
170
|
w["Confidence"] = HTML_CONFIDENCE[w["Confidence"]]
|
171
171
|
w["Message"] = with_context warning, w["Message"]
|
172
172
|
else
|
@@ -190,14 +190,14 @@ class Brakeman::Report
|
|
190
190
|
end
|
191
191
|
|
192
192
|
#Generate table of controller warnings or nil if no warnings
|
193
|
-
def generate_controller_warnings
|
193
|
+
def generate_controller_warnings html = false
|
194
194
|
unless checks.controller_warnings.empty?
|
195
195
|
table = Ruport::Data::Table(["Confidence", "Controller", "Warning Type", "Message"])
|
196
196
|
checks.controller_warnings.each do |warning|
|
197
197
|
next if warning.confidence > tracker.options[:min_confidence]
|
198
198
|
w = warning.to_row :controller
|
199
199
|
|
200
|
-
if
|
200
|
+
if html
|
201
201
|
w["Confidence"] = HTML_CONFIDENCE[w["Confidence"]]
|
202
202
|
w["Message"] = with_context warning, w["Message"]
|
203
203
|
else
|
@@ -257,14 +257,14 @@ class Brakeman::Report
|
|
257
257
|
end
|
258
258
|
|
259
259
|
#Generate listings of templates and their output
|
260
|
-
def generate_templates
|
260
|
+
def generate_templates html = false
|
261
261
|
out_processor = Brakeman::OutputProcessor.new
|
262
262
|
table = Ruport::Data::Table(["Name", "Output"])
|
263
263
|
tracker.templates.each do |name, template|
|
264
264
|
unless template[:outputs].empty?
|
265
265
|
template[:outputs].each do |out|
|
266
266
|
out = out_processor.format out
|
267
|
-
out = CGI.escapeHTML(out) if
|
267
|
+
out = CGI.escapeHTML(out) if html
|
268
268
|
table << { "Name" => name,
|
269
269
|
"Output" => out.gsub("\n", ";").gsub(/\s+/, " ") }
|
270
270
|
end
|
@@ -277,9 +277,14 @@ class Brakeman::Report
|
|
277
277
|
def to_html
|
278
278
|
out = html_header <<
|
279
279
|
"<h2 id='summary'>Summary</h2>" <<
|
280
|
-
generate_overview.to_html << "<br/>" <<
|
280
|
+
generate_overview(true).to_html << "<br/>" <<
|
281
281
|
generate_warning_overview.to_html
|
282
282
|
|
283
|
+
#Return early if only summarizing
|
284
|
+
if tracker.options[:summary_only]
|
285
|
+
return out
|
286
|
+
end
|
287
|
+
|
283
288
|
if tracker.options[:report_routes] or tracker.options[:debug]
|
284
289
|
out << "<h2>Controllers</h2>" <<
|
285
290
|
generate_controllers.to_html
|
@@ -287,24 +292,24 @@ class Brakeman::Report
|
|
287
292
|
|
288
293
|
if tracker.options[:debug]
|
289
294
|
out << "<h2>Templates</h2>" <<
|
290
|
-
generate_templates.to_html
|
295
|
+
generate_templates(true).to_html
|
291
296
|
end
|
292
297
|
|
293
|
-
res = generate_errors
|
298
|
+
res = generate_errors(true)
|
294
299
|
if res
|
295
300
|
out << "<div onClick=\"toggle('errors_table');\"> <h2>Exceptions raised during the analysis (click to see them)</h2 ></div> <div id='errors_table' style='display:none'>" << res.to_html << '</div>'
|
296
301
|
end
|
297
302
|
|
298
|
-
res = generate_warnings
|
303
|
+
res = generate_warnings(true)
|
299
304
|
out << "<h2>Security Warnings</h2>" << res.to_html if res
|
300
305
|
|
301
|
-
res = generate_controller_warnings
|
306
|
+
res = generate_controller_warnings(true)
|
302
307
|
out << res.to_html if res
|
303
308
|
|
304
|
-
res = generate_model_warnings
|
309
|
+
res = generate_model_warnings(true)
|
305
310
|
out << res.to_html if res
|
306
311
|
|
307
|
-
res = generate_template_warnings
|
312
|
+
res = generate_template_warnings(true)
|
308
313
|
out << res.to_html if res
|
309
314
|
|
310
315
|
out << "</body></html>"
|
@@ -317,6 +322,11 @@ class Brakeman::Report
|
|
317
322
|
generate_overview.to_s << "\n" <<
|
318
323
|
generate_warning_overview.to_s << "\n"
|
319
324
|
|
325
|
+
#Return output early if only summarizing
|
326
|
+
if tracker.options[:summary_only]
|
327
|
+
return out
|
328
|
+
end
|
329
|
+
|
320
330
|
if tracker.options[:report_routes] or tracker.options[:debug]
|
321
331
|
out << "+CONTROLLERS+\n" <<
|
322
332
|
generate_controllers.to_s << "\n"
|
@@ -352,6 +362,11 @@ class Brakeman::Report
|
|
352
362
|
generate_overview.to_csv << "\n" <<
|
353
363
|
generate_warning_overview.to_csv << "\n"
|
354
364
|
|
365
|
+
#Return output early if only summarizing
|
366
|
+
if tracker.options[:summary_only]
|
367
|
+
return out
|
368
|
+
end
|
369
|
+
|
355
370
|
if tracker.options[:report_routes] or tracker.options[:debug]
|
356
371
|
out << "CONTROLLERS\n" <<
|
357
372
|
generate_controllers.to_csv << "\n"
|
@@ -483,107 +498,6 @@ class Brakeman::Report
|
|
483
498
|
@warnings_summary = summary
|
484
499
|
end
|
485
500
|
|
486
|
-
#Return file name related to given warning. Uses +warning.file+ if it exists
|
487
|
-
def file_for warning
|
488
|
-
if warning.file
|
489
|
-
File.expand_path warning.file, tracker.options[:app_path]
|
490
|
-
else
|
491
|
-
case warning.warning_set
|
492
|
-
when :controller
|
493
|
-
file_by_name warning.controller, :controller
|
494
|
-
when :template
|
495
|
-
file_by_name warning.template[:name], :template
|
496
|
-
when :model
|
497
|
-
file_by_name warning.model, :model
|
498
|
-
when :warning
|
499
|
-
file_by_name warning.class
|
500
|
-
else
|
501
|
-
nil
|
502
|
-
end
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
#Attempt to determine path to context file based on the reported name
|
507
|
-
#in the warning.
|
508
|
-
#
|
509
|
-
#For example,
|
510
|
-
#
|
511
|
-
# file_by_name FileController #=> "/rails/root/app/controllers/file_controller.rb
|
512
|
-
def file_by_name name, type = nil
|
513
|
-
return nil unless name
|
514
|
-
string_name = name.to_s
|
515
|
-
name = name.to_sym
|
516
|
-
|
517
|
-
unless type
|
518
|
-
if string_name =~ /Controller$/
|
519
|
-
type = :controller
|
520
|
-
elsif camelize(string_name) == string_name
|
521
|
-
type = :model
|
522
|
-
else
|
523
|
-
type = :template
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
|
-
path = tracker.options[:app_path]
|
528
|
-
|
529
|
-
case type
|
530
|
-
when :controller
|
531
|
-
if tracker.controllers[name] and tracker.controllers[name][:file]
|
532
|
-
path = tracker.controllers[name][:file]
|
533
|
-
else
|
534
|
-
path += "/app/controllers/#{underscore(string_name)}.rb"
|
535
|
-
end
|
536
|
-
when :model
|
537
|
-
if tracker.models[name] and tracker.models[name][:file]
|
538
|
-
path = tracker.models[name][:file]
|
539
|
-
else
|
540
|
-
path += "/app/controllers/#{underscore(string_name)}.rb"
|
541
|
-
end
|
542
|
-
when :template
|
543
|
-
if tracker.templates[name] and tracker.templates[name][:file]
|
544
|
-
path = tracker.templates[name][:file]
|
545
|
-
elsif string_name.include? " "
|
546
|
-
name = string_name.split[0].to_sym
|
547
|
-
path = file_for name, :template
|
548
|
-
else
|
549
|
-
path = nil
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
path
|
554
|
-
end
|
555
|
-
|
556
|
-
#Return array of lines surrounding the warning location from the original
|
557
|
-
#file.
|
558
|
-
def context_for warning
|
559
|
-
file = file_for warning
|
560
|
-
context = []
|
561
|
-
return context unless warning.line and file and File.exist? file
|
562
|
-
|
563
|
-
current_line = 0
|
564
|
-
start_line = warning.line - 5
|
565
|
-
end_line = warning.line + 5
|
566
|
-
|
567
|
-
start_line = 1 if start_line < 0
|
568
|
-
|
569
|
-
File.open file do |f|
|
570
|
-
f.each_line do |line|
|
571
|
-
current_line += 1
|
572
|
-
|
573
|
-
next if line.strip == ""
|
574
|
-
|
575
|
-
if current_line > end_line
|
576
|
-
break
|
577
|
-
end
|
578
|
-
|
579
|
-
if current_line >= start_line
|
580
|
-
context << [current_line, line]
|
581
|
-
end
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
context
|
586
|
-
end
|
587
501
|
|
588
502
|
#Generate HTML for warnings, including context show/hidden via Javascript
|
589
503
|
def with_context warning, message
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'brakeman/scanner'
|
2
|
+
|
3
|
+
#Class for rescanning changed files after an initial scan
|
4
|
+
class Brakeman::Rescanner < Brakeman::Scanner
|
5
|
+
|
6
|
+
SCAN_ORDER = [:config, :gemfile, :initializer, :lib, :routes, :template,
|
7
|
+
:model, :controller]
|
8
|
+
|
9
|
+
#Create new Rescanner to scan changed files
|
10
|
+
def initialize options, processor, changed_files
|
11
|
+
super(options, processor)
|
12
|
+
|
13
|
+
@paths = changed_files.map {|f| File.expand_path f, tracker.options[:app_path] }
|
14
|
+
@old_results = tracker.checks #Old warnings from previous scan
|
15
|
+
@changes = nil #True if files had to be rescanned
|
16
|
+
@reindex = Set.new
|
17
|
+
end
|
18
|
+
|
19
|
+
#Runs checks.
|
20
|
+
#Will rescan files if they have not already been scanned
|
21
|
+
def recheck
|
22
|
+
rescan if @changes.nil?
|
23
|
+
|
24
|
+
tracker.run_checks if @changes
|
25
|
+
|
26
|
+
Brakeman::RescanReport.new @old_results, tracker.checks
|
27
|
+
end
|
28
|
+
|
29
|
+
#Rescans changed files
|
30
|
+
def rescan
|
31
|
+
tracker.template_cache.clear
|
32
|
+
|
33
|
+
paths_by_type = {}
|
34
|
+
|
35
|
+
SCAN_ORDER.each do |type|
|
36
|
+
paths_by_type[type] = []
|
37
|
+
end
|
38
|
+
|
39
|
+
@paths.each do |path|
|
40
|
+
type = file_type(path)
|
41
|
+
paths_by_type[type] << path unless type == :unknown
|
42
|
+
end
|
43
|
+
|
44
|
+
@changes = false
|
45
|
+
|
46
|
+
SCAN_ORDER.each do |type|
|
47
|
+
paths_by_type[type].each do |path|
|
48
|
+
warn "Rescanning #{path} as #{type}" if tracker.options[:debug]
|
49
|
+
|
50
|
+
if rescan_file path, type
|
51
|
+
@changes = true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
if @changes and not @reindex.empty?
|
57
|
+
tracker.reindex_call_sites @reindex
|
58
|
+
end
|
59
|
+
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
#Rescans a single file
|
64
|
+
def rescan_file path, type = nil
|
65
|
+
type ||= file_type path
|
66
|
+
|
67
|
+
case type
|
68
|
+
when :controller
|
69
|
+
rescan_controller path
|
70
|
+
@reindex << :controllers << :templates
|
71
|
+
when :template
|
72
|
+
rescan_template path
|
73
|
+
@reindex << :templates
|
74
|
+
when :model
|
75
|
+
rescan_model path
|
76
|
+
when :lib
|
77
|
+
process_library path
|
78
|
+
when :config
|
79
|
+
process_config
|
80
|
+
when :initializer
|
81
|
+
process_initializer path
|
82
|
+
when :routes
|
83
|
+
# Routes affect which controller methods are treated as actions
|
84
|
+
# which affects which templates are rendered, so routes, controllers,
|
85
|
+
# and templates rendered from controllers must be rescanned
|
86
|
+
tracker.reset_routes
|
87
|
+
tracker.reset_templates :only_rendered => true
|
88
|
+
process_routes
|
89
|
+
process_controllers
|
90
|
+
@reindex << :controllers << :templates
|
91
|
+
when :gemfile
|
92
|
+
process_gems
|
93
|
+
else
|
94
|
+
return false #Nothing to do, file hopefully does not need to be rescanned
|
95
|
+
end
|
96
|
+
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
def rescan_controller path
|
101
|
+
#Process source
|
102
|
+
process_controller path
|
103
|
+
|
104
|
+
#Process data flow and template rendering
|
105
|
+
#from the controller
|
106
|
+
tracker.controllers.each do |name, controller|
|
107
|
+
if controller[:file] == path
|
108
|
+
tracker.templates.keys.each do |template_name|
|
109
|
+
if template_name.to_s.match /(.+)\.#{name}#/
|
110
|
+
tracker.templates.delete template_name
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
@processor.process_controller_alias controller[:src]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def rescan_template path
|
120
|
+
template_name = template_path_to_name(path)
|
121
|
+
|
122
|
+
tracker.reset_template template_name
|
123
|
+
process_template path
|
124
|
+
|
125
|
+
@processor.process_template_alias tracker.templates[template_name]
|
126
|
+
|
127
|
+
rescan = Set.new
|
128
|
+
|
129
|
+
rendered_from_controller = /^#{template_name}\.(.+Controller)#(.+)/
|
130
|
+
rendered_from_view = /^#{template_name}\.Template:(.+)/
|
131
|
+
|
132
|
+
#Search for processed template and process it.
|
133
|
+
#Search for rendered versions of template and re-render (if necessary)
|
134
|
+
tracker.templates.each do |name, template|
|
135
|
+
if template[:file] == path or template[:file].nil?
|
136
|
+
name = name.to_s
|
137
|
+
|
138
|
+
if name.match(rendered_from_controller)
|
139
|
+
#Rendered from controller, so reprocess controller
|
140
|
+
|
141
|
+
rescan << [:controller, $1.to_sym, $2.to_sym]
|
142
|
+
elsif name.match(rendered_from_view)
|
143
|
+
#Rendered from another template, so reprocess that template
|
144
|
+
|
145
|
+
rescan << [:template, $1.to_sym]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
rescan.each do |r|
|
151
|
+
if r[0] == :controller
|
152
|
+
controller = tracker.controllers[r[1]]
|
153
|
+
|
154
|
+
unless @paths.include? controller[:file]
|
155
|
+
@processor.process_controller_alias controller[:src], r[2]
|
156
|
+
end
|
157
|
+
elsif r[0] == :template
|
158
|
+
template = tracker.templates[r[1]]
|
159
|
+
|
160
|
+
rescan_template template[:file]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def rescan_model path
|
166
|
+
num_models = tracker.models.length
|
167
|
+
tracker.reset_model path
|
168
|
+
process_model path if File.exists? path
|
169
|
+
|
170
|
+
#Only need to rescan other things if a model is added or removed
|
171
|
+
if num_models != tracker.models.length
|
172
|
+
process_templates
|
173
|
+
process_controllers
|
174
|
+
@reindex << :templates << :controllers
|
175
|
+
end
|
176
|
+
|
177
|
+
@reindex << :models
|
178
|
+
end
|
179
|
+
|
180
|
+
#Guess at what kind of file the path contains
|
181
|
+
def file_type path
|
182
|
+
case path
|
183
|
+
when /\/app\/controllers/
|
184
|
+
:controller
|
185
|
+
when /\/app\/views/
|
186
|
+
:template
|
187
|
+
when /\/app\/models/
|
188
|
+
:model
|
189
|
+
when /\/lib/
|
190
|
+
:lib
|
191
|
+
when /\/config\/initializers/
|
192
|
+
:initializer
|
193
|
+
when /config\/routes\.rb/
|
194
|
+
:routes
|
195
|
+
when /\/config/
|
196
|
+
:config
|
197
|
+
when /Gemfile/
|
198
|
+
:gemfile
|
199
|
+
else
|
200
|
+
:unknown
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
#Class to make reporting of rescan results simpler to deal with
|
206
|
+
class Brakeman::RescanReport
|
207
|
+
attr_reader :old_results, :new_results
|
208
|
+
|
209
|
+
def initialize old_results, new_results
|
210
|
+
@old_results = old_results
|
211
|
+
@new_results = new_results
|
212
|
+
@all_warnings = nil
|
213
|
+
@diff = nil
|
214
|
+
end
|
215
|
+
|
216
|
+
#Returns true if any warnings were found (new or old)
|
217
|
+
def any_warnings?
|
218
|
+
not all_warnings.empty?
|
219
|
+
end
|
220
|
+
|
221
|
+
#Returns an array of all warnings found
|
222
|
+
def all_warnings
|
223
|
+
@all_warnings ||= new_results.all_warnings
|
224
|
+
end
|
225
|
+
|
226
|
+
#Returns an array of warnings which were in the old report but are not in the
|
227
|
+
#new report after rescanning
|
228
|
+
def fixed_warnings
|
229
|
+
diff[:fixed]
|
230
|
+
end
|
231
|
+
|
232
|
+
#Returns an array of warnings which were in the new report but were not in
|
233
|
+
#the old report
|
234
|
+
def new_warnings
|
235
|
+
diff[:new]
|
236
|
+
end
|
237
|
+
|
238
|
+
#Returns true if there are any new or fixed warnings
|
239
|
+
def warnings_changed?
|
240
|
+
not (diff[:new].empty? and diff[:fixed].empty?)
|
241
|
+
end
|
242
|
+
|
243
|
+
#Returns a hash of arrays for :new and :fixed warnings
|
244
|
+
def diff
|
245
|
+
@diff ||= @new_results.diff(@old_results)
|
246
|
+
end
|
247
|
+
end
|