brakeman-lib 4.4.0 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +63 -0
  3. data/README.md +6 -7
  4. data/lib/brakeman.rb +7 -0
  5. data/lib/brakeman/app_tree.rb +34 -22
  6. data/lib/brakeman/call_index.rb +54 -15
  7. data/lib/brakeman/checks.rb +7 -7
  8. data/lib/brakeman/checks/base_check.rb +75 -56
  9. data/lib/brakeman/checks/check_content_tag.rb +12 -0
  10. data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
  11. data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
  12. data/lib/brakeman/checks/check_default_routes.rb +5 -0
  13. data/lib/brakeman/checks/check_deserialize.rb +49 -0
  14. data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
  15. data/lib/brakeman/checks/check_evaluation.rb +0 -1
  16. data/lib/brakeman/checks/check_execute.rb +44 -1
  17. data/lib/brakeman/checks/check_file_access.rb +7 -1
  18. data/lib/brakeman/checks/check_force_ssl.rb +27 -0
  19. data/lib/brakeman/checks/check_header_dos.rb +2 -2
  20. data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
  21. data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
  22. data/lib/brakeman/checks/check_json_parsing.rb +7 -2
  23. data/lib/brakeman/checks/check_link_to_href.rb +6 -1
  24. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  25. data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
  26. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  27. data/lib/brakeman/checks/check_model_attributes.rb +12 -50
  28. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  29. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
  30. data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
  31. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
  32. data/lib/brakeman/checks/check_secrets.rb +1 -1
  33. data/lib/brakeman/checks/check_send.rb +0 -1
  34. data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
  35. data/lib/brakeman/checks/check_session_settings.rb +15 -12
  36. data/lib/brakeman/checks/check_simple_format.rb +5 -0
  37. data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
  38. data/lib/brakeman/checks/check_sql.rb +27 -20
  39. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  40. data/lib/brakeman/checks/check_xml_dos.rb +2 -2
  41. data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
  42. data/lib/brakeman/differ.rb +16 -28
  43. data/lib/brakeman/file_parser.rb +6 -8
  44. data/lib/brakeman/file_path.rb +85 -0
  45. data/lib/brakeman/options.rb +7 -0
  46. data/lib/brakeman/parsers/haml_embedded.rb +44 -0
  47. data/lib/brakeman/parsers/slim_embedded.rb +44 -0
  48. data/lib/brakeman/parsers/template_parser.rb +8 -8
  49. data/lib/brakeman/processor.rb +4 -5
  50. data/lib/brakeman/processors/alias_processor.rb +49 -7
  51. data/lib/brakeman/processors/base_processor.rb +10 -7
  52. data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
  53. data/lib/brakeman/processors/controller_processor.rb +9 -13
  54. data/lib/brakeman/processors/gem_processor.rb +10 -2
  55. data/lib/brakeman/processors/haml_template_processor.rb +92 -123
  56. data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
  57. data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
  58. data/lib/brakeman/processors/lib/find_call.rb +3 -64
  59. data/lib/brakeman/processors/lib/module_helper.rb +8 -8
  60. data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
  61. data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
  62. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
  63. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
  64. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
  65. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  66. data/lib/brakeman/processors/lib/render_path.rb +18 -1
  67. data/lib/brakeman/processors/library_processor.rb +5 -5
  68. data/lib/brakeman/processors/model_processor.rb +4 -5
  69. data/lib/brakeman/processors/output_processor.rb +5 -0
  70. data/lib/brakeman/processors/slim_template_processor.rb +16 -0
  71. data/lib/brakeman/processors/template_alias_processor.rb +32 -5
  72. data/lib/brakeman/processors/template_processor.rb +14 -10
  73. data/lib/brakeman/report.rb +3 -3
  74. data/lib/brakeman/report/ignore/config.rb +2 -3
  75. data/lib/brakeman/report/ignore/interactive.rb +2 -2
  76. data/lib/brakeman/report/pager.rb +1 -0
  77. data/lib/brakeman/report/report_base.rb +51 -6
  78. data/lib/brakeman/report/report_codeclimate.rb +3 -3
  79. data/lib/brakeman/report/report_hash.rb +1 -1
  80. data/lib/brakeman/report/report_html.rb +2 -2
  81. data/lib/brakeman/report/report_json.rb +1 -24
  82. data/lib/brakeman/report/report_table.rb +20 -4
  83. data/lib/brakeman/report/report_tabs.rb +1 -1
  84. data/lib/brakeman/report/report_text.rb +2 -2
  85. data/lib/brakeman/rescanner.rb +13 -12
  86. data/lib/brakeman/scanner.rb +24 -18
  87. data/lib/brakeman/tracker.rb +35 -7
  88. data/lib/brakeman/tracker/collection.rb +4 -3
  89. data/lib/brakeman/tracker/config.rb +44 -48
  90. data/lib/brakeman/tracker/constants.rb +2 -1
  91. data/lib/brakeman/util.rb +18 -147
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +27 -13
  94. data/lib/brakeman/warning_codes.rb +4 -0
  95. data/lib/ruby_parser/bm_sexp.rb +1 -1
  96. data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
  97. metadata +58 -43
@@ -1,5 +1,6 @@
1
1
  begin
2
2
  Brakeman.load_brakeman_dependency 'ruby_parser'
3
+ Brakeman.load_brakeman_dependency 'ruby_parser/legacy'
3
4
  require 'ruby_parser/bm_sexp.rb'
4
5
  require 'ruby_parser/bm_sexp_processor.rb'
5
6
  require 'brakeman/processor'
@@ -15,7 +16,6 @@ end
15
16
  #Scans the Rails application.
16
17
  class Brakeman::Scanner
17
18
  attr_reader :options
18
- RUBY_1_9 = RUBY_VERSION >= "1.9.0"
19
19
 
20
20
  #Pass in path to the root of the Rails application
21
21
  def initialize options, processor = nil
@@ -65,7 +65,7 @@ class Brakeman::Scanner
65
65
  end
66
66
 
67
67
  def parse_files
68
- fp = Brakeman::FileParser.new tracker, @app_tree
68
+ fp = Brakeman::FileParser.new tracker
69
69
 
70
70
  files = {
71
71
  :initializers => @app_tree.initializer_paths,
@@ -94,7 +94,7 @@ class Brakeman::Scanner
94
94
  #
95
95
  #Stores parsed information in tracker.config
96
96
  def process_config
97
- if options[:rails3] or options[:rails4] or options[:rails5]
97
+ if options[:rails3] or options[:rails4] or options[:rails5] or options[:rails6]
98
98
  process_config_file "application.rb"
99
99
  process_config_file "environments/production.rb"
100
100
  else
@@ -110,15 +110,15 @@ class Brakeman::Scanner
110
110
  end
111
111
 
112
112
  if @app_tree.exists? ".ruby-version"
113
- tracker.config.set_ruby_version @app_tree.read ".ruby-version"
113
+ tracker.config.set_ruby_version @app_tree.file_path(".ruby-version").read
114
114
  end
115
115
  end
116
116
 
117
117
  def process_config_file file
118
- path = "config/#{file}"
118
+ path = @app_tree.file_path("config/#{file}")
119
119
 
120
- if @app_tree.exists?(path)
121
- @processor.process_config(parse_ruby(@app_tree.read(path)), path)
120
+ if path.exists?
121
+ @processor.process_config(parse_ruby_file(path), path)
122
122
  end
123
123
 
124
124
  rescue => e
@@ -131,20 +131,25 @@ class Brakeman::Scanner
131
131
  #Process Gemfile
132
132
  def process_gems
133
133
  gem_files = {}
134
+
134
135
  if @app_tree.exists? "Gemfile"
135
- gem_files[:gemfile] = { :src => parse_ruby(@app_tree.read("Gemfile")), :file => "Gemfile" }
136
+ file = @app_tree.file_path("Gemfile")
137
+ gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
136
138
  elsif @app_tree.exists? "gems.rb"
137
- gem_files[:gemfile] = { :src => parse_ruby(@app_tree.read("gems.rb")), :file => "gems.rb" }
139
+ file = @app_tree.file_path("gems.rb")
140
+ gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
138
141
  end
139
142
 
140
143
  if @app_tree.exists? "Gemfile.lock"
141
- gem_files[:gemlock] = { :src => @app_tree.read("Gemfile.lock"), :file => "Gemfile.lock" }
144
+ file = @app_tree.file_path("Gemfile.lock")
145
+ gem_files[:gemlock] = { :src => file.read, :file => file }
142
146
  elsif @app_tree.exists? "gems.locked"
143
- gem_files[:gemlock] = { :src => @app_tree.read("gems.locked"), :file => "gems.locked" }
147
+ file = @app_tree.file_path("gems.locked")
148
+ gem_files[:gemlock] = { :src => file.read, :file => file }
144
149
  end
145
150
 
146
151
  if @app_tree.gemspec
147
- gem_files[:gemspec] = { :src => parse_ruby(@app_tree.read(@app_tree.gemspec)), :file => @app_tree.gemspec }
152
+ gem_files[:gemspec] = { :src => parse_ruby_file(@app_tree.gemspec), :file => @app_tree.gemspec }
148
153
  end
149
154
 
150
155
  if not gem_files.empty?
@@ -214,10 +219,10 @@ class Brakeman::Scanner
214
219
  #Adds parsed information to tracker.routes
215
220
  def process_routes
216
221
  if @app_tree.exists?("config/routes.rb")
217
- begin
218
- @processor.process_routes parse_ruby(@app_tree.read("config/routes.rb"))
219
- rescue => e
220
- tracker.error e.exception(e.message + "\nWhile processing routes.rb"), e.backtrace
222
+ file = @app_tree.file_path("config/routes.rb")
223
+ if routes_sexp = parse_ruby_file(file)
224
+ @processor.process_routes routes_sexp
225
+ else
221
226
  Brakeman.notify "[Notice] Error while processing routes - assuming all public controller methods are actions."
222
227
  options[:assume_all_routes] = true
223
228
  end
@@ -316,8 +321,9 @@ class Brakeman::Scanner
316
321
  tracker.index_call_sites
317
322
  end
318
323
 
319
- def parse_ruby input
320
- RubyParser.new.parse input
324
+ def parse_ruby_file file
325
+ fp = Brakeman::FileParser.new(self.tracker)
326
+ fp.parse_ruby(file.read, file)
321
327
  end
322
328
  end
323
329
 
@@ -12,7 +12,7 @@ class Brakeman::Tracker
12
12
  attr_accessor :controllers, :constants, :templates, :models, :errors,
13
13
  :checks, :initializers, :config, :routes, :processor, :libs,
14
14
  :template_cache, :options, :filter_cache, :start_time, :end_time,
15
- :duration, :ignored_filter
15
+ :duration, :ignored_filter, :app_tree
16
16
 
17
17
  #Place holder when there should be a model, but it is not
18
18
  #clear what model it will be.
@@ -34,7 +34,7 @@ class Brakeman::Tracker
34
34
  #we can match models later without knowing precisely what
35
35
  #class they are.
36
36
  @models = {}
37
- @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, nil, nil, self)
37
+ @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, @app_tree.file_path("NOT_REAL.rb"), nil, self)
38
38
  @routes = {}
39
39
  @initializers = {}
40
40
  @errors = []
@@ -61,13 +61,17 @@ class Brakeman::Tracker
61
61
  Brakeman.debug exception
62
62
  Brakeman.debug backtrace
63
63
 
64
- @errors << { :error => exception.to_s.gsub("\n", " "), :backtrace => backtrace }
64
+ @errors << {
65
+ :exception => exception,
66
+ :error => exception.to_s.gsub("\n", " "),
67
+ :backtrace => backtrace
68
+ }
65
69
  end
66
70
 
67
71
  #Run a set of checks on the current information. Results will be stored
68
72
  #in Tracker#checks.
69
73
  def run_checks
70
- @checks = Brakeman::Checks.run_checks(@app_tree, self)
74
+ @checks = Brakeman::Checks.run_checks(self)
71
75
 
72
76
  @end_time = Time.now
73
77
  @duration = @end_time - @start_time
@@ -168,7 +172,7 @@ class Brakeman::Tracker
168
172
 
169
173
  #Returns a Report with this Tracker's information
170
174
  def report
171
- Brakeman::Report.new(@app_tree, self)
175
+ Brakeman::Report.new(self)
172
176
  end
173
177
 
174
178
  def warnings
@@ -223,6 +227,10 @@ class Brakeman::Tracker
223
227
  finder.process_source template.src, :template => template, :file => template.file
224
228
  end
225
229
 
230
+ self.initializers.each do |file_name, src|
231
+ finder.process_all_source src, :file => file_name
232
+ end
233
+
226
234
  @call_index = Brakeman::CallIndex.new finder.calls
227
235
  end
228
236
 
@@ -233,8 +241,8 @@ class Brakeman::Tracker
233
241
  #
234
242
  #This will limit reindexing to the given sets
235
243
  def reindex_call_sites locations
236
- #If reindexing templates, models, and controllers, just redo
237
- #everything
244
+ #If reindexing templates, models, controllers,
245
+ #just redo everything.
238
246
  if locations.length == 3
239
247
  return index_call_sites
240
248
  end
@@ -256,6 +264,12 @@ class Brakeman::Tracker
256
264
  method_sets << self.controllers
257
265
  end
258
266
 
267
+ if locations.include? :initializers
268
+ self.initializers.each do |file_name, src|
269
+ @call_index.remove_indexes_by_file file_name
270
+ end
271
+ end
272
+
259
273
  @call_index.remove_indexes_by_class classes_to_reindex
260
274
 
261
275
  finder = Brakeman::FindAllCalls.new self
@@ -275,6 +289,12 @@ class Brakeman::Tracker
275
289
  end
276
290
  end
277
291
 
292
+ if locations.include? :initializers
293
+ self.initializers.each do |file_name, src|
294
+ finder.process_all_source src, :file => file_name
295
+ end
296
+ end
297
+
278
298
  @call_index.index_calls finder.calls
279
299
  end
280
300
 
@@ -359,4 +379,12 @@ class Brakeman::Tracker
359
379
  def reset_routes
360
380
  @routes = {}
361
381
  end
382
+
383
+ def reset_initializer path
384
+ @initializers.delete_if do |file, src|
385
+ path.relative.include? file
386
+ end
387
+
388
+ @call_index.remove_indexes_by_file path
389
+ end
362
390
  end
@@ -9,13 +9,14 @@ module Brakeman
9
9
  def initialize name, parent, file_name, src, tracker
10
10
  @name = name
11
11
  @parent = parent
12
- @file_name = file_name
13
- @files = [ file_name ]
14
- @src = { file_name => src }
12
+ @files = []
13
+ @src = {}
15
14
  @includes = []
16
15
  @methods = { :public => {}, :private => {}, :protected => {} }
17
16
  @options = {}
18
17
  @tracker = tracker
18
+
19
+ add_file file_name, src
19
20
  end
20
21
 
21
22
  def ancestor? parent, seen={}
@@ -4,10 +4,8 @@ module Brakeman
4
4
  class Config
5
5
  include Util
6
6
 
7
- attr_reader :rails, :tracker
8
- attr_accessor :rails_version, :ruby_version
7
+ attr_reader :gems, :rails, :ruby_version, :tracker
9
8
  attr_writer :erubis, :escape_html
10
- attr_reader :gems
11
9
 
12
10
  def initialize tracker
13
11
  @tracker = tracker
@@ -19,16 +17,9 @@ module Brakeman
19
17
  @ruby_version = ""
20
18
  end
21
19
 
22
- def allow_forgery_protection?
23
- @rails[:action_controller] and
24
- @rails[:action_controller][:allow_forgery_protection] == Sexp.new(:false)
25
- end
26
-
27
20
  def default_protect_from_forgery?
28
- if version_between? "5.2.0", "9.9.9"
29
- if @rails[:action_controller] and
30
- @rails[:action_controller][:default_protect_from_forgery] == Sexp.new(:false)
31
-
21
+ if version_between? "5.2.0.beta1", "9.9.9"
22
+ if @rails.dig(:action_controller, :default_protect_from_forgery) == Sexp.new(:false)
32
23
  return false
33
24
  else
34
25
  return true
@@ -48,17 +39,21 @@ module Brakeman
48
39
 
49
40
  def escape_html_entities_in_json?
50
41
  #TODO add version-specific information here
51
- @rails[:active_support] and
52
- true? @rails[:active_support][:escape_html_entities_in_json]
42
+ true? @rails.dig(:active_support, :escape_html_entities_in_json)
43
+ end
44
+
45
+ def escape_filter_interpolations?
46
+ # TODO see if app is actually turning this off itself
47
+ has_gem?(:haml) and
48
+ version_between? "5.0.0", "5.99", gem_version(:haml)
53
49
  end
54
50
 
55
51
  def whitelist_attributes?
56
- @rails[:active_record] and
57
- @rails[:active_record][:whitelist_attributes] == Sexp.new(:true)
52
+ @rails.dig(:active_record, :whitelist_attributes) == Sexp.new(:true)
58
53
  end
59
54
 
60
55
  def gem_version name
61
- @gems[name] and @gems[name][:version]
56
+ extract_version @gems.dig(name, :version)
62
57
  end
63
58
 
64
59
  def add_gem name, version, file, line
@@ -78,11 +73,16 @@ module Brakeman
78
73
  @gems[name]
79
74
  end
80
75
 
81
- def set_rails_version
82
- # Ignore ~>, etc. when using values from Gemfile
83
- version = gem_version(:rails) || gem_version(:railties)
84
- if version and version.match(/(\d+\.\d+(\.\d+.*)?)/)
85
- @rails_version = $1
76
+ def set_rails_version version = nil
77
+ version = if version
78
+ # Only used by Rails2ConfigProcessor right now
79
+ extract_version(version)
80
+ else
81
+ gem_version(:rails) || gem_version(:railties)
82
+ end
83
+
84
+ if version
85
+ @rails_version = version
86
86
 
87
87
  if tracker.options[:rails3].nil? and tracker.options[:rails4].nil?
88
88
  if @rails_version.start_with? "3"
@@ -97,6 +97,12 @@ module Brakeman
97
97
  tracker.options[:rails4] = true
98
98
  tracker.options[:rails5] = true
99
99
  Brakeman.notify "[Notice] Detected Rails 5 application"
100
+ elsif @rails_version.start_with? "6"
101
+ tracker.options[:rails3] = true
102
+ tracker.options[:rails4] = true
103
+ tracker.options[:rails5] = true
104
+ tracker.options[:rails6] = true
105
+ Brakeman.notify "[Notice] Detected Rails 6 application"
100
106
  end
101
107
  end
102
108
  end
@@ -107,12 +113,20 @@ module Brakeman
107
113
  end
108
114
  end
109
115
 
116
+ def rails_version
117
+ # This needs to be here because Util#rails_version calls Tracker::Config#rails_version
118
+ # but Tracker::Config includes Util...
119
+ @rails_version
120
+ end
121
+
110
122
  def set_ruby_version version
123
+ @ruby_version = extract_version(version)
124
+ end
125
+
126
+ def extract_version version
111
127
  return unless version.is_a? String
112
128
 
113
- if version =~ /(\d+\.\d+\.\d+)/
114
- self.ruby_version = $1
115
- end
129
+ version[/\d+\.\d+(\.\d+.*)?/]
116
130
  end
117
131
 
118
132
  #Returns true if low_version <= RAILS_VERSION <= high_version
@@ -122,33 +136,15 @@ module Brakeman
122
136
  current_version ||= rails_version
123
137
  return false unless current_version
124
138
 
125
- version = current_version.split(".").map!(&:to_i)
126
- low_version = low_version.split(".").map!(&:to_i)
127
- high_version = high_version.split(".").map!(&:to_i)
128
-
129
- version.each_with_index do |v, i|
130
- if v < low_version.fetch(i, 0)
131
- return false
132
- elsif v > low_version.fetch(i, 0)
133
- break
134
- end
135
- end
139
+ low = Gem::Version.new(low_version)
140
+ high = Gem::Version.new(high_version)
141
+ current = Gem::Version.new(current_version)
136
142
 
137
- version.each_with_index do |v, i|
138
- if v > high_version.fetch(i, 0)
139
- return false
140
- elsif v < high_version.fetch(i, 0)
141
- break
142
- end
143
- end
144
-
145
- true
143
+ current.between?(low, high)
146
144
  end
147
145
 
148
146
  def session_settings
149
- @rails[:action_controller] &&
150
- @rails[:action_controller][:session]
147
+ @rails.dig(:action_controller, :session)
151
148
  end
152
-
153
149
  end
154
150
  end
@@ -49,7 +49,7 @@ module Brakeman
49
49
  include Brakeman::Util
50
50
 
51
51
  def initialize
52
- @constants = Hash.new { |h, k| h[k] = [] }
52
+ @constants = {}
53
53
  end
54
54
 
55
55
  def size
@@ -103,6 +103,7 @@ module Brakeman
103
103
  end
104
104
 
105
105
  base_name = Constants.get_constant_base_name(name)
106
+ @constants[base_name] ||= []
106
107
  @constants[base_name] << Constant.new(name, value, context)
107
108
  end
108
109
 
data/lib/brakeman/util.rb CHANGED
@@ -94,11 +94,21 @@ module Brakeman::Util
94
94
  # end
95
95
  # names #["bob"]
96
96
  def hash_iterate hash
97
+ hash = remove_kwsplat(hash)
98
+
97
99
  1.step(hash.length - 1, 2) do |i|
98
100
  yield hash[i], hash[i + 1]
99
101
  end
100
102
  end
101
103
 
104
+ def remove_kwsplat exp
105
+ if exp.any? { |e| node_type? e, :kwsplat }
106
+ exp.reject { |e| node_type? e, :kwsplat }
107
+ else
108
+ exp
109
+ end
110
+ end
111
+
102
112
  #Insert value into Hash Sexp
103
113
  def hash_insert hash, key, value
104
114
  index = 1
@@ -264,6 +274,13 @@ module Brakeman::Util
264
274
  node_type? exp, :const, :colon2, :colon3
265
275
  end
266
276
 
277
+ def kwsplat? exp
278
+ exp.is_a? Sexp and
279
+ exp.node_type == :hash and
280
+ exp[1].is_a? Sexp and
281
+ exp[1].node_type == :kwsplat
282
+ end
283
+
267
284
  #Check if _exp_ is a Sexp.
268
285
  def sexp? exp
269
286
  exp.is_a? Sexp
@@ -329,158 +346,12 @@ module Brakeman::Util
329
346
  @tracker.config.rails_version
330
347
  end
331
348
 
332
- #Return file name related to given warning. Uses +warning.file+ if it exists
333
- def file_for warning, tracker = nil
334
- if tracker.nil?
335
- tracker = @tracker || self.tracker
336
- end
337
-
338
- if warning.file
339
- File.expand_path warning.file, tracker.app_path
340
- elsif warning.template and warning.template.file
341
- warning.template.file
342
- else
343
- case warning.warning_set
344
- when :controller
345
- file_by_name warning.controller, :controller, tracker
346
- when :template
347
- file_by_name warning.template.name, :template, tracker
348
- when :model
349
- file_by_name warning.model, :model, tracker
350
- when :warning
351
- file_by_name warning.class, nil, tracker
352
- else
353
- nil
354
- end
355
- end
356
- end
357
-
358
- #Attempt to determine path to context file based on the reported name
359
- #in the warning.
360
- #
361
- #For example,
362
- #
363
- # file_by_name FileController #=> "/rails/root/app/controllers/file_controller.rb
364
- def file_by_name name, type, tracker = nil
365
- return nil unless name
366
- string_name = name.to_s
367
- name = name.to_sym
368
-
369
- unless type
370
- if string_name =~ /Controller$/
371
- type = :controller
372
- elsif camelize(string_name) == string_name # This is not always true
373
- type = :model
374
- else
375
- type = :template
376
- end
377
- end
378
-
379
- path = tracker.app_path
380
-
381
- case type
382
- when :controller
383
- if tracker.controllers[name]
384
- path = tracker.controllers[name].file
385
- else
386
- path += "/app/controllers/#{underscore(string_name)}.rb"
387
- end
388
- when :model
389
- if tracker.models[name]
390
- path = tracker.models[name].file
391
- else
392
- path += "/app/models/#{underscore(string_name)}.rb"
393
- end
394
- when :template
395
- if tracker.templates[name] and tracker.templates[name].file
396
- path = tracker.templates[name].file
397
- elsif string_name.include? " "
398
- name = string_name.split[0].to_sym
399
- path = file_for tracker, name, :template
400
- else
401
- path = nil
402
- end
403
- end
404
-
405
- path
406
- end
407
-
408
- #Return array of lines surrounding the warning location from the original
409
- #file.
410
- def context_for app_tree, warning, tracker = nil
411
- file = file_for warning, tracker
412
- context = []
413
- return context unless warning.line and file and @app_tree.path_exists? file
414
-
415
- current_line = 0
416
- start_line = warning.line - 5
417
- end_line = warning.line + 5
418
-
419
- start_line = 1 if start_line < 0
420
-
421
- File.open file do |f|
422
- f.each_line do |line|
423
- current_line += 1
424
-
425
- next if line.strip == ""
426
-
427
- if current_line > end_line
428
- break
429
- end
430
-
431
- if current_line >= start_line
432
- context << [current_line, line]
433
- end
434
- end
435
- end
436
-
437
- context
438
- end
439
-
440
- def relative_path file
441
- pname = Pathname.new file
442
- if file and not file.empty? and pname.absolute?
443
- pname.relative_path_from(Pathname.new(@tracker.app_path)).to_s
444
- else
445
- file
446
- end
447
- end
448
-
449
349
  #Convert path/filename to view name
450
350
  #
451
351
  # views/test/something.html.erb -> test/something
452
352
  def template_path_to_name path
453
- names = path.split("/")
353
+ names = path.relative.split("/")
454
354
  names.last.gsub!(/(\.(html|js)\..*|\.(rhtml|haml|erb|slim))$/, '')
455
355
  names[(names.index("views") + 1)..-1].join("/").to_sym
456
356
  end
457
-
458
- def github_url file, line=nil
459
- if repo_url = @tracker.options[:github_url] and file and not file.empty? and file.start_with? '/'
460
- url = "#{repo_url}/#{relative_path(file)}"
461
- url << "#L#{line}" if line
462
- else
463
- nil
464
- end
465
- end
466
-
467
- def truncate_table str
468
- @terminal_width ||= if @tracker.options[:table_width]
469
- @tracker.options[:table_width]
470
- elsif $stdin && $stdin.tty?
471
- Brakeman.load_brakeman_dependency 'highline'
472
- ::HighLine.new.terminal_size[0]
473
- else
474
- 80
475
- end
476
- lines = str.lines
477
-
478
- lines.map do |line|
479
- if line.chomp.length > @terminal_width
480
- line[0..(@terminal_width - 3)] + ">>\n"
481
- else
482
- line
483
- end
484
- end.join
485
- end
486
357
  end