brakeman 2.0.0 → 2.1.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/CHANGES +20 -0
- data/README.md +6 -1
- data/bin/brakeman +13 -3
- data/lib/brakeman.rb +64 -7
- data/lib/brakeman/call_index.rb +6 -4
- data/lib/brakeman/checks/check_basic_auth.rb +47 -2
- data/lib/brakeman/checks/check_cross_site_scripting.rb +50 -12
- data/lib/brakeman/checks/check_execute.rb +4 -1
- data/lib/brakeman/checks/check_model_attr_accessible.rb +48 -0
- data/lib/brakeman/checks/check_sql.rb +101 -154
- data/lib/brakeman/options.rb +16 -0
- data/lib/brakeman/parsers/rails2_erubis.rb +2 -0
- data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +2 -0
- data/lib/brakeman/parsers/rails3_erubis.rb +2 -0
- data/lib/brakeman/processors/alias_processor.rb +19 -4
- data/lib/brakeman/processors/controller_alias_processor.rb +2 -3
- data/lib/brakeman/processors/gem_processor.rb +5 -4
- data/lib/brakeman/processors/lib/find_all_calls.rb +43 -16
- data/lib/brakeman/report.rb +39 -640
- data/lib/brakeman/report/ignore/config.rb +130 -0
- data/lib/brakeman/report/ignore/interactive.rb +311 -0
- data/lib/brakeman/report/renderer.rb +2 -0
- data/lib/brakeman/report/report_base.rb +279 -0
- data/lib/brakeman/report/report_csv.rb +56 -0
- data/lib/brakeman/report/report_hash.rb +22 -0
- data/lib/brakeman/report/report_html.rb +203 -0
- data/lib/brakeman/report/report_json.rb +46 -0
- data/lib/brakeman/report/report_table.rb +109 -0
- data/lib/brakeman/report/report_tabs.rb +17 -0
- data/lib/brakeman/report/templates/ignored_warnings.html.erb +21 -0
- data/lib/brakeman/report/templates/overview.html.erb +6 -0
- data/lib/brakeman/report/templates/security_warnings.html.erb +1 -1
- data/lib/brakeman/scanner.rb +14 -12
- data/lib/brakeman/tracker.rb +5 -1
- data/lib/brakeman/util.rb +2 -0
- data/lib/brakeman/version.rb +1 -1
- data/lib/ruby_parser/bm_sexp.rb +12 -1
- metadata +179 -90
- checksums.yaml +0 -7
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Brakeman
|
5
|
+
class IgnoreConfig
|
6
|
+
attr_reader :shown_warnings, :ignored_warnings
|
7
|
+
attr_accessor :file
|
8
|
+
|
9
|
+
def initialize file, new_warnings
|
10
|
+
@file = file
|
11
|
+
@new_warnings = new_warnings
|
12
|
+
@already_ignored = []
|
13
|
+
@ignored_fingerprints = Set.new
|
14
|
+
@notes = {}
|
15
|
+
@shown_warnings = @ignored_warnings = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Populate ignored_warnings and shown_warnings based on ignore
|
19
|
+
# configuration
|
20
|
+
def filter_ignored
|
21
|
+
@shown_warnings = []
|
22
|
+
@ignored_warnings = []
|
23
|
+
|
24
|
+
@new_warnings.each do |w|
|
25
|
+
if ignored? w
|
26
|
+
@ignored_warnings << w
|
27
|
+
else
|
28
|
+
@shown_warnings << w
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@shown_warnings
|
33
|
+
end
|
34
|
+
|
35
|
+
# Remove warning from ignored list
|
36
|
+
def unignore warning
|
37
|
+
@ignored_fingerprints.delete warning.fingerprint
|
38
|
+
@already_ignored.reject! do |w|
|
39
|
+
w[:fingerprint] == warning.fingerprint
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Determine if warning should be ignored
|
44
|
+
def ignored? warning
|
45
|
+
@ignored_fingerprints.include? warning.fingerprint
|
46
|
+
end
|
47
|
+
|
48
|
+
def ignore warning
|
49
|
+
@ignored_fingerprints << warning.fingerprint
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add note for warning
|
53
|
+
def add_note warning, note
|
54
|
+
@notes[warning.fingerprint] = note
|
55
|
+
end
|
56
|
+
|
57
|
+
# Retrieve note for warning if it exists. Returns nil if no
|
58
|
+
# note is found
|
59
|
+
def note_for warning
|
60
|
+
if warning.is_a? Warning
|
61
|
+
fingerprint = warning.fingerprint
|
62
|
+
else
|
63
|
+
fingerprint = warning[:fingerprint]
|
64
|
+
end
|
65
|
+
|
66
|
+
@already_ignored.each do |w|
|
67
|
+
if fingerprint == w[:fingerprint]
|
68
|
+
return w[:note]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# Read configuration to file
|
76
|
+
def read_from_file file = @file
|
77
|
+
if File.exist? file
|
78
|
+
@already_ignored = MultiJson.load(File.read(file), :symbolize_keys => true)[:ignored_warnings]
|
79
|
+
else
|
80
|
+
Brakeman.notify "[Notice] Could not find ignore configuration in #{file}"
|
81
|
+
@already_ignored = []
|
82
|
+
end
|
83
|
+
|
84
|
+
@already_ignored.each do |w|
|
85
|
+
@ignored_fingerprints << w[:fingerprint]
|
86
|
+
@notes[w[:fingerprint]] = w[:note]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Save configuration to file
|
91
|
+
def save_to_file warnings, file = @file
|
92
|
+
warnings = warnings.map do |w|
|
93
|
+
if w.is_a? Warning
|
94
|
+
w_hash = w.to_hash
|
95
|
+
w_hash[:file] = w.relative_path
|
96
|
+
w = w_hash
|
97
|
+
end
|
98
|
+
|
99
|
+
w[:note] = @notes[w[:fingerprint]] || ""
|
100
|
+
w
|
101
|
+
end
|
102
|
+
|
103
|
+
output = {
|
104
|
+
:ignored_warnings => warnings,
|
105
|
+
:updated => Time.now.to_s,
|
106
|
+
:brakeman_version => Brakeman::Version
|
107
|
+
}
|
108
|
+
|
109
|
+
File.open file, "w" do |f|
|
110
|
+
f.puts MultiJson.dump(output, :pretty => true)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Save old ignored warnings and newly ignored ones
|
115
|
+
def save_with_old
|
116
|
+
warnings = @ignored_warnings.dup
|
117
|
+
|
118
|
+
# Only add ignored warnings not already ignored
|
119
|
+
@already_ignored.each do |w|
|
120
|
+
fingerprint = w[:fingerprint]
|
121
|
+
|
122
|
+
unless @ignored_warnings.find { |w| w.fingerprint == fingerprint }
|
123
|
+
warnings << w
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
save_to_file warnings
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
Brakeman.load_dependency 'highline'
|
2
|
+
|
3
|
+
module Brakeman
|
4
|
+
class InteractiveIgnorer
|
5
|
+
def initialize file, warnings
|
6
|
+
@ignore_config = Brakeman::IgnoreConfig.new(file, warnings)
|
7
|
+
@new_warnings = warnings
|
8
|
+
@skip_ignored = false
|
9
|
+
@skip_rest = false
|
10
|
+
@ignore_rest = false
|
11
|
+
@quit = false
|
12
|
+
@restart = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
file_menu
|
17
|
+
initial_menu
|
18
|
+
|
19
|
+
@ignore_config.filter_ignored
|
20
|
+
|
21
|
+
unless @quit
|
22
|
+
final_menu
|
23
|
+
end
|
24
|
+
|
25
|
+
if @restart
|
26
|
+
@restart = false
|
27
|
+
start
|
28
|
+
end
|
29
|
+
|
30
|
+
@ignore_config
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def file_menu
|
36
|
+
loop do
|
37
|
+
@ignore_config.file = HighLine.new.ask "Input file: " do |q|
|
38
|
+
if @ignore_config.file and not @ignore_config.file.empty?
|
39
|
+
q.default = @ignore_config.file
|
40
|
+
else
|
41
|
+
q.default = "config/brakeman.ignore"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if File.exist? @ignore_config.file
|
46
|
+
@ignore_config.read_from_file
|
47
|
+
return
|
48
|
+
else
|
49
|
+
if yes_or_no "No such file. Continue with empty config? "
|
50
|
+
return
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initial_menu
|
57
|
+
HighLine.new.choose do |m|
|
58
|
+
m.choice "Inspect all warnings" do
|
59
|
+
@skip_ignored = false
|
60
|
+
process_warnings
|
61
|
+
end
|
62
|
+
|
63
|
+
m.choice "Hide previously ignored warnings" do
|
64
|
+
@skip_ignored = true
|
65
|
+
process_warnings
|
66
|
+
end
|
67
|
+
|
68
|
+
m.choice "Skip - use current ignore configuration" do
|
69
|
+
@quit = true
|
70
|
+
@ignore_config.filter_ignored
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def warning_menu
|
76
|
+
HighLine.new.choose do |m|
|
77
|
+
m.prompt = "Action: "
|
78
|
+
m.layout = :one_line
|
79
|
+
m.list_option = ", "
|
80
|
+
m.select_by = :name
|
81
|
+
|
82
|
+
m.choice "i"
|
83
|
+
m.choice "n"
|
84
|
+
m.choice "k"
|
85
|
+
m.choice "u"
|
86
|
+
m.choice "a"
|
87
|
+
m.choice "s"
|
88
|
+
m.choice "q"
|
89
|
+
m.choice "?" do
|
90
|
+
say <<-HELP
|
91
|
+
i - Add warning to ignore list
|
92
|
+
n - Add warning to ignore list and add note
|
93
|
+
s - Skip this warning (will remain ignored or shown)
|
94
|
+
u - Remove this warning from ignore list
|
95
|
+
a - Ignore this warning and all remaining warnings
|
96
|
+
k - Skip this warning and all remaining warnings
|
97
|
+
q - Quit, do not update ignored warnings
|
98
|
+
? - Display this help
|
99
|
+
HELP
|
100
|
+
|
101
|
+
"?"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def final_menu
|
107
|
+
summarize_changes
|
108
|
+
|
109
|
+
HighLine.new.choose do |m|
|
110
|
+
m.choice "Save changes" do
|
111
|
+
save
|
112
|
+
end
|
113
|
+
|
114
|
+
m.choice "Start over" do
|
115
|
+
start_over
|
116
|
+
end
|
117
|
+
|
118
|
+
m.choice "Quit, do not save changes" do
|
119
|
+
quit
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def save
|
125
|
+
@ignore_config.file = HighLine.new.ask "Output file: " do |q|
|
126
|
+
if @ignore_config.file and not @ignore_config.file.empty?
|
127
|
+
q.default = @ignore_config.file
|
128
|
+
else
|
129
|
+
q.default = "config/brakeman.ignore"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
@ignore_config.save_with_old
|
134
|
+
end
|
135
|
+
|
136
|
+
def start_over
|
137
|
+
reset_config
|
138
|
+
@restart = true
|
139
|
+
end
|
140
|
+
|
141
|
+
def reset_config
|
142
|
+
@ignore_config = Brakeman::IgnoreConfig.new(@ignore_config.file, @new_warnings)
|
143
|
+
end
|
144
|
+
|
145
|
+
def process_warnings
|
146
|
+
@new_warnings.each do |w|
|
147
|
+
if skip_ignored? w or @skip_rest
|
148
|
+
next
|
149
|
+
elsif @ignore_rest
|
150
|
+
ignore w
|
151
|
+
elsif @quit or @restart
|
152
|
+
return
|
153
|
+
else
|
154
|
+
ask_about w
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def ask_about warning
|
160
|
+
pretty_display warning
|
161
|
+
warning_action warning_menu, warning
|
162
|
+
end
|
163
|
+
|
164
|
+
def warning_action action, warning
|
165
|
+
case action
|
166
|
+
when "i"
|
167
|
+
ignore warning
|
168
|
+
when "n"
|
169
|
+
ignore_and_note warning
|
170
|
+
when "s"
|
171
|
+
# do nothing
|
172
|
+
when "u"
|
173
|
+
unignore warning
|
174
|
+
when "a"
|
175
|
+
ignore_rest warning
|
176
|
+
when "k"
|
177
|
+
skip_rest warning
|
178
|
+
when "q"
|
179
|
+
quit
|
180
|
+
when "?"
|
181
|
+
ask_about warning
|
182
|
+
else
|
183
|
+
raise "Unexpected action"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def ignore warning
|
188
|
+
@ignore_config.ignore warning
|
189
|
+
end
|
190
|
+
|
191
|
+
def ignore_and_note warning
|
192
|
+
note = HighLine.new.ask("Note: ")
|
193
|
+
@ignore_config.ignore warning
|
194
|
+
@ignore_config.add_note warning, note
|
195
|
+
end
|
196
|
+
|
197
|
+
def unignore warning
|
198
|
+
@ignore_config.unignore warning
|
199
|
+
end
|
200
|
+
|
201
|
+
def skip_rest warning
|
202
|
+
@skip_rest = true
|
203
|
+
end
|
204
|
+
|
205
|
+
def ignore_rest warning
|
206
|
+
ignore warning
|
207
|
+
@ignore_rest = true
|
208
|
+
end
|
209
|
+
|
210
|
+
def quit
|
211
|
+
reset_config
|
212
|
+
@ignore_config.read_from_file
|
213
|
+
@ignore_config.filter_ignored
|
214
|
+
@quit = true
|
215
|
+
end
|
216
|
+
|
217
|
+
def pretty_display warning
|
218
|
+
say "-" * 20
|
219
|
+
show_confidence warning
|
220
|
+
|
221
|
+
label "Category"
|
222
|
+
say warning.warning_type
|
223
|
+
|
224
|
+
label "Message"
|
225
|
+
say warning.message
|
226
|
+
|
227
|
+
if warning.code
|
228
|
+
label "Code"
|
229
|
+
say warning.format_code
|
230
|
+
end
|
231
|
+
|
232
|
+
if warning.relative_path
|
233
|
+
label "File"
|
234
|
+
say warning.relative_path
|
235
|
+
end
|
236
|
+
|
237
|
+
if warning.line
|
238
|
+
label "Line"
|
239
|
+
say warning.line
|
240
|
+
end
|
241
|
+
|
242
|
+
if already_ignored? warning
|
243
|
+
show_note warning
|
244
|
+
say "Already ignored", :red
|
245
|
+
end
|
246
|
+
|
247
|
+
say ""
|
248
|
+
end
|
249
|
+
|
250
|
+
def already_ignored? warning
|
251
|
+
@ignore_config.ignored? warning
|
252
|
+
end
|
253
|
+
|
254
|
+
def skip_ignored? warning
|
255
|
+
@skip_ignored and already_ignored? warning
|
256
|
+
end
|
257
|
+
|
258
|
+
def summarize_changes
|
259
|
+
say "-" * 20
|
260
|
+
|
261
|
+
say "Ignoring #{@ignore_config.ignored_warnings.length} warnings", :yellow
|
262
|
+
say "Showing #{@ignore_config.shown_warnings.length} warnings", :green
|
263
|
+
end
|
264
|
+
|
265
|
+
def label name
|
266
|
+
say "#{name}: ", :green
|
267
|
+
end
|
268
|
+
|
269
|
+
def show_confidence warning
|
270
|
+
label "Confidence"
|
271
|
+
|
272
|
+
case warning.confidence
|
273
|
+
when 0
|
274
|
+
say "High", :red
|
275
|
+
when 1
|
276
|
+
say "Medium", :yellow
|
277
|
+
when 2
|
278
|
+
say "Weak", :cyan
|
279
|
+
else
|
280
|
+
say "Unknown"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def show_note warning
|
285
|
+
note = @ignore_config.note_for warning
|
286
|
+
|
287
|
+
if note
|
288
|
+
label "Note"
|
289
|
+
say note
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def say text, color = nil
|
294
|
+
text = text.to_s
|
295
|
+
|
296
|
+
if color
|
297
|
+
HighLine.new.say HighLine.new.color(text, color)
|
298
|
+
else
|
299
|
+
HighLine.new.say text
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def yes_or_no message
|
304
|
+
answer = HighLine.new.ask message do |q|
|
305
|
+
q.in = ["y", "n", "yes", "no"]
|
306
|
+
end
|
307
|
+
|
308
|
+
answer.match /^y/i
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'brakeman/util'
|
3
|
+
require 'brakeman/version'
|
4
|
+
require 'brakeman/report/renderer'
|
5
|
+
require 'brakeman/processors/output_processor'
|
6
|
+
|
7
|
+
# Base class for report formats
|
8
|
+
class Brakeman::Report::Base
|
9
|
+
include Brakeman::Util
|
10
|
+
|
11
|
+
attr_reader :tracker, :checks
|
12
|
+
|
13
|
+
TEXT_CONFIDENCE = [ "High", "Medium", "Weak" ]
|
14
|
+
|
15
|
+
def initialize app_tree, tracker
|
16
|
+
@app_tree = app_tree
|
17
|
+
@tracker = tracker
|
18
|
+
@checks = tracker.checks
|
19
|
+
@ignore_filter = tracker.ignored_filter
|
20
|
+
@highlight_user_input = tracker.options[:highlight_user_input]
|
21
|
+
@warnings_summary = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
#Generate table of how many warnings of each warning type were reported
|
25
|
+
def generate_warning_overview
|
26
|
+
types = warnings_summary.keys
|
27
|
+
types.delete :high_confidence
|
28
|
+
values = types.sort.collect{|warning_type| [warning_type, warnings_summary[warning_type]] }
|
29
|
+
locals = {:types => types, :warnings_summary => warnings_summary}
|
30
|
+
|
31
|
+
render_array('warning_overview', ['Warning Type', 'Total'], values, locals)
|
32
|
+
end
|
33
|
+
|
34
|
+
#Generate table of controllers and routes found for those controllers
|
35
|
+
def generate_controllers
|
36
|
+
controller_rows = []
|
37
|
+
|
38
|
+
tracker.controllers.keys.map{|k| k.to_s}.sort.each do |name|
|
39
|
+
name = name.to_sym
|
40
|
+
c = tracker.controllers[name]
|
41
|
+
|
42
|
+
if tracker.routes[:allow_all_actions] or tracker.routes[name] == :allow_all_actions
|
43
|
+
routes = c[:public].keys.map{|e| e.to_s}.sort.join(", ")
|
44
|
+
elsif tracker.routes[name].nil?
|
45
|
+
#No routes defined for this controller.
|
46
|
+
#This can happen when it is only a parent class
|
47
|
+
#for other controllers, for example.
|
48
|
+
routes = "[None]"
|
49
|
+
|
50
|
+
else
|
51
|
+
routes = (Set.new(c[:public].keys) & tracker.routes[name.to_sym]).
|
52
|
+
to_a.
|
53
|
+
map {|e| e.to_s}.
|
54
|
+
sort.
|
55
|
+
join(", ")
|
56
|
+
end
|
57
|
+
|
58
|
+
if routes == ""
|
59
|
+
routes = "[None]"
|
60
|
+
end
|
61
|
+
|
62
|
+
controller_rows << { "Name" => name.to_s,
|
63
|
+
"Parent" => c[:parent].to_s,
|
64
|
+
"Includes" => c[:includes].join(", "),
|
65
|
+
"Routes" => routes
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
cols = ['Name', 'Parent', 'Includes', 'Routes']
|
70
|
+
|
71
|
+
locals = {:controller_rows => controller_rows}
|
72
|
+
values = controller_rows.collect{|row| row.values_at(*cols) }
|
73
|
+
render_array('controller_overview', cols, values, locals)
|
74
|
+
end
|
75
|
+
|
76
|
+
#Generate table of errors or return nil if no errors
|
77
|
+
def generate_errors
|
78
|
+
values = tracker.errors.collect{|error| [error[:error], error[:backtrace][0]]}
|
79
|
+
render_array('error_overview', ['Error', 'Location'], values, {:tracker => tracker})
|
80
|
+
end
|
81
|
+
|
82
|
+
def generate_warnings
|
83
|
+
render_warnings generic_warnings,
|
84
|
+
:warning,
|
85
|
+
'security_warnings',
|
86
|
+
["Confidence", "Class", "Method", "Warning Type", "Message"],
|
87
|
+
'Class'
|
88
|
+
end
|
89
|
+
|
90
|
+
#Generate table of template warnings or return nil if no warnings
|
91
|
+
def generate_template_warnings
|
92
|
+
render_warnings template_warnings,
|
93
|
+
:template,
|
94
|
+
'view_warnings',
|
95
|
+
['Confidence', 'Template', 'Warning Type', 'Message'],
|
96
|
+
'Template'
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
#Generate table of model warnings or return nil if no warnings
|
101
|
+
def generate_model_warnings
|
102
|
+
render_warnings model_warnings,
|
103
|
+
:model,
|
104
|
+
'model_warnings',
|
105
|
+
['Confidence', 'Model', 'Warning Type', 'Message'],
|
106
|
+
'Model'
|
107
|
+
end
|
108
|
+
|
109
|
+
#Generate table of controller warnings or nil if no warnings
|
110
|
+
def generate_controller_warnings
|
111
|
+
render_warnings controller_warnings,
|
112
|
+
:controller,
|
113
|
+
'controller_warnings',
|
114
|
+
['Confidence', 'Controller', 'Warning Type', 'Message'],
|
115
|
+
'Controller'
|
116
|
+
end
|
117
|
+
|
118
|
+
def generate_ignored_warnings
|
119
|
+
render_warnings ignored_warnings,
|
120
|
+
:ignored,
|
121
|
+
'ignored_warnings',
|
122
|
+
['Confidence', 'Warning Type', 'File', 'Message'],
|
123
|
+
'Warning Type'
|
124
|
+
end
|
125
|
+
|
126
|
+
def render_warnings warnings, type, template, cols, sort_col
|
127
|
+
unless warnings.empty?
|
128
|
+
rows = sort(convert_to_rows(warnings, type), sort_col)
|
129
|
+
|
130
|
+
values = rows.collect { |row| row.values_at(*cols) }
|
131
|
+
|
132
|
+
locals = { :warnings => rows }
|
133
|
+
|
134
|
+
render_array(template, cols, values, locals)
|
135
|
+
else
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def convert_to_rows warnings, type = :warning
|
141
|
+
warnings.map do |warning|
|
142
|
+
w = warning.to_row type
|
143
|
+
|
144
|
+
case type
|
145
|
+
when :warning
|
146
|
+
convert_warning w, warning
|
147
|
+
when :template
|
148
|
+
convert_template_warning w, warning
|
149
|
+
when :model
|
150
|
+
convert_model_warning w, warning
|
151
|
+
when :controller
|
152
|
+
convert_controller_warning w, warning
|
153
|
+
when :ignored
|
154
|
+
convert_ignored_warning w, warning
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def convert_warning warning, original
|
160
|
+
warning["Confidence"] = TEXT_CONFIDENCE[warning["Confidence"]]
|
161
|
+
warning["Message"] = text_message original, warning["Message"]
|
162
|
+
warning
|
163
|
+
end
|
164
|
+
|
165
|
+
def convert_template_warning warning, original
|
166
|
+
convert_warning warning, original
|
167
|
+
end
|
168
|
+
|
169
|
+
def convert_model_warning warning, original
|
170
|
+
convert_warning warning, original
|
171
|
+
end
|
172
|
+
|
173
|
+
def convert_controller_warning warning, original
|
174
|
+
convert_warning warning, original
|
175
|
+
end
|
176
|
+
|
177
|
+
def convert_ignored_warning warning, original
|
178
|
+
convert_warning warning, original
|
179
|
+
end
|
180
|
+
|
181
|
+
def sort rows, sort_col
|
182
|
+
stabilizer = 0
|
183
|
+
rows.sort_by do |row|
|
184
|
+
stabilizer += 1
|
185
|
+
|
186
|
+
row.values_at("Confidence", "Warning Type", sort_col) << stabilizer
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
#Return summary of warnings in hash and store in @warnings_summary
|
191
|
+
def warnings_summary
|
192
|
+
return @warnings_summary if @warnings_summary
|
193
|
+
|
194
|
+
summary = Hash.new(0)
|
195
|
+
high_confidence_warnings = 0
|
196
|
+
|
197
|
+
[all_warnings].each do |warnings|
|
198
|
+
warnings.each do |warning|
|
199
|
+
summary[warning.warning_type.to_s] += 1
|
200
|
+
high_confidence_warnings += 1 if warning.confidence == 0
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
summary[:high_confidence] = high_confidence_warnings
|
205
|
+
@warnings_summary = summary
|
206
|
+
end
|
207
|
+
|
208
|
+
def all_warnings
|
209
|
+
if @ignore_filter
|
210
|
+
@all_warnings ||= @ignore_filter.shown_warnings
|
211
|
+
else
|
212
|
+
@all_warnings ||= tracker.checks.all_warnings
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def filter_warnings warnings
|
217
|
+
if @ignore_filter
|
218
|
+
warnings.reject do |w|
|
219
|
+
@ignore_filter.ignored? w
|
220
|
+
end
|
221
|
+
else
|
222
|
+
warnings
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def generic_warnings
|
227
|
+
filter_warnings tracker.checks.warnings
|
228
|
+
end
|
229
|
+
|
230
|
+
def template_warnings
|
231
|
+
filter_warnings tracker.checks.template_warnings
|
232
|
+
end
|
233
|
+
|
234
|
+
def model_warnings
|
235
|
+
filter_warnings tracker.checks.model_warnings
|
236
|
+
end
|
237
|
+
|
238
|
+
def controller_warnings
|
239
|
+
filter_warnings tracker.checks.controller_warnings
|
240
|
+
end
|
241
|
+
|
242
|
+
def ignored_warnings
|
243
|
+
if @ignore_filter
|
244
|
+
@ignore_filter.ignored_warnings
|
245
|
+
else
|
246
|
+
[]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def number_of_templates tracker
|
251
|
+
Set.new(tracker.templates.map {|k,v| v[:name].to_s[/[^.]+/]}).length
|
252
|
+
end
|
253
|
+
|
254
|
+
def warning_file warning, absolute = @tracker.options[:absolute_paths]
|
255
|
+
return nil if warning.file.nil?
|
256
|
+
|
257
|
+
if absolute
|
258
|
+
warning.file
|
259
|
+
else
|
260
|
+
relative_path warning.file
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def rails_version
|
265
|
+
return tracker.config[:rails_version] if tracker.config[:rails_version]
|
266
|
+
return "3.x" if tracker.options[:rails3]
|
267
|
+
"Unknown"
|
268
|
+
end
|
269
|
+
|
270
|
+
#Escape warning message and highlight user input in text output
|
271
|
+
def text_message warning, message
|
272
|
+
if @highlight_user_input and warning.user_input
|
273
|
+
user_input = warning.format_user_input
|
274
|
+
message.gsub(user_input, "+#{user_input}+")
|
275
|
+
else
|
276
|
+
message
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|