railroader 4.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +1091 -0
  3. data/FEATURES +16 -0
  4. data/README.md +174 -0
  5. data/bin/railroader +8 -0
  6. data/lib/railroader/app_tree.rb +191 -0
  7. data/lib/railroader/call_index.rb +219 -0
  8. data/lib/railroader/checks/base_check.rb +505 -0
  9. data/lib/railroader/checks/check_basic_auth.rb +88 -0
  10. data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
  11. data/lib/railroader/checks/check_content_tag.rb +200 -0
  12. data/lib/railroader/checks/check_create_with.rb +74 -0
  13. data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
  14. data/lib/railroader/checks/check_default_routes.rb +86 -0
  15. data/lib/railroader/checks/check_deserialize.rb +56 -0
  16. data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
  17. data/lib/railroader/checks/check_digest_dos.rb +38 -0
  18. data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
  19. data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
  20. data/lib/railroader/checks/check_escape_function.rb +21 -0
  21. data/lib/railroader/checks/check_evaluation.rb +35 -0
  22. data/lib/railroader/checks/check_execute.rb +189 -0
  23. data/lib/railroader/checks/check_file_access.rb +71 -0
  24. data/lib/railroader/checks/check_file_disclosure.rb +35 -0
  25. data/lib/railroader/checks/check_filter_skipping.rb +31 -0
  26. data/lib/railroader/checks/check_forgery_setting.rb +81 -0
  27. data/lib/railroader/checks/check_header_dos.rb +31 -0
  28. data/lib/railroader/checks/check_i18n_xss.rb +48 -0
  29. data/lib/railroader/checks/check_jruby_xml.rb +36 -0
  30. data/lib/railroader/checks/check_json_encoding.rb +47 -0
  31. data/lib/railroader/checks/check_json_parsing.rb +107 -0
  32. data/lib/railroader/checks/check_link_to.rb +132 -0
  33. data/lib/railroader/checks/check_link_to_href.rb +146 -0
  34. data/lib/railroader/checks/check_mail_to.rb +49 -0
  35. data/lib/railroader/checks/check_mass_assignment.rb +196 -0
  36. data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
  37. data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
  38. data/lib/railroader/checks/check_model_attributes.rb +119 -0
  39. data/lib/railroader/checks/check_model_serialize.rb +67 -0
  40. data/lib/railroader/checks/check_nested_attributes.rb +38 -0
  41. data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
  42. data/lib/railroader/checks/check_number_to_currency.rb +74 -0
  43. data/lib/railroader/checks/check_permit_attributes.rb +43 -0
  44. data/lib/railroader/checks/check_quote_table_name.rb +40 -0
  45. data/lib/railroader/checks/check_redirect.rb +256 -0
  46. data/lib/railroader/checks/check_regex_dos.rb +68 -0
  47. data/lib/railroader/checks/check_render.rb +97 -0
  48. data/lib/railroader/checks/check_render_dos.rb +37 -0
  49. data/lib/railroader/checks/check_render_inline.rb +53 -0
  50. data/lib/railroader/checks/check_response_splitting.rb +21 -0
  51. data/lib/railroader/checks/check_route_dos.rb +42 -0
  52. data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
  53. data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
  54. data/lib/railroader/checks/check_secrets.rb +40 -0
  55. data/lib/railroader/checks/check_select_tag.rb +59 -0
  56. data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
  57. data/lib/railroader/checks/check_send.rb +47 -0
  58. data/lib/railroader/checks/check_send_file.rb +19 -0
  59. data/lib/railroader/checks/check_session_manipulation.rb +35 -0
  60. data/lib/railroader/checks/check_session_settings.rb +176 -0
  61. data/lib/railroader/checks/check_simple_format.rb +58 -0
  62. data/lib/railroader/checks/check_single_quotes.rb +101 -0
  63. data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
  64. data/lib/railroader/checks/check_sql.rb +700 -0
  65. data/lib/railroader/checks/check_sql_cves.rb +106 -0
  66. data/lib/railroader/checks/check_ssl_verify.rb +48 -0
  67. data/lib/railroader/checks/check_strip_tags.rb +89 -0
  68. data/lib/railroader/checks/check_symbol_dos.rb +71 -0
  69. data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
  70. data/lib/railroader/checks/check_translate_bug.rb +45 -0
  71. data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
  72. data/lib/railroader/checks/check_unscoped_find.rb +57 -0
  73. data/lib/railroader/checks/check_validation_regex.rb +116 -0
  74. data/lib/railroader/checks/check_weak_hash.rb +148 -0
  75. data/lib/railroader/checks/check_without_protection.rb +80 -0
  76. data/lib/railroader/checks/check_xml_dos.rb +45 -0
  77. data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
  78. data/lib/railroader/checks.rb +209 -0
  79. data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
  80. data/lib/railroader/commandline.rb +179 -0
  81. data/lib/railroader/differ.rb +66 -0
  82. data/lib/railroader/file_parser.rb +54 -0
  83. data/lib/railroader/format/style.css +133 -0
  84. data/lib/railroader/options.rb +339 -0
  85. data/lib/railroader/parsers/rails2_erubis.rb +6 -0
  86. data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
  87. data/lib/railroader/parsers/rails3_erubis.rb +81 -0
  88. data/lib/railroader/parsers/template_parser.rb +108 -0
  89. data/lib/railroader/processor.rb +102 -0
  90. data/lib/railroader/processors/alias_processor.rb +1229 -0
  91. data/lib/railroader/processors/base_processor.rb +295 -0
  92. data/lib/railroader/processors/config_processor.rb +14 -0
  93. data/lib/railroader/processors/controller_alias_processor.rb +278 -0
  94. data/lib/railroader/processors/controller_processor.rb +249 -0
  95. data/lib/railroader/processors/erb_template_processor.rb +77 -0
  96. data/lib/railroader/processors/erubis_template_processor.rb +92 -0
  97. data/lib/railroader/processors/gem_processor.rb +64 -0
  98. data/lib/railroader/processors/haml_template_processor.rb +191 -0
  99. data/lib/railroader/processors/lib/basic_processor.rb +37 -0
  100. data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
  101. data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
  102. data/lib/railroader/processors/lib/find_call.rb +183 -0
  103. data/lib/railroader/processors/lib/find_return_value.rb +166 -0
  104. data/lib/railroader/processors/lib/module_helper.rb +111 -0
  105. data/lib/railroader/processors/lib/processor_helper.rb +88 -0
  106. data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
  107. data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
  108. data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
  109. data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
  110. data/lib/railroader/processors/lib/render_helper.rb +181 -0
  111. data/lib/railroader/processors/lib/render_path.rb +107 -0
  112. data/lib/railroader/processors/lib/route_helper.rb +68 -0
  113. data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
  114. data/lib/railroader/processors/library_processor.rb +74 -0
  115. data/lib/railroader/processors/model_processor.rb +91 -0
  116. data/lib/railroader/processors/output_processor.rb +144 -0
  117. data/lib/railroader/processors/route_processor.rb +17 -0
  118. data/lib/railroader/processors/slim_template_processor.rb +111 -0
  119. data/lib/railroader/processors/template_alias_processor.rb +118 -0
  120. data/lib/railroader/processors/template_processor.rb +85 -0
  121. data/lib/railroader/report/config/remediation.yml +71 -0
  122. data/lib/railroader/report/ignore/config.rb +153 -0
  123. data/lib/railroader/report/ignore/interactive.rb +362 -0
  124. data/lib/railroader/report/pager.rb +112 -0
  125. data/lib/railroader/report/renderer.rb +24 -0
  126. data/lib/railroader/report/report_base.rb +292 -0
  127. data/lib/railroader/report/report_codeclimate.rb +79 -0
  128. data/lib/railroader/report/report_csv.rb +55 -0
  129. data/lib/railroader/report/report_hash.rb +23 -0
  130. data/lib/railroader/report/report_html.rb +216 -0
  131. data/lib/railroader/report/report_json.rb +45 -0
  132. data/lib/railroader/report/report_markdown.rb +107 -0
  133. data/lib/railroader/report/report_table.rb +117 -0
  134. data/lib/railroader/report/report_tabs.rb +17 -0
  135. data/lib/railroader/report/report_text.rb +198 -0
  136. data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
  137. data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
  138. data/lib/railroader/report/templates/error_overview.html.erb +29 -0
  139. data/lib/railroader/report/templates/header.html.erb +58 -0
  140. data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
  141. data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
  142. data/lib/railroader/report/templates/overview.html.erb +38 -0
  143. data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
  144. data/lib/railroader/report/templates/template_overview.html.erb +21 -0
  145. data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
  146. data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
  147. data/lib/railroader/report.rb +88 -0
  148. data/lib/railroader/rescanner.rb +483 -0
  149. data/lib/railroader/scanner.rb +321 -0
  150. data/lib/railroader/tracker/collection.rb +93 -0
  151. data/lib/railroader/tracker/config.rb +154 -0
  152. data/lib/railroader/tracker/constants.rb +171 -0
  153. data/lib/railroader/tracker/controller.rb +161 -0
  154. data/lib/railroader/tracker/library.rb +17 -0
  155. data/lib/railroader/tracker/model.rb +90 -0
  156. data/lib/railroader/tracker/template.rb +33 -0
  157. data/lib/railroader/tracker.rb +362 -0
  158. data/lib/railroader/util.rb +503 -0
  159. data/lib/railroader/version.rb +3 -0
  160. data/lib/railroader/warning.rb +294 -0
  161. data/lib/railroader/warning_codes.rb +117 -0
  162. data/lib/railroader.rb +544 -0
  163. data/lib/ruby_parser/bm_sexp.rb +626 -0
  164. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  165. metadata +386 -0
@@ -0,0 +1,112 @@
1
+ module Railroader
2
+ class Pager
3
+ def initialize tracker, pager = :less, output = $stdout
4
+ @tracker = tracker
5
+ @pager = pager
6
+ @output = output
7
+ end
8
+
9
+ def page_report report, format
10
+ if @pager == :less
11
+ set_color
12
+ end
13
+
14
+ text = report.format(format)
15
+
16
+ if in_ci?
17
+ no_pager text
18
+ else
19
+ page_output text
20
+ end
21
+ end
22
+
23
+ def page_output text
24
+ case @pager
25
+ when :none
26
+ no_pager text
27
+ when :highline
28
+ page_via_highline text
29
+ when :less
30
+ if less_available?
31
+ page_via_less text
32
+ else
33
+ page_via_highline text
34
+ end
35
+ else
36
+ no_pager text
37
+ end
38
+ end
39
+
40
+ def no_pager text
41
+ @output.puts text
42
+ end
43
+
44
+ def page_via_highline text
45
+ Railroader.load_railroader_dependency 'highline'
46
+ h = ::HighLine.new($stdin, @output)
47
+ h.page_at = :auto
48
+ h.say text
49
+ end
50
+
51
+ def page_via_less text
52
+ # Adapted from https://github.com/piotrmurach/tty-pager/
53
+
54
+ write_io = open("|less #{less_options.join}", 'w')
55
+ pid = write_io.pid
56
+
57
+ write_io.write(text)
58
+ write_io.close
59
+
60
+ Process.waitpid2(pid, Process::WNOHANG)
61
+ rescue Errno::ECHILD
62
+ # on jruby 9x waiting on pid raises (per tty-pager)
63
+ true
64
+ rescue => e
65
+ warn "[Error] #{e}"
66
+ warn "[Error] Could not use pager. Set --no-pager to avoid this issue."
67
+ no_pager text
68
+ end
69
+
70
+ def in_ci?
71
+ ci = ENV["CI"]
72
+
73
+ ci.is_a? String and ci.downcase == "true"
74
+ end
75
+
76
+ def less_available?
77
+ return @less_available unless @less_available.nil?
78
+
79
+ @less_available = system("which less > /dev/null")
80
+ end
81
+
82
+ def less_options
83
+ # -R show colors
84
+ # -F exit if output fits on one screen
85
+ # -X do not clear screen after less exits
86
+
87
+ return @less_options if @less_options
88
+
89
+ @less_options = []
90
+
91
+ if system("which less > /dev/null")
92
+ less_help = `less -?`
93
+
94
+ ["-R ", "-F ", "-X "].each do |opt|
95
+ if less_help.include? opt
96
+ @less_options << opt
97
+ end
98
+ end
99
+ end
100
+
101
+ @less_options
102
+ end
103
+
104
+ def set_color
105
+ return unless @tracker
106
+
107
+ unless less_options.include? "-R " or @tracker.options[:output_color] == :force
108
+ @tracker.options[:output_color] = false
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,24 @@
1
+ require 'erb'
2
+
3
+ class Railroader::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,292 @@
1
+ require 'set'
2
+ require 'railroader/util'
3
+ require 'railroader/version'
4
+ require 'railroader/report/renderer'
5
+ require 'railroader/processors/output_processor'
6
+ require 'railroader/warning'
7
+
8
+ # Base class for report formats
9
+ class Railroader::Report::Base
10
+ include Railroader::Util
11
+
12
+ attr_reader :tracker, :checks
13
+
14
+ TEXT_CONFIDENCE = Railroader::Warning::TEXT_CONFIDENCE
15
+
16
+ def initialize app_tree, tracker
17
+ @app_tree = app_tree
18
+ @tracker = tracker
19
+ @checks = tracker.checks
20
+ @ignore_filter = tracker.ignored_filter
21
+ @highlight_user_input = tracker.options[:highlight_user_input]
22
+ @warnings_summary = nil
23
+ end
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}
31
+
32
+ render_array('warning_overview', ['Warning Type', 'Total'], values, locals)
33
+ end
34
+
35
+ #Generate table of controllers and routes found for those controllers
36
+ def generate_controllers
37
+ controller_rows = []
38
+
39
+ tracker.controllers.keys.map{|k| k.to_s}.sort.each do |name|
40
+ name = name.to_sym
41
+ c = tracker.controllers[name]
42
+
43
+ if tracker.routes.include? :allow_all_actions or (tracker.routes[name] and tracker.routes[name].include? :allow_all_actions)
44
+ routes = c.methods_public.keys.map{|e| e.to_s}.sort.join(", ")
45
+ elsif tracker.routes[name].nil?
46
+ #No routes defined for this controller.
47
+ #This can happen when it is only a parent class
48
+ #for other controllers, for example.
49
+ routes = "[None]"
50
+
51
+ else
52
+ routes = (Set.new(c.methods_public.keys) & tracker.routes[name.to_sym]).
53
+ to_a.
54
+ map {|e| e.to_s}.
55
+ sort.
56
+ join(", ")
57
+ end
58
+
59
+ if routes == ""
60
+ routes = "[None]"
61
+ end
62
+
63
+ controller_rows << { "Name" => name.to_s,
64
+ "Parent" => c.parent.to_s,
65
+ "Includes" => c.includes.join(", "),
66
+ "Routes" => routes
67
+ }
68
+ end
69
+
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
212
+ end
213
+
214
+ def all_warnings
215
+ if @ignore_filter
216
+ @all_warnings ||= @ignore_filter.shown_warnings
217
+ else
218
+ @all_warnings ||= tracker.checks.all_warnings
219
+ end
220
+ end
221
+
222
+ def filter_warnings warnings
223
+ if @ignore_filter
224
+ warnings.reject do |w|
225
+ @ignore_filter.ignored? w
226
+ end
227
+ else
228
+ warnings
229
+ end
230
+ end
231
+
232
+ def generic_warnings
233
+ filter_warnings tracker.checks.warnings
234
+ end
235
+
236
+ def template_warnings
237
+ filter_warnings tracker.checks.template_warnings
238
+ end
239
+
240
+ def model_warnings
241
+ filter_warnings tracker.checks.model_warnings
242
+ end
243
+
244
+ def controller_warnings
245
+ filter_warnings tracker.checks.controller_warnings
246
+ end
247
+
248
+ def ignored_warnings
249
+ if @ignore_filter
250
+ @ignore_filter.ignored_warnings
251
+ else
252
+ []
253
+ end
254
+ end
255
+
256
+ def number_of_templates tracker
257
+ Set.new(tracker.templates.map {|k,v| v.name.to_s[/[^.]+/]}).length
258
+ end
259
+
260
+ def warning_file warning, absolute = @tracker.options[:absolute_paths]
261
+ return nil if warning.file.nil?
262
+
263
+ if absolute
264
+ warning.file
265
+ else
266
+ relative_path warning.file
267
+ end
268
+ end
269
+
270
+ def rails_version
271
+ case
272
+ when tracker.config.rails_version
273
+ tracker.config.rails_version
274
+ when tracker.options[:rails4]
275
+ "4.x"
276
+ when tracker.options[:rails3]
277
+ "3.x"
278
+ else
279
+ "Unknown"
280
+ end
281
+ 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
+ end
@@ -0,0 +1,79 @@
1
+ require "json"
2
+ require "yaml"
3
+ require "pathname"
4
+
5
+ class Railroader::Report::CodeClimate < Railroader::Report::Base
6
+ DOCUMENTATION_PATH = File.expand_path("../../../../docs/warning_types", __FILE__)
7
+ REMEDIATION_POINTS_CONFIG_PATH = File.expand_path("../config/remediation.yml", __FILE__)
8
+ REMEDIATION_POINTS_DEFAULT = 300_000
9
+
10
+ def generate_report
11
+ all_warnings.map { |warning| issue_json(warning) }.join("\0")
12
+ end
13
+
14
+ private
15
+
16
+ def issue_json(warning)
17
+ warning_code_name = name_for(warning.warning_code)
18
+
19
+ {
20
+ type: "Issue",
21
+ check_name: warning_code_name,
22
+ description: warning.message,
23
+ fingerprint: warning.fingerprint,
24
+ categories: ["Security"],
25
+ severity: severity_level_for(warning.confidence),
26
+ remediation_points: remediation_points_for(warning_code_name),
27
+ location: {
28
+ path: file_path(warning),
29
+ lines: {
30
+ begin: warning.line || 1,
31
+ end: warning.line || 1,
32
+ }
33
+ },
34
+ content: {
35
+ body: content_for(warning.warning_code, warning.link)
36
+ }
37
+ }.to_json
38
+ end
39
+
40
+ def severity_level_for(confidence)
41
+ if confidence == 0
42
+ "critical"
43
+ else
44
+ "normal"
45
+ end
46
+ end
47
+
48
+ def remediation_points_for(warning_code)
49
+ @remediation_points ||= YAML.load_file(REMEDIATION_POINTS_CONFIG_PATH)
50
+ @remediation_points.fetch(name_for(warning_code), REMEDIATION_POINTS_DEFAULT)
51
+ end
52
+
53
+ def name_for(warning_code)
54
+ @warning_codes ||= Railroader::WarningCodes::Codes.invert
55
+ @warning_codes[warning_code].to_s
56
+ end
57
+
58
+ def content_for(warning_code, link)
59
+ @contents ||= {}
60
+ unless link.nil?
61
+ @contents[warning_code] ||= local_content_for(link) || "Read more: #{link}"
62
+ end
63
+ end
64
+
65
+ def local_content_for(link)
66
+ directory = link.split("/").last
67
+ filename = File.join(DOCUMENTATION_PATH, directory, "index.markdown")
68
+
69
+ File.read(filename) if File.exist?(filename)
70
+ end
71
+
72
+ def file_path(warning)
73
+ fp = Pathname.new(warning.relative_path)
74
+ if tracker.options[:path_prefix]
75
+ fp = Pathname.new(tracker.options[:path_prefix]) + fp
76
+ end
77
+ fp.to_s
78
+ end
79
+ end
@@ -0,0 +1,55 @@
1
+ require 'csv'
2
+ require "railroader/report/report_table"
3
+
4
+ class Railroader::Report::CSV < Railroader::Report::Table
5
+ def generate_report
6
+ output = csv_header
7
+ output << "\nSUMMARY\n"
8
+
9
+ output << table_to_csv(generate_overview) << "\n"
10
+
11
+ output << table_to_csv(generate_warning_overview) << "\n"
12
+
13
+ #Return output early if only summarizing
14
+ if tracker.options[:summary_only]
15
+ return output
16
+ end
17
+
18
+ if tracker.options[:report_routes] or tracker.options[:debug]
19
+ output << "CONTROLLERS\n"
20
+ output << table_to_csv(generate_controllers) << "\n"
21
+ end
22
+
23
+ if tracker.options[:debug]
24
+ output << "TEMPLATES\n\n"
25
+ output << table_to_csv(generate_templates) << "\n"
26
+ end
27
+
28
+ res = generate_errors
29
+ output << "ERRORS\n" << table_to_csv(res) << "\n" if res
30
+
31
+ res = generate_warnings
32
+ output << "SECURITY WARNINGS\n" << table_to_csv(res) << "\n" if res
33
+
34
+ output << "Controller Warnings\n"
35
+ res = generate_controller_warnings
36
+ output << table_to_csv(res) << "\n" if res
37
+
38
+ output << "Model Warnings\n"
39
+ res = generate_model_warnings
40
+ output << table_to_csv(res) << "\n" if res
41
+
42
+ res = generate_template_warnings
43
+ output << "Template Warnings\n"
44
+ output << table_to_csv(res) << "\n" if res
45
+
46
+ output
47
+ end
48
+
49
+ #Generate header for CSV output
50
+ def csv_header
51
+ header = CSV.generate_line(["Application Path", "Report Generation Time", "Checks Performed", "Rails Version"])
52
+ header << CSV.generate_line([File.expand_path(tracker.app_path), Time.now.to_s, checks.checks_run.sort.join(", "), rails_version])
53
+ "BRAKEMAN REPORT\n\n" + header
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ # Generates a hash table for use in Railroader tests
2
+ class Railroader::Report::Hash < Railroader::Report::Base
3
+ def generate_report
4
+ report = { :errors => tracker.errors,
5
+ :controllers => tracker.controllers,
6
+ :models => tracker.models,
7
+ :templates => tracker.templates
8
+ }
9
+
10
+ [:generic_warnings, :controller_warnings, :model_warnings, :template_warnings].each do |meth|
11
+ report[meth] = self.send(meth)
12
+ report[meth].each do |w|
13
+ w.message = w.format_message
14
+ w.context = context_for(@app_tree, w).join("\n")
15
+ end
16
+ end
17
+
18
+ report[:config] = tracker.config
19
+ report[:checks_run] = tracker.checks.checks_run
20
+
21
+ report
22
+ end
23
+ end