brakeman-lib 4.5.0 → 4.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +164 -108
  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 +59 -56
  9. data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
  10. data/lib/brakeman/checks/check_cross_site_scripting.rb +9 -4
  11. data/lib/brakeman/checks/check_default_routes.rb +5 -0
  12. data/lib/brakeman/checks/check_deserialize.rb +49 -0
  13. data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
  14. data/lib/brakeman/checks/check_execute.rb +26 -1
  15. data/lib/brakeman/checks/check_file_access.rb +7 -1
  16. data/lib/brakeman/checks/check_force_ssl.rb +27 -0
  17. data/lib/brakeman/checks/check_header_dos.rb +2 -2
  18. data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
  19. data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
  20. data/lib/brakeman/checks/check_json_parsing.rb +7 -2
  21. data/lib/brakeman/checks/check_link_to_href.rb +6 -1
  22. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  23. data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
  24. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  25. data/lib/brakeman/checks/check_model_attributes.rb +12 -50
  26. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  27. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
  28. data/lib/brakeman/checks/check_reverse_tabnabbing.rb +58 -0
  29. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
  30. data/lib/brakeman/checks/check_secrets.rb +1 -1
  31. data/lib/brakeman/checks/check_session_settings.rb +15 -12
  32. data/lib/brakeman/checks/check_simple_format.rb +5 -0
  33. data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
  34. data/lib/brakeman/checks/check_sql.rb +15 -17
  35. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  36. data/lib/brakeman/checks/check_xml_dos.rb +2 -2
  37. data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
  38. data/lib/brakeman/differ.rb +16 -28
  39. data/lib/brakeman/file_parser.rb +10 -16
  40. data/lib/brakeman/file_path.rb +85 -0
  41. data/lib/brakeman/options.rb +7 -0
  42. data/lib/brakeman/parsers/haml_embedded.rb +1 -1
  43. data/lib/brakeman/parsers/template_parser.rb +6 -4
  44. data/lib/brakeman/processor.rb +4 -5
  45. data/lib/brakeman/processors/alias_processor.rb +27 -7
  46. data/lib/brakeman/processors/base_processor.rb +10 -7
  47. data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
  48. data/lib/brakeman/processors/controller_processor.rb +9 -13
  49. data/lib/brakeman/processors/gem_processor.rb +10 -2
  50. data/lib/brakeman/processors/haml_template_processor.rb +92 -123
  51. data/lib/brakeman/processors/lib/call_conversion_helper.rb +5 -4
  52. data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
  53. data/lib/brakeman/processors/lib/find_call.rb +3 -64
  54. data/lib/brakeman/processors/lib/module_helper.rb +8 -8
  55. data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
  56. data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
  57. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
  58. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
  59. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
  60. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  61. data/lib/brakeman/processors/lib/render_path.rb +18 -1
  62. data/lib/brakeman/processors/library_processor.rb +5 -5
  63. data/lib/brakeman/processors/model_processor.rb +4 -5
  64. data/lib/brakeman/processors/output_processor.rb +5 -0
  65. data/lib/brakeman/processors/template_alias_processor.rb +32 -5
  66. data/lib/brakeman/processors/template_processor.rb +14 -10
  67. data/lib/brakeman/report.rb +3 -3
  68. data/lib/brakeman/report/ignore/config.rb +2 -3
  69. data/lib/brakeman/report/ignore/interactive.rb +2 -2
  70. data/lib/brakeman/report/pager.rb +1 -0
  71. data/lib/brakeman/report/report_base.rb +51 -6
  72. data/lib/brakeman/report/report_codeclimate.rb +3 -3
  73. data/lib/brakeman/report/report_hash.rb +1 -1
  74. data/lib/brakeman/report/report_html.rb +2 -2
  75. data/lib/brakeman/report/report_json.rb +1 -24
  76. data/lib/brakeman/report/report_table.rb +20 -4
  77. data/lib/brakeman/report/report_tabs.rb +1 -1
  78. data/lib/brakeman/report/report_text.rb +6 -7
  79. data/lib/brakeman/rescanner.rb +13 -12
  80. data/lib/brakeman/scanner.rb +19 -14
  81. data/lib/brakeman/tracker.rb +30 -6
  82. data/lib/brakeman/tracker/collection.rb +4 -3
  83. data/lib/brakeman/tracker/config.rb +44 -73
  84. data/lib/brakeman/tracker/constants.rb +2 -1
  85. data/lib/brakeman/util.rb +1 -147
  86. data/lib/brakeman/version.rb +1 -1
  87. data/lib/brakeman/warning.rb +27 -13
  88. data/lib/brakeman/warning_codes.rb +4 -0
  89. data/lib/ruby_parser/bm_sexp.rb +7 -2
  90. data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
  91. metadata +27 -22
@@ -13,9 +13,9 @@ module Brakeman::ModuleHelper
13
13
 
14
14
  if @tracker.libs[name]
15
15
  @current_module = @tracker.libs[name]
16
- @current_module.add_file @file_name, exp
16
+ @current_module.add_file @current_file, exp
17
17
  else
18
- @current_module = tracker_class.new name, parent, @file_name, exp, @tracker
18
+ @current_module = tracker_class.new name, parent, @current_file, exp, @tracker
19
19
  @tracker.libs[name] = @current_module
20
20
  end
21
21
 
@@ -45,9 +45,9 @@ module Brakeman::ModuleHelper
45
45
 
46
46
  if collection[name]
47
47
  @current_class = collection[name]
48
- @current_class.add_file @file_name, exp
48
+ @current_class.add_file @current_file, exp
49
49
  else
50
- @current_class = tracker_class.new name, parent, @file_name, exp, @tracker
50
+ @current_class = tracker_class.new name, parent, @current_file, exp, @tracker
51
51
  collection[name] = @current_class
52
52
  end
53
53
 
@@ -85,9 +85,9 @@ module Brakeman::ModuleHelper
85
85
  @current_method = nil
86
86
 
87
87
  if @current_class
88
- @current_class.add_method @visibility, name, res, @file_name
88
+ @current_class.add_method @visibility, name, res, @current_file
89
89
  elsif @current_module
90
- @current_module.add_method @visibility, name, res, @file_name
90
+ @current_module.add_method @visibility, name, res, @current_file
91
91
  end
92
92
  res
93
93
  end
@@ -101,9 +101,9 @@ module Brakeman::ModuleHelper
101
101
  @current_method = nil
102
102
 
103
103
  if @current_class
104
- @current_class.add_method @visibility, name, res, @file_name
104
+ @current_class.add_method @visibility, name, res, @current_file
105
105
  elsif @current_module
106
- @current_module.add_method @visibility, name, res, @file_name
106
+ @current_module.add_method @visibility, name, res, @current_file
107
107
  end
108
108
 
109
109
  res
@@ -73,10 +73,10 @@ module Brakeman::ProcessorHelper
73
73
  end
74
74
  end
75
75
 
76
- def current_file_name
76
+ def current_file
77
77
  case
78
- when @file_name
79
- @file_name
78
+ when @current_file
79
+ @current_file
80
80
  when @current_class.is_a?(Brakeman::Collection)
81
81
  @current_class.file
82
82
  when @current_module.is_a?(Brakeman::Collection)
@@ -27,9 +27,9 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BasicProcessor
27
27
  end
28
28
 
29
29
  #Use this method to process configuration file
30
- def process_config src, file_name
31
- @file_name = file_name
32
- res = Brakeman::ConfigAliasProcessor.new.process_safely(src, nil, file_name)
30
+ def process_config src, current_file
31
+ @current_file = current_file
32
+ res = Brakeman::ConfigAliasProcessor.new.process_safely(src, nil, current_file)
33
33
  process res
34
34
  end
35
35
 
@@ -75,7 +75,7 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BasicProcessor
75
75
  def process_cdecl exp
76
76
  #Set Rails version required
77
77
  if exp.lhs == :RAILS_GEM_VERSION
78
- @tracker.config.rails_version = exp.rhs.value
78
+ @tracker.config.set_rails_version exp.rhs.value
79
79
  end
80
80
 
81
81
  exp
@@ -16,7 +16,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BasicProcessor
16
16
  @prefix = [] #Controller name prefix (a module name, usually)
17
17
  @current_controller = nil
18
18
  @with_options = nil #For use inside map.with_options
19
- @file_name = "config/routes.rb"
19
+ @current_file = "config/routes.rb"
20
20
  end
21
21
 
22
22
  #Call this with parsed route file information.
@@ -24,7 +24,7 @@ class Brakeman::Rails2RoutesProcessor < Brakeman::BasicProcessor
24
24
  #This method first calls RouteAliasProcessor#process_safely on the +exp+,
25
25
  #so it does not modify the +exp+.
26
26
  def process_routes exp
27
- process Brakeman::RouteAliasProcessor.new.process_safely(exp, nil, @file_name)
27
+ process Brakeman::RouteAliasProcessor.new.process_safely(exp, nil, @current_file)
28
28
  end
29
29
 
30
30
  #Looking for mapping of routes
@@ -24,9 +24,9 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
24
24
  end
25
25
 
26
26
  #Use this method to process configuration file
27
- def process_config src, file_name
28
- @file_name = file_name
29
- res = Brakeman::AliasProcessor.new(@tracker).process_safely(src, nil, @file_name)
27
+ def process_config src, current_file
28
+ @current_file = current_file
29
+ res = Brakeman::AliasProcessor.new(@tracker).process_safely(src, nil, @current_file)
30
30
  process res
31
31
  end
32
32
 
@@ -17,11 +17,11 @@ class Brakeman::Rails3RoutesProcessor < Brakeman::BasicProcessor
17
17
  @current_controller = nil
18
18
  @with_options = nil #For use inside map.with_options
19
19
  @controller_block = false
20
- @file_name = "config/routes.rb"
20
+ @current_file = "config/routes.rb"
21
21
  end
22
22
 
23
23
  def process_routes exp
24
- process Brakeman::AliasProcessor.new.process_safely(exp, nil, @file_name)
24
+ process Brakeman::AliasProcessor.new.process_safely(exp, nil, @current_file)
25
25
  end
26
26
 
27
27
  def process_call exp
@@ -36,7 +36,7 @@ module Brakeman::RenderHelper
36
36
 
37
37
  #Determines file name for partial and then processes it
38
38
  def process_partial name, args, line
39
- if name == "" or !(string? name or symbol? name)
39
+ if !(string? name or symbol? name) or name.value == ""
40
40
  return
41
41
  end
42
42
 
@@ -148,7 +148,7 @@ module Brakeman::RenderHelper
148
148
  #This information will be stored in tracker.templates, but with a name
149
149
  #specifying this particular route. The original source should remain
150
150
  #pristine (so it can be processed within other environments).
151
- @tracker.processor.process_template name, src, template.type, called_from
151
+ @tracker.processor.process_template name, src, template.type, called_from, template.file
152
152
  end
153
153
  end
154
154
 
@@ -83,7 +83,7 @@ module Brakeman
83
83
  end
84
84
 
85
85
  def map &block
86
- @path.map &block
86
+ @path.map(&block)
87
87
  end
88
88
 
89
89
  def to_a
@@ -114,6 +114,23 @@ module Brakeman
114
114
  JSON.generate(@path)
115
115
  end
116
116
 
117
+ def with_relative_paths
118
+ @path.map do |loc|
119
+ r = loc.dup
120
+
121
+ if r[:file]
122
+ r[:file] = r[:file].relative
123
+ end
124
+
125
+ if r[:rendered] and r[:rendered][:file]
126
+ r[:rendered] = r[:rendered].dup
127
+ r[:rendered][:file] = r[:rendered][:file].relative
128
+ end
129
+
130
+ r
131
+ end
132
+ end
133
+
117
134
  def initialize_copy original
118
135
  @path = original.path.dup
119
136
  self
@@ -9,15 +9,15 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
9
9
 
10
10
  def initialize tracker
11
11
  super
12
- @file_name = nil
12
+ @current_file = nil
13
13
  @alias_processor = Brakeman::AliasProcessor.new tracker
14
14
  @current_module = nil
15
15
  @current_class = nil
16
16
  @initializer_env = nil
17
17
  end
18
18
 
19
- def process_library src, file_name = nil
20
- @file_name = file_name
19
+ def process_library src, current_file = @current_file
20
+ @current_file = current_file
21
21
  process src
22
22
  end
23
23
 
@@ -41,10 +41,10 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
41
41
 
42
42
  if @current_class
43
43
  exp.body = process_all! exp.body
44
- @current_class.add_method :public, exp.method_name, exp, @file_name
44
+ @current_class.add_method :public, exp.method_name, exp, @current_file
45
45
  elsif @current_module
46
46
  exp.body = process_all! exp.body
47
- @current_module.add_method :public, exp.method_name, exp, @file_name
47
+ @current_module.add_method :public, exp.method_name, exp, @current_file
48
48
  end
49
49
 
50
50
  exp
@@ -12,24 +12,23 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
12
12
  @current_method = nil
13
13
  @current_module = nil
14
14
  @visibility = :public
15
- @file_name = nil
15
+ @current_file = nil
16
16
  end
17
17
 
18
18
  #Process model source
19
- def process_model src, file_name = nil
20
- @file_name = file_name
19
+ def process_model src, current_file = @current_file
20
+ @current_file = current_file
21
21
  process src
22
22
  end
23
23
 
24
24
  #s(:class, NAME, PARENT, BODY)
25
25
  def process_class exp
26
26
  name = class_name(exp.class_name)
27
- parent = class_name(exp.parent_name)
28
27
 
29
28
  #If inside an inner class we treat it as a library.
30
29
  if @current_class
31
30
  Brakeman.debug "[Notice] Treating inner class as library: #{name}"
32
- Brakeman::LibraryProcessor.new(@tracker).process_library exp, @file_name
31
+ Brakeman::LibraryProcessor.new(@tracker).process_library exp, @current_file
33
32
  return exp
34
33
  end
35
34
 
@@ -8,6 +8,11 @@ require 'brakeman/util'
8
8
  class Brakeman::OutputProcessor < Ruby2Ruby
9
9
  include Brakeman::Util
10
10
 
11
+ def initialize *args
12
+ super
13
+ @user_input = nil
14
+ end
15
+
11
16
  #Copies +exp+ and then formats it.
12
17
  def format exp, user_input = nil, &block
13
18
  @user_input = user_input
@@ -14,25 +14,52 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
14
14
  def initialize tracker, template, called_from = nil
15
15
  super tracker
16
16
  @template = template
17
+ @current_file = template.file
17
18
  @called_from = called_from
18
19
  end
19
20
 
20
21
  #Process template
21
- def process_template name, args, _, line = nil, file_name = nil
22
- @file_name = file_name || relative_path(@template.file || @tracker.templates[@template.name])
23
-
22
+ def process_template name, args, _, line = nil
24
23
  if @called_from
25
24
  if @called_from.include_template? name
26
25
  Brakeman.debug "Skipping circular render from #{@template.name} to #{name}"
27
26
  return
28
27
  end
29
28
 
30
- super name, args, @called_from.dup.add_template_render(@template.name, line, @file_name), line
29
+ super name, args, @called_from.dup.add_template_render(@template.name, line, @current_file), line
30
+ else
31
+ super name, args, Brakeman::RenderPath.new.add_template_render(@template.name, line, @current_file), line
32
+ end
33
+ end
34
+
35
+ def process_lasgn exp
36
+ if exp.lhs == :haml_temp or haml_capture? exp.rhs
37
+ exp.rhs = process exp.rhs
38
+
39
+ # Avoid propagating contents of block
40
+ if node_type? exp.rhs, :iter
41
+ new_exp = exp.dup
42
+ new_exp.rhs = exp.rhs.block_call
43
+
44
+ super new_exp
45
+
46
+ exp # Still save the original, though
47
+ else
48
+ super exp
49
+ end
31
50
  else
32
- super name, args, Brakeman::RenderPath.new.add_template_render(@template.name, line, @file_name), line
51
+ super exp
33
52
  end
34
53
  end
35
54
 
55
+ HAML_CAPTURE = [:capture, :capture_haml]
56
+
57
+ def haml_capture? exp
58
+ node_type? exp, :iter and
59
+ call? exp.block_call and
60
+ HAML_CAPTURE.include? exp.block_call.method
61
+ end
62
+
36
63
  #Determine template name
37
64
  def template_name name
38
65
  if !name.to_s.include?('/') && @template.name.to_s.include?('/')
@@ -5,10 +5,10 @@ require 'brakeman/tracker/template'
5
5
  class Brakeman::TemplateProcessor < Brakeman::BaseProcessor
6
6
 
7
7
  #Initializes template information.
8
- def initialize tracker, template_name, called_from = nil, file_name = nil
9
- super(tracker)
10
- @current_template = Brakeman::Template.new template_name, called_from, file_name, tracker
11
- @file_name = file_name
8
+ def initialize tracker, template_name, called_from = nil, current_file = nil
9
+ super(tracker)
10
+ @current_template = Brakeman::Template.new template_name, called_from, current_file, tracker
11
+ @current_file = @current_template.file
12
12
 
13
13
  if called_from
14
14
  template_name = (template_name.to_s + "." + called_from.to_s).to_sym
@@ -61,9 +61,9 @@ class Brakeman::TemplateProcessor < Brakeman::BaseProcessor
61
61
  branches = [arg.then_clause, arg.else_clause].compact
62
62
 
63
63
  if branches.empty?
64
- s(:nil)
64
+ s(:nil).line(arg.line)
65
65
  elsif branches.length == 2
66
- Sexp.new(:or, *branches)
66
+ Sexp.new(:or, *branches).line(arg.line)
67
67
  else
68
68
  branches.first
69
69
  end
@@ -77,9 +77,13 @@ class Brakeman::TemplateProcessor < Brakeman::BaseProcessor
77
77
  end
78
78
 
79
79
  def add_output output, type = :output
80
- s = Sexp.new(type, output)
81
- s.line(output.line)
82
- @current_template.add_output s
83
- s
80
+ if node_type? output, :or
81
+ Sexp.new(:or, add_output(output.lhs, type), add_output(output.rhs, type)).line(output.line)
82
+ else
83
+ s = Sexp.new(type, output)
84
+ s.line(output.line)
85
+ @current_template.add_output s
86
+ s
87
+ end
84
88
  end
85
89
  end
@@ -8,8 +8,8 @@ class Brakeman::Report
8
8
 
9
9
  VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate, :to_plain, :to_text]
10
10
 
11
- def initialize app_tree, tracker
12
- @app_tree = app_tree
11
+ def initialize tracker
12
+ @app_tree = tracker.app_tree
13
13
  @tracker = tracker
14
14
  end
15
15
 
@@ -83,6 +83,6 @@ class Brakeman::Report
83
83
  alias to_s to_text
84
84
 
85
85
  def generate reporter
86
- reporter.new(@app_tree, @tracker).generate_report
86
+ reporter.new(@tracker).generate_report
87
87
  end
88
88
  end
@@ -22,6 +22,7 @@ module Brakeman
22
22
  def filter_ignored
23
23
  @shown_warnings = []
24
24
  @ignored_warnings = []
25
+ @used_fingerprints = Set.new
25
26
 
26
27
  @new_warnings.each do |w|
27
28
  if ignored? w
@@ -112,9 +113,7 @@ module Brakeman
112
113
  def save_to_file warnings, file = @file
113
114
  warnings = warnings.map do |w|
114
115
  if w.is_a? Warning
115
- w_hash = w.to_hash
116
- w_hash[:file] = w.relative_path
117
- w = w_hash
116
+ w = w.to_hash(absolute_paths: false)
118
117
  end
119
118
 
120
119
  w[:note] = @notes[w[:fingerprint]] || ""
@@ -280,9 +280,9 @@ q - Quit, do not update ignored warnings
280
280
  say warning.format_code
281
281
  end
282
282
 
283
- if warning.relative_path
283
+ if warning.file
284
284
  label "File"
285
- say warning.relative_path
285
+ say warning.file.relative
286
286
  end
287
287
 
288
288
  if warning.line
@@ -4,6 +4,7 @@ module Brakeman
4
4
  @tracker = tracker
5
5
  @pager = pager
6
6
  @output = output
7
+ @less_available = @less_options = nil
7
8
  end
8
9
 
9
10
  def page_report report, format
@@ -13,8 +13,8 @@ class Brakeman::Report::Base
13
13
 
14
14
  TEXT_CONFIDENCE = Brakeman::Warning::TEXT_CONFIDENCE
15
15
 
16
- def initialize app_tree, tracker
17
- @app_tree = app_tree
16
+ def initialize tracker
17
+ @app_tree = tracker.app_tree
18
18
  @tracker = tracker
19
19
  @checks = tracker.checks
20
20
  @ignore_filter = tracker.ignored_filter
@@ -123,16 +123,52 @@ class Brakeman::Report::Base
123
123
  Set.new(tracker.templates.map {|k,v| v.name.to_s[/[^.]+/]}).length
124
124
  end
125
125
 
126
- def warning_file warning, absolute = @tracker.options[:absolute_paths]
126
+ def absolute_paths?
127
+ @tracker.options[:absolute_paths]
128
+ end
129
+
130
+ def warning_file warning
127
131
  return nil if warning.file.nil?
128
132
 
129
- if absolute
130
- warning.file
133
+ if absolute_paths?
134
+ warning.file.absolute
131
135
  else
132
- relative_path warning.file
136
+ warning.file.relative
133
137
  end
134
138
  end
135
139
 
140
+ #Return array of lines surrounding the warning location from the original
141
+ #file.
142
+ def context_for warning
143
+ file = warning.file
144
+ context = []
145
+ return context unless warning.line and file and file.exists?
146
+
147
+ current_line = 0
148
+ start_line = warning.line - 5
149
+ end_line = warning.line + 5
150
+
151
+ start_line = 1 if start_line < 0
152
+
153
+ File.open file do |f|
154
+ f.each_line do |line|
155
+ current_line += 1
156
+
157
+ next if line.strip == ""
158
+
159
+ if current_line > end_line
160
+ break
161
+ end
162
+
163
+ if current_line >= start_line
164
+ context << [current_line, line]
165
+ end
166
+ end
167
+ end
168
+
169
+ context
170
+ end
171
+
136
172
  def rails_version
137
173
  case
138
174
  when tracker.config.rails_version
@@ -145,4 +181,13 @@ class Brakeman::Report::Base
145
181
  "Unknown"
146
182
  end
147
183
  end
184
+
185
+ def github_url file, line=nil
186
+ if repo_url = @tracker.options[:github_url] and file
187
+ url = "#{repo_url}/#{file.relative}"
188
+ url << "#L#{line}" if line
189
+ else
190
+ nil
191
+ end
192
+ end
148
193
  end