brakeman-lib 5.0.1 → 5.0.2

Sign up to get free protection for your applications and to get access to all the features.
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