brakeman-min 0.5.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/CHANGES +529 -0
  2. data/README.md +74 -28
  3. data/bin/brakeman +60 -266
  4. data/lib/brakeman.rb +422 -0
  5. data/lib/brakeman/app_tree.rb +101 -0
  6. data/lib/brakeman/brakeman.rake +10 -0
  7. data/lib/brakeman/call_index.rb +215 -0
  8. data/lib/brakeman/checks.rb +180 -0
  9. data/lib/brakeman/checks/base_check.rb +538 -0
  10. data/lib/brakeman/checks/check_basic_auth.rb +89 -0
  11. data/lib/brakeman/checks/check_content_tag.rb +162 -0
  12. data/lib/brakeman/checks/check_cross_site_scripting.rb +334 -0
  13. data/lib/{checks → brakeman/checks}/check_default_routes.rb +13 -6
  14. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  15. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  16. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  17. data/lib/brakeman/checks/check_evaluation.rb +33 -0
  18. data/lib/brakeman/checks/check_execute.rb +98 -0
  19. data/lib/brakeman/checks/check_file_access.rb +62 -0
  20. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  21. data/lib/brakeman/checks/check_forgery_setting.rb +54 -0
  22. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  23. data/lib/brakeman/checks/check_json_parsing.rb +102 -0
  24. data/lib/brakeman/checks/check_link_to.rb +132 -0
  25. data/lib/brakeman/checks/check_link_to_href.rb +92 -0
  26. data/lib/{checks → brakeman/checks}/check_mail_to.rb +14 -13
  27. data/lib/brakeman/checks/check_mass_assignment.rb +143 -0
  28. data/lib/brakeman/checks/check_model_attr_accessible.rb +48 -0
  29. data/lib/brakeman/checks/check_model_attributes.rb +118 -0
  30. data/lib/brakeman/checks/check_model_serialize.rb +66 -0
  31. data/lib/{checks → brakeman/checks}/check_nested_attributes.rb +10 -6
  32. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  33. data/lib/brakeman/checks/check_redirect.rb +177 -0
  34. data/lib/brakeman/checks/check_render.rb +62 -0
  35. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  36. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  37. data/lib/brakeman/checks/check_sanitize_methods.rb +54 -0
  38. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  39. data/lib/brakeman/checks/check_select_vulnerability.rb +58 -0
  40. data/lib/brakeman/checks/check_send.rb +35 -0
  41. data/lib/brakeman/checks/check_send_file.rb +19 -0
  42. data/lib/brakeman/checks/check_session_settings.rb +145 -0
  43. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  44. data/lib/brakeman/checks/check_skip_before_filter.rb +62 -0
  45. data/lib/brakeman/checks/check_sql.rb +577 -0
  46. data/lib/brakeman/checks/check_strip_tags.rb +64 -0
  47. data/lib/brakeman/checks/check_symbol_dos.rb +67 -0
  48. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  49. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  50. data/lib/brakeman/checks/check_validation_regex.rb +88 -0
  51. data/lib/brakeman/checks/check_without_protection.rb +64 -0
  52. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  53. data/lib/brakeman/differ.rb +66 -0
  54. data/lib/{format → brakeman/format}/style.css +28 -0
  55. data/lib/brakeman/options.rb +256 -0
  56. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  57. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  58. data/lib/{scanner_erubis.rb → brakeman/parsers/rails3_erubis.rb} +8 -21
  59. data/lib/brakeman/processor.rb +102 -0
  60. data/lib/brakeman/processors/alias_processor.rb +780 -0
  61. data/lib/{processors → brakeman/processors}/base_processor.rb +90 -74
  62. data/lib/brakeman/processors/config_processor.rb +14 -0
  63. data/lib/brakeman/processors/controller_alias_processor.rb +334 -0
  64. data/lib/brakeman/processors/controller_processor.rb +265 -0
  65. data/lib/{processors → brakeman/processors}/erb_template_processor.rb +21 -19
  66. data/lib/brakeman/processors/erubis_template_processor.rb +96 -0
  67. data/lib/brakeman/processors/gem_processor.rb +59 -0
  68. data/lib/{processors → brakeman/processors}/haml_template_processor.rb +26 -21
  69. data/lib/brakeman/processors/lib/find_all_calls.rb +185 -0
  70. data/lib/{processors → brakeman/processors}/lib/find_call.rb +23 -28
  71. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  72. data/lib/brakeman/processors/lib/processor_helper.rb +82 -0
  73. data/lib/{processors/config_processor.rb → brakeman/processors/lib/rails2_config_processor.rb} +32 -35
  74. data/lib/{processors → brakeman/processors}/lib/rails2_route_processor.rb +60 -52
  75. data/lib/brakeman/processors/lib/rails3_config_processor.rb +129 -0
  76. data/lib/brakeman/processors/lib/rails3_route_processor.rb +282 -0
  77. data/lib/{processors → brakeman/processors}/lib/render_helper.rb +54 -20
  78. data/lib/brakeman/processors/lib/route_helper.rb +62 -0
  79. data/lib/{processors → brakeman/processors}/library_processor.rb +24 -17
  80. data/lib/{processors → brakeman/processors}/model_processor.rb +46 -22
  81. data/lib/{processors → brakeman/processors}/output_processor.rb +34 -40
  82. data/lib/brakeman/processors/route_processor.rb +17 -0
  83. data/lib/brakeman/processors/slim_template_processor.rb +113 -0
  84. data/lib/brakeman/processors/template_alias_processor.rb +120 -0
  85. data/lib/{processors → brakeman/processors}/template_processor.rb +10 -7
  86. data/lib/brakeman/report.rb +68 -0
  87. data/lib/brakeman/report/ignore/config.rb +130 -0
  88. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  89. data/lib/brakeman/report/initializers/faster_csv.rb +7 -0
  90. data/lib/brakeman/report/initializers/multi_json.rb +29 -0
  91. data/lib/brakeman/report/renderer.rb +24 -0
  92. data/lib/brakeman/report/report_base.rb +279 -0
  93. data/lib/brakeman/report/report_csv.rb +56 -0
  94. data/lib/brakeman/report/report_hash.rb +22 -0
  95. data/lib/brakeman/report/report_html.rb +203 -0
  96. data/lib/brakeman/report/report_json.rb +46 -0
  97. data/lib/brakeman/report/report_table.rb +109 -0
  98. data/lib/brakeman/report/report_tabs.rb +17 -0
  99. data/lib/brakeman/report/templates/controller_overview.html.erb +18 -0
  100. data/lib/brakeman/report/templates/controller_warnings.html.erb +17 -0
  101. data/lib/brakeman/report/templates/error_overview.html.erb +25 -0
  102. data/lib/brakeman/report/templates/header.html.erb +44 -0
  103. data/lib/brakeman/report/templates/ignored_warnings.html.erb +21 -0
  104. data/lib/brakeman/report/templates/model_warnings.html.erb +17 -0
  105. data/lib/brakeman/report/templates/overview.html.erb +34 -0
  106. data/lib/brakeman/report/templates/security_warnings.html.erb +19 -0
  107. data/lib/brakeman/report/templates/template_overview.html.erb +17 -0
  108. data/lib/brakeman/report/templates/view_warnings.html.erb +30 -0
  109. data/lib/brakeman/report/templates/warning_overview.html.erb +13 -0
  110. data/lib/brakeman/rescanner.rb +446 -0
  111. data/lib/brakeman/scanner.rb +362 -0
  112. data/lib/brakeman/tracker.rb +296 -0
  113. data/lib/brakeman/util.rb +413 -0
  114. data/lib/brakeman/version.rb +3 -0
  115. data/lib/brakeman/warning.rb +217 -0
  116. data/lib/brakeman/warning_codes.rb +68 -0
  117. data/lib/ruby_parser/bm_sexp.rb +562 -0
  118. data/lib/ruby_parser/bm_sexp_processor.rb +230 -0
  119. metadata +152 -66
  120. data/lib/checks.rb +0 -71
  121. data/lib/checks/base_check.rb +0 -357
  122. data/lib/checks/check_cross_site_scripting.rb +0 -336
  123. data/lib/checks/check_evaluation.rb +0 -27
  124. data/lib/checks/check_execute.rb +0 -110
  125. data/lib/checks/check_file_access.rb +0 -46
  126. data/lib/checks/check_forgery_setting.rb +0 -42
  127. data/lib/checks/check_mass_assignment.rb +0 -74
  128. data/lib/checks/check_model_attributes.rb +0 -36
  129. data/lib/checks/check_redirect.rb +0 -98
  130. data/lib/checks/check_render.rb +0 -65
  131. data/lib/checks/check_send_file.rb +0 -15
  132. data/lib/checks/check_session_settings.rb +0 -79
  133. data/lib/checks/check_sql.rb +0 -146
  134. data/lib/checks/check_validation_regex.rb +0 -60
  135. data/lib/processor.rb +0 -86
  136. data/lib/processors/alias_processor.rb +0 -384
  137. data/lib/processors/controller_alias_processor.rb +0 -237
  138. data/lib/processors/controller_processor.rb +0 -202
  139. data/lib/processors/erubis_template_processor.rb +0 -85
  140. data/lib/processors/lib/find_model_call.rb +0 -39
  141. data/lib/processors/lib/processor_helper.rb +0 -36
  142. data/lib/processors/lib/rails3_route_processor.rb +0 -184
  143. data/lib/processors/lib/route_helper.rb +0 -34
  144. data/lib/processors/params_processor.rb +0 -77
  145. data/lib/processors/route_processor.rb +0 -11
  146. data/lib/processors/template_alias_processor.rb +0 -86
  147. data/lib/report.rb +0 -680
  148. data/lib/scanner.rb +0 -227
  149. data/lib/tracker.rb +0 -144
  150. data/lib/util.rb +0 -141
  151. data/lib/version.rb +0 -1
  152. data/lib/warning.rb +0 -99
@@ -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,7 @@
1
+ # Ruby 1.8 compatible
2
+ if CSV.const_defined? :Reader
3
+ require 'fastercsv'
4
+ Object.send(:remove_const, :CSV)
5
+ CSV = FasterCSV
6
+ end
7
+
@@ -0,0 +1,29 @@
1
+ #MultiJson interface changed in 1.3.0, but need
2
+ #to support older MultiJson for Rails 3.1.
3
+ mj_engine = nil
4
+
5
+ if MultiJson.respond_to? :default_adapter
6
+ mj_engine = MultiJson.default_adapter
7
+ else
8
+ mj_engine = MultiJson.default_engine
9
+
10
+ module MultiJson
11
+ def self.dump *args
12
+ encode *args
13
+ end
14
+
15
+ def self.load *args
16
+ decode *args
17
+ end
18
+ end
19
+ end
20
+
21
+ #This is so OkJson will work with symbol values
22
+ if mj_engine == :ok_json
23
+ class Symbol
24
+ def to_json
25
+ self.to_s.inspect
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,24 @@
1
+ require 'erb'
2
+
3
+ class Brakeman::Report
4
+ class Renderer
5
+ def initialize(template_file, hash = {})
6
+ hash[:locals] ||= {}
7
+ singleton = class << self; self end
8
+
9
+ hash[:locals].each do |attribute_name, attribute_value|
10
+ singleton.send(:define_method, attribute_name) { attribute_value }
11
+ end
12
+
13
+ # There are last, so as to make overwriting these using locals impossible.
14
+ singleton.send(:define_method, 'template_file') { template_file }
15
+ singleton.send(:define_method, 'template') {
16
+ File.read(File.expand_path("templates/#{template_file}.html.erb", File.dirname(__FILE__)))
17
+ }
18
+ end
19
+
20
+ def render
21
+ ERB.new(template).result(binding)
22
+ end
23
+ end
24
+ 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