brakeman-lib 5.0.1 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3dc2339132662438de0f96b04c56b445ba69e60ca3e0b58db4c1e3e803e6c1b
4
- data.tar.gz: c1b340eb481e9b182f4bed44d709656fde4405a04bc11c63681b06ad0fa4ec6c
3
+ metadata.gz: d16867dd5c48de9ec2975e1dc420e3a5154939361988d70c4217f251881452ed
4
+ data.tar.gz: f5cae624d83a1298fb3f07108c76d1f55c756404d6998fccfd9e5fcfe69a068e
5
5
  SHA512:
6
- metadata.gz: fc6e90801ce54677dc85db3c6d0b1b70414462cb54629e4af369007ac5477e0f7f31bafebea54a0120a0f3316a582686e65a9ad4851c51ea50e531f3b8936bb2
7
- data.tar.gz: 4c0184c78d871d814d5a098526d785bdd62efc2a898bbbc0c3f2d71af6fd4250cfe9ed5e49fe8c42b3c84d93887ebca71729a3d934f324a93df6652d276ba307
6
+ metadata.gz: f8724b266165ef9ed4ad926432e0786b955cb2e98b56e7100354b0ad04a51cc0eaa139343a769980852ae615bd209e8854f6f83616b0703d3a2aaf08229860c6
7
+ data.tar.gz: 963f46a856d6f943c74c6aca8ec3f3dc61ae3d82758fbfdda63bb4fc789ff95535f49cc73f9abef4cf1553323606d4fd50c8a03082178a6dd3cea0883e544a40
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 5.0.2 - 2021-06-07
2
+
3
+ * Fix Loofah version check
4
+
1
5
  # 5.0.1 - 2021-04-27
2
6
 
3
7
  * Detect `::Rails.application.configure` too
data/lib/brakeman.rb CHANGED
@@ -250,6 +250,8 @@ module Brakeman
250
250
  [:to_sarif]
251
251
  when :sonar, :to_sonar
252
252
  [:to_sonar]
253
+ when :github, :to_github
254
+ [:to_github]
253
255
  else
254
256
  [:to_text]
255
257
  end
@@ -283,6 +285,8 @@ module Brakeman
283
285
  :to_sarif
284
286
  when /\.sonar$/i
285
287
  :to_sonar
288
+ when /\.github$/i
289
+ :to_github
286
290
  else
287
291
  :to_text
288
292
  end
@@ -26,7 +26,7 @@ class Brakeman::CheckDetailedExceptions < Brakeman::BaseCheck
26
26
  def check_detailed_exceptions
27
27
  tracker.controllers.each do |_name, controller|
28
28
  controller.methods_public.each do |method_name, definition|
29
- src = definition[:src]
29
+ src = definition.src
30
30
  body = src.body.last
31
31
  next unless body
32
32
 
@@ -10,7 +10,7 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
10
10
  #Process calls
11
11
  def run_check
12
12
  Brakeman.debug "Finding eval-like calls"
13
- calls = tracker.find_call :method => [:eval, :instance_eval, :class_eval, :module_eval]
13
+ calls = tracker.find_call methods: [:eval, :instance_eval, :class_eval, :module_eval], nested: true
14
14
 
15
15
  Brakeman.debug "Processing eval-like calls"
16
16
  calls.each do |call|
@@ -90,7 +90,8 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
90
90
  def loofah_vulnerable_cve_2018_8048?
91
91
  loofah_version = tracker.config.gem_version(:loofah)
92
92
 
93
- loofah_version and loofah_version < "2.2.1"
93
+ # 2.2.1 is fix version
94
+ loofah_version and version_between?("0.0.0", "2.2.0", loofah_version)
94
95
  end
95
96
 
96
97
  def warn_sanitizer_cve cve, link, upgrade_version
@@ -572,7 +572,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
572
572
  end
573
573
 
574
574
  IGNORE_METHODS_IN_SQL = Set[:id, :merge_conditions, :table_name, :quoted_table_name,
575
- :quoted_primary_key, :to_i, :to_f, :sanitize_sql, :sanitize_sql_array,
575
+ :quoted_primary_key, :to_i, :to_f, :sanitize_sql, :sanitize_sql_array, :sanitize_sql_like,
576
576
  :sanitize_sql_for_assignment, :sanitize_sql_for_conditions, :sanitize_sql_hash,
577
577
  :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
578
578
  :to_sql, :sanitize, :primary_key, :table_name_prefix, :table_name_suffix,
@@ -592,7 +592,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
592
592
  IGNORE_METHODS_IN_SQL.include? exp.method or
593
593
  quote_call? exp or
594
594
  arel? exp or
595
- exp.method.to_s.end_with? "_id"
595
+ exp.method.to_s.end_with? "_id" or
596
+ number_target? exp
596
597
  end
597
598
  when :if
598
599
  safe_value? exp.then_clause and safe_value? exp.else_clause
@@ -695,4 +696,16 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
695
696
  active_record_models.include? klass
696
697
  end
697
698
  end
699
+
700
+ def number_target? exp
701
+ return unless call? exp
702
+
703
+ if number? exp.target
704
+ true
705
+ elsif call? exp.target
706
+ number_target? exp.target
707
+ else
708
+ false
709
+ end
710
+ end
698
711
  end
@@ -32,7 +32,7 @@ class Brakeman::CheckVerbConfusion < Brakeman::BaseCheck
32
32
  return
33
33
  end
34
34
 
35
- process method[:src]
35
+ process method.src
36
36
  end
37
37
 
38
38
  def process_if exp
@@ -1,3 +1,5 @@
1
+ require 'parallel'
2
+
1
3
  module Brakeman
2
4
  ASTFile = Struct.new(:path, :ast)
3
5
 
@@ -13,21 +15,46 @@ module Brakeman
13
15
  end
14
16
 
15
17
  def parse_files list
16
- read_files list do |path, contents|
17
- if ast = parse_ruby(contents, path.relative)
18
- ASTFile.new(path, ast)
18
+ # Parse the files in parallel.
19
+ # By default, the parsing will be in separate processes.
20
+ # So we map the result to ASTFiles and/or Exceptions
21
+ # then partition them into ASTFiles and Exceptions
22
+ # and add the Exceptions to @errors
23
+ #
24
+ # Basically just a funky way to deal with two possible
25
+ # return types that are returned from isolated processes.
26
+ #
27
+ # Note this method no longer uses read_files
28
+ @file_list, new_errors = Parallel.map(list) do |file_name|
29
+ file_path = @app_tree.file_path(file_name)
30
+ contents = file_path.read
31
+
32
+ begin
33
+ if ast = parse_ruby(contents, file_path.relative)
34
+ ASTFile.new(file_name, ast)
35
+ end
36
+ rescue Exception => e
37
+ e
19
38
  end
39
+ end.compact.partition do |result|
40
+ result.is_a? ASTFile
20
41
  end
42
+
43
+ errors.concat new_errors
21
44
  end
22
45
 
23
46
  def read_files list
24
47
  list.each do |path|
25
48
  file = @app_tree.file_path(path)
26
49
 
27
- result = yield file, file.read
50
+ begin
51
+ result = yield file, file.read
28
52
 
29
- if result
30
- @file_list << result
53
+ if result
54
+ @file_list << result
55
+ end
56
+ rescue Exception => e
57
+ @errors << e
31
58
  end
32
59
  end
33
60
  end
@@ -42,17 +69,12 @@ module Brakeman
42
69
  Brakeman.debug "Parsing #{path}"
43
70
  RubyParser.new.parse input, path, @timeout
44
71
  rescue Racc::ParseError => e
45
- error e.exception(e.message + "\nCould not parse #{path}")
72
+ raise e.exception(e.message + "\nCould not parse #{path}")
46
73
  rescue Timeout::Error => e
47
- error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
74
+ raise Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
48
75
  rescue => e
49
- error e.exception(e.message + "\nWhile processing #{path}")
76
+ raise e.exception(e.message + "\nWhile processing #{path}")
50
77
  end
51
78
  end
52
-
53
- def error exception
54
- @errors << exception
55
- nil
56
- end
57
79
  end
58
80
  end
@@ -233,7 +233,7 @@ module Brakeman::Options
233
233
 
234
234
  opts.on "-f",
235
235
  "--format TYPE",
236
- [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar],
236
+ [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar, :github],
237
237
  "Specify output formats. Default is text" do |type|
238
238
 
239
239
  type = "s" if type == :text
@@ -220,13 +220,28 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
220
220
  exp = math_op(:+, target, first_arg, exp)
221
221
  end
222
222
  when :-, :*, :/
223
- exp = math_op(method, target, first_arg, exp)
223
+ if method == :* and array? target
224
+ if string? first_arg
225
+ exp = process_array_join(target, first_arg)
226
+ end
227
+ else
228
+ exp = math_op(method, target, first_arg, exp)
229
+ end
224
230
  when :[]
225
231
  if array? target
226
232
  exp = process_array_access(target, exp.args, exp)
227
233
  elsif hash? target
228
234
  exp = process_hash_access(target, first_arg, exp)
229
235
  end
236
+ when :fetch
237
+ if array? target
238
+ # Not dealing with default value
239
+ # so just pass in first argument, but process_array_access expects
240
+ # an array of arguments.
241
+ exp = process_array_access(target, [first_arg], exp)
242
+ elsif hash? target
243
+ exp = process_hash_access(target, first_arg, exp)
244
+ end
230
245
  when :merge!, :update
231
246
  if hash? target and hash? first_arg
232
247
  target = process_hash_merge! target, first_arg
@@ -266,6 +281,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
266
281
  target = find_push_target(target_var)
267
282
  env[target] = exp unless target.nil? # Happens in TemplateAliasProcessor
268
283
  end
284
+ when :push
285
+ if array? target
286
+ target << first_arg
287
+ env[target_var] = target
288
+ return target
289
+ end
269
290
  when :first
270
291
  if array? target and first_arg.nil? and sexp? target[1]
271
292
  exp = target[1]
@@ -279,7 +300,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
279
300
  exp = target
280
301
  end
281
302
  when :join
282
- if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
303
+ if array? target and (string? first_arg or first_arg.nil?)
283
304
  exp = process_array_join(target, first_arg)
284
305
  end
285
306
  when :!
@@ -287,6 +308,15 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
287
308
  if call? target and target.method == :!
288
309
  exp = s(:or, s(:true).line(exp.line), s(:false).line(exp.line)).line(exp.line)
289
310
  end
311
+ when :values
312
+ # Hash literal
313
+ if node_type? target, :hash
314
+ exp = hash_values(target)
315
+ end
316
+ when :values_at
317
+ if hash? target
318
+ exp = hash_values_at target, exp.args
319
+ end
290
320
  end
291
321
 
292
322
  exp
@@ -294,6 +324,11 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
294
324
 
295
325
  # Painful conversion of Array#join into string interpolation
296
326
  def process_array_join array, join_str
327
+ # Empty array
328
+ if array.length == 1
329
+ return s(:str, '').line(array.line)
330
+ end
331
+
297
332
  result = s().line(array.line)
298
333
 
299
334
  join_value = if string? join_str
@@ -302,8 +337,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
302
337
  nil
303
338
  end
304
339
 
305
- array[1..-2].each do |e|
306
- result << join_item(e, join_value)
340
+ if array.length > 2
341
+ array[1..-2].each do |e|
342
+ result << join_item(e, join_value)
343
+ end
307
344
  end
308
345
 
309
346
  result << join_item(array.last, nil)
@@ -332,7 +369,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
332
369
  result.unshift combined_first
333
370
 
334
371
  # Have to fix up strings that follow interpolation
335
- result.reduce(s(:dstr).line(array.line)) do |memo, e|
372
+ string = result.reduce(s(:dstr).line(array.line)) do |memo, e|
336
373
  if string? e and node_type? memo.last, :evstr
337
374
  e.value = "#{join_value}#{e.value}"
338
375
  elsif join_value and node_type? memo.last, :evstr and node_type? e, :evstr
@@ -341,6 +378,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
341
378
 
342
379
  memo << e
343
380
  end
381
+
382
+ # Convert (:dstr, "hello world")
383
+ # to (:str, "hello world")
384
+ if string.length == 2 and string.last.is_a? String
385
+ string[0] = :str
386
+ end
387
+
388
+ string
344
389
  end
345
390
 
346
391
  def join_item item, join_value
@@ -1013,8 +1058,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
1013
1058
  method_name = call.method
1014
1059
 
1015
1060
  #Look for helper methods and see if we can get a return value
1016
- if found_method = find_method(method_name, @current_class)
1017
- helper = found_method[:method]
1061
+ if found_method = tracker.find_method(method_name, @current_class)
1062
+ helper = found_method.src
1018
1063
 
1019
1064
  if sexp? helper
1020
1065
  value = process_helper_method helper, call.args
@@ -51,7 +51,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
51
51
  #Need to process the method like it was in a controller in order
52
52
  #to get the renders set
53
53
  processor = Brakeman::ControllerProcessor.new(@tracker, mixin.file)
54
- method = mixin.get_method(name)[:src].deep_clone
54
+ method = mixin.get_method(name).src.deep_clone
55
55
 
56
56
  if node_type? method, :defn
57
57
  method = processor.process_defn method
@@ -143,16 +143,16 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
143
143
  #Basically, adds any instance variable assignments to the environment.
144
144
  #TODO: method arguments?
145
145
  def process_before_filter name
146
- filter = find_method name, @current_class
146
+ filter = tracker.find_method name, @current_class
147
147
 
148
148
  if filter.nil?
149
149
  Brakeman.debug "[Notice] Could not find filter #{name}"
150
150
  return
151
151
  end
152
152
 
153
- method = filter[:method]
153
+ method = filter.src
154
154
 
155
- if ivars = @tracker.filter_cache[[filter[:controller], name]]
155
+ if ivars = @tracker.filter_cache[[filter.owner, name]]
156
156
  ivars.each do |variable, value|
157
157
  env[variable] = value
158
158
  end
@@ -162,7 +162,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
162
162
 
163
163
  ivars = processor.only_ivars(:include_request_vars).all
164
164
 
165
- @tracker.filter_cache[[filter[:controller], name]] = ivars
165
+ @tracker.filter_cache[[filter.owner, name]] = ivars
166
166
 
167
167
  ivars.each do |variable, value|
168
168
  env[variable] = value
@@ -182,7 +182,7 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
182
182
  # method as the line number
183
183
  if line.nil? and controller = @tracker.controllers[@current_class]
184
184
  if meth = controller.get_method(@current_method)
185
- if line = meth[:src] && meth[:src].last && meth[:src].last.line
185
+ if line = meth.src && meth.src.last && meth.src.last.line
186
186
  line += 1
187
187
  else
188
188
  line = 1
@@ -241,41 +241,4 @@ class Brakeman::ControllerAliasProcessor < Brakeman::AliasProcessor
241
241
  []
242
242
  end
243
243
  end
244
-
245
- #Finds a method in the given class or a parent class
246
- #
247
- #Returns nil if the method could not be found.
248
- #
249
- #If found, returns hash table with controller name and method sexp.
250
- def find_method method_name, klass
251
- return nil if sexp? method_name
252
- method_name = method_name.to_sym
253
-
254
- if method = @method_cache[method_name]
255
- return method
256
- end
257
-
258
- controller = @tracker.controllers[klass]
259
- controller ||= @tracker.libs[klass]
260
-
261
- if klass and controller
262
- method = controller.get_method method_name
263
-
264
- if method.nil?
265
- controller.includes.each do |included|
266
- method = find_method method_name, included
267
- if method
268
- @method_cache[method_name] = method
269
- return method
270
- end
271
- end
272
-
273
- @method_cache[method_name] = find_method method_name, controller.parent
274
- else
275
- @method_cache[method_name] = { :controller => controller.name, :method => method[:src] }
276
- end
277
- else
278
- nil
279
- end
280
- end
281
244
  end
@@ -76,6 +76,8 @@ module Brakeman
76
76
 
77
77
  #Have to do this because first element is :array and we have to skip it
78
78
  array[1..-1][index] or original_exp
79
+ elsif all_literals? array
80
+ safe_literal(array.line)
79
81
  else
80
82
  original_exp
81
83
  end
@@ -92,5 +94,13 @@ module Brakeman
92
94
  original_exp
93
95
  end
94
96
  end
97
+
98
+ def hash_values_at hash, keys
99
+ values = keys.map do |key|
100
+ process_hash_access hash, key
101
+ end
102
+
103
+ Sexp.new(:array).concat(values).line(hash.line)
104
+ end
95
105
  end
96
106
  end
@@ -54,6 +54,15 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
54
54
 
55
55
  def process_call exp
56
56
  if process_call_defn? exp
57
+ exp
58
+ elsif @current_method.nil? and exp.target.nil? and (@current_class or @current_module)
59
+ # Methods called inside class / module
60
+ case exp.method
61
+ when :include
62
+ module_name = class_name(exp.first_arg)
63
+ (@current_class || @current_module).add_include module_name
64
+ end
65
+
57
66
  exp
58
67
  else
59
68
  process_default exp
@@ -6,7 +6,7 @@ require 'brakeman/report/report_base'
6
6
  class Brakeman::Report
7
7
  attr_reader :tracker
8
8
 
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, :to_junit]
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, :to_junit, :to_github]
10
10
 
11
11
  def initialize tracker
12
12
  @app_tree = tracker.app_tree
@@ -48,6 +48,9 @@ class Brakeman::Report
48
48
  when :to_sonar
49
49
  require_report 'sonar'
50
50
  Brakeman::Report::Sonar
51
+ when :to_github
52
+ require_report 'github'
53
+ Brakeman::Report::Github
51
54
  else
52
55
  raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
53
56
  end
@@ -62,7 +62,7 @@ module Brakeman
62
62
  process_warnings
63
63
  end
64
64
 
65
- m.choice "Hide previously ignored warnings" do
65
+ m.choice "Inspect new warnings" do
66
66
  @skip_ignored = true
67
67
  pre_show_help
68
68
  process_warnings
@@ -0,0 +1,31 @@
1
+ # Github Actions Formatter
2
+ # Formats warnings as workflow commands to create annotations in GitHub UI
3
+ class Brakeman::Report::Github < Brakeman::Report::Base
4
+ def generate_report
5
+ # @see https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
6
+ errors.concat(warnings).join("\n")
7
+ end
8
+
9
+ def warnings
10
+ all_warnings
11
+ .map { |warning| "::warning file=#{warning_file(warning)},line=#{warning.line}::#{warning.message}" }
12
+ end
13
+
14
+ def errors
15
+ tracker.errors.map do |error|
16
+ if error[:exception].is_a?(Racc::ParseError)
17
+ # app/services/balance.rb:4 :: parse error on value "..." (tDOT3)
18
+ file, line = error[:exception].message.split(':').map(&:strip)[0,2]
19
+ "::error file=#{file},line=#{line}::#{clean_message(error[:error])}"
20
+ else
21
+ "::error ::#{clean_message(error[:error])}"
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def clean_message(msg)
29
+ msg.gsub('::','').squeeze(' ')
30
+ end
31
+ end
@@ -353,6 +353,9 @@ class Brakeman::Scanner
353
353
  def parse_ruby_file file
354
354
  fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
355
355
  fp.parse_ruby(file.read, file)
356
+ rescue Exception => e
357
+ tracker.error(e)
358
+ nil
356
359
  end
357
360
  end
358
361
 
@@ -35,6 +35,7 @@ class Brakeman::Tracker
35
35
  #class they are.
36
36
  @models = {}
37
37
  @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, @app_tree.file_path("NOT_REAL.rb"), nil, self)
38
+ @method_cache = {}
38
39
  @routes = {}
39
40
  @initializers = {}
40
41
  @errors = []
@@ -99,8 +100,8 @@ class Brakeman::Tracker
99
100
  classes.each do |set|
100
101
  set.each do |set_name, collection|
101
102
  collection.each_method do |method_name, definition|
102
- src = definition[:src]
103
- yield src, set_name, method_name, definition[:file]
103
+ src = definition.src
104
+ yield src, set_name, method_name, definition.file
104
105
  end
105
106
  end
106
107
  end
@@ -220,6 +221,34 @@ class Brakeman::Tracker
220
221
  nil
221
222
  end
222
223
 
224
+ def find_method method_name, class_name, method_type = :instance
225
+ return nil unless method_name.is_a? Symbol
226
+
227
+ klass = find_class(class_name)
228
+ return nil unless klass
229
+
230
+ cache_key = [klass, method_name, method_type]
231
+
232
+ if method = @method_cache[cache_key]
233
+ return method
234
+ end
235
+
236
+ if method = klass.get_method(method_name, method_type)
237
+ return method
238
+ else
239
+ # Check modules included for method definition
240
+ # TODO: only for instance methods, otherwise check extends!
241
+ klass.includes.each do |included_name|
242
+ if method = find_method(method_name, included_name, method_type)
243
+ return (@method_cache[cache_key] = method)
244
+ end
245
+ end
246
+
247
+ # Not in any included modules, check the parent
248
+ @method_cache[cache_key] = find_method(method_name, klass.parent)
249
+ end
250
+ end
251
+
223
252
  def index_call_sites
224
253
  finder = Brakeman::FindAllCalls.new self
225
254
 
@@ -285,8 +314,8 @@ class Brakeman::Tracker
285
314
  method_sets.each do |set|
286
315
  set.each do |set_name, info|
287
316
  info.each_method do |method_name, definition|
288
- src = definition[:src]
289
- finder.process_source src, :class => set_name, :method => method_name, :file => definition[:file]
317
+ src = definition.src
318
+ finder.process_source src, :class => set_name, :method => method_name, :file => definition.file
290
319
  end
291
320
  end
292
321
  end
@@ -1,4 +1,5 @@
1
1
  require 'brakeman/util'
2
+ require 'brakeman/tracker/method_info'
2
3
 
3
4
  module Brakeman
4
5
  class Collection
@@ -13,6 +14,7 @@ module Brakeman
13
14
  @src = {}
14
15
  @includes = []
15
16
  @methods = { :public => {}, :private => {}, :protected => {} }
17
+ @class_methods = {}
16
18
  @options = {}
17
19
  @tracker = tracker
18
20
 
@@ -46,11 +48,16 @@ module Brakeman
46
48
  end
47
49
 
48
50
  def add_method visibility, name, src, file_name
51
+ meth_info = Brakeman::MethodInfo.new(name, src, self, file_name)
52
+
49
53
  if src.node_type == :defs
54
+ @class_methods[name] = meth_info
55
+
56
+ # TODO fix this weirdness
50
57
  name = :"#{src[1]}.#{name}"
51
58
  end
52
59
 
53
- @methods[visibility][name] = { :src => src, :file => file_name }
60
+ @methods[visibility][name] = meth_info
54
61
  end
55
62
 
56
63
  def each_method
@@ -61,16 +68,31 @@ module Brakeman
61
68
  end
62
69
  end
63
70
 
64
- def get_method name
65
- each_method do |n, info|
66
- if n == name
67
- return info
71
+ def get_method name, type = :instance
72
+ case type
73
+ when :class
74
+ get_class_method name
75
+ when :instance
76
+ get_instance_method name
77
+ else
78
+ raise "Unexpected method type: #{type.inspect}"
79
+ end
80
+ end
81
+
82
+ def get_instance_method name
83
+ @methods.each do |_vis, meths|
84
+ if meths[name]
85
+ return meths[name]
68
86
  end
69
87
  end
70
88
 
71
89
  nil
72
90
  end
73
91
 
92
+ def get_class_method name
93
+ @class_methods[name]
94
+ end
95
+
74
96
  def file
75
97
  @files.first
76
98
  end
@@ -0,0 +1,29 @@
1
+ require 'brakeman/util'
2
+
3
+ module Brakeman
4
+ class MethodInfo
5
+ include Brakeman::Util
6
+
7
+ attr_reader :name, :src, :owner, :file, :type
8
+
9
+ def initialize name, src, owner, file
10
+ @name = name
11
+ @src = src
12
+ @owner = owner
13
+ @file = file
14
+ @type = case src.node_type
15
+ when :defn
16
+ :instance
17
+ when :defs
18
+ :class
19
+ else
20
+ raise "Expected sexp type: #{src.node_type}"
21
+ end
22
+ end
23
+
24
+ # To support legacy code that expected a Hash
25
+ def [] attr
26
+ self.send(attr)
27
+ end
28
+ end
29
+ end
data/lib/brakeman/util.rb CHANGED
@@ -142,6 +142,14 @@ module Brakeman::Util
142
142
  nil
143
143
  end
144
144
 
145
+ def hash_values hash
146
+ values = hash.each_sexp.each_slice(2).map do |_, value|
147
+ value
148
+ end
149
+
150
+ Sexp.new(:array).concat(values).line(hash.line)
151
+ end
152
+
145
153
  #These are never modified
146
154
  PARAMS_SEXP = Sexp.new(:params)
147
155
  SESSION_SEXP = Sexp.new(:session)
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "5.0.1"
2
+ Version = "5.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 5.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-28 00:00:00.000000000 Z
11
+ date: 2021-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.10.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: parallel
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.20'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.20'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: ruby_parser
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -380,6 +394,7 @@ files:
380
394
  - lib/brakeman/report/report_base.rb
381
395
  - lib/brakeman/report/report_codeclimate.rb
382
396
  - lib/brakeman/report/report_csv.rb
397
+ - lib/brakeman/report/report_github.rb
383
398
  - lib/brakeman/report/report_hash.rb
384
399
  - lib/brakeman/report/report_html.rb
385
400
  - lib/brakeman/report/report_json.rb
@@ -409,6 +424,7 @@ files:
409
424
  - lib/brakeman/tracker/constants.rb
410
425
  - lib/brakeman/tracker/controller.rb
411
426
  - lib/brakeman/tracker/library.rb
427
+ - lib/brakeman/tracker/method_info.rb
412
428
  - lib/brakeman/tracker/model.rb
413
429
  - lib/brakeman/tracker/template.rb
414
430
  - lib/brakeman/util.rb