brakeman 5.0.1 → 5.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +4 -0
  3. data/bundle/load.rb +3 -2
  4. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/MIT-LICENSE.txt +20 -0
  5. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel.rb +523 -0
  6. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel/processor_count.rb +42 -0
  7. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel/version.rb +3 -0
  8. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/History.rdoc +19 -0
  9. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/Manifest.txt +2 -0
  10. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/README.rdoc +0 -0
  11. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/compare/normalize.rb +2 -2
  12. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/debugging.md +0 -0
  13. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/rp_extensions.rb +0 -0
  14. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/rp_stringscanner.rb +0 -0
  15. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby20_parser.rb +273 -278
  16. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby20_parser.y +0 -3
  17. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby21_parser.rb +286 -291
  18. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby21_parser.y +0 -3
  19. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby22_parser.rb +292 -297
  20. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby22_parser.y +0 -3
  21. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby23_parser.rb +290 -295
  22. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby23_parser.y +0 -3
  23. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby24_parser.rb +291 -296
  24. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby24_parser.y +0 -3
  25. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby25_parser.rb +292 -297
  26. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby25_parser.y +0 -3
  27. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby26_parser.rb +296 -301
  28. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby26_parser.y +0 -3
  29. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby27_parser.rb +2480 -2528
  30. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby27_parser.y +0 -26
  31. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.rb +7310 -0
  32. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.y +2677 -0
  33. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_lexer.rb +0 -0
  34. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_lexer.rex +0 -0
  35. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_lexer.rex.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_parser.rb +2 -0
  37. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_parser.yy +2 -30
  38. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/lib/ruby_parser_extras.rb +2 -2
  39. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/tools/munge.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.1 → ruby_parser-3.16.0}/tools/ripper.rb +1 -1
  41. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/History.rdoc +6 -0
  42. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/Manifest.txt +0 -0
  43. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/README.rdoc +0 -0
  44. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/composite_sexp_processor.rb +0 -0
  45. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/pt_testcase.rb +2 -2
  46. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/sexp.rb +0 -0
  47. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/sexp_matcher.rb +0 -0
  48. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/sexp_processor.rb +1 -1
  49. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/strict_sexp.rb +0 -0
  50. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.2 → sexp_processor-4.15.3}/lib/unique.rb +0 -0
  51. data/lib/brakeman.rb +4 -0
  52. data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
  53. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  54. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -1
  55. data/lib/brakeman/checks/check_sql.rb +15 -2
  56. data/lib/brakeman/checks/check_verb_confusion.rb +1 -1
  57. data/lib/brakeman/file_parser.rb +36 -14
  58. data/lib/brakeman/options.rb +1 -1
  59. data/lib/brakeman/processors/alias_processor.rb +52 -7
  60. data/lib/brakeman/processors/controller_alias_processor.rb +6 -43
  61. data/lib/brakeman/processors/lib/call_conversion_helper.rb +10 -0
  62. data/lib/brakeman/processors/library_processor.rb +9 -0
  63. data/lib/brakeman/report.rb +4 -1
  64. data/lib/brakeman/report/ignore/interactive.rb +1 -1
  65. data/lib/brakeman/report/report_github.rb +31 -0
  66. data/lib/brakeman/scanner.rb +3 -0
  67. data/lib/brakeman/tracker.rb +33 -4
  68. data/lib/brakeman/tracker/collection.rb +27 -5
  69. data/lib/brakeman/tracker/method_info.rb +29 -0
  70. data/lib/brakeman/util.rb +8 -0
  71. data/lib/brakeman/version.rb +1 -1
  72. metadata +51 -43
@@ -79,10 +79,12 @@ require "ruby24_parser"
79
79
  require "ruby25_parser"
80
80
  require "ruby26_parser"
81
81
  require "ruby27_parser"
82
+ require "ruby30_parser"
82
83
 
83
84
  class RubyParser # HACK
84
85
  VERSIONS.clear # also a HACK caused by racc namespace issues
85
86
 
87
+ class V30 < ::Ruby30Parser; end
86
88
  class V27 < ::Ruby27Parser; end
87
89
  class V26 < ::Ruby26Parser; end
88
90
  class V25 < ::Ruby25Parser; end
@@ -16,6 +16,8 @@ class Ruby25Parser
16
16
  class Ruby26Parser
17
17
  #elif V == 27
18
18
  class Ruby27Parser
19
+ #elif V == 30
20
+ class Ruby30Parser
19
21
  #else
20
22
  fail "version not specified or supported on code generation"
21
23
  #endif
@@ -1064,18 +1066,6 @@ rule
1064
1066
  _, args, _ = val
1065
1067
  result = args
1066
1068
  }
1067
- #if V >= 27
1068
- | tLPAREN2 args_forward rparen
1069
- {
1070
- if (!self.lexer.is_local_id(:"*") ||
1071
- !self.lexer.is_local_id(:"**") ||
1072
- !self.lexer.is_local_id(:"&")) then
1073
-
1074
- yyerror("Invalid argument forwarding")
1075
- end
1076
- result = call_args [s(:forward_args).line(lexer.lineno)]
1077
- }
1078
- #endif
1079
1069
 
1080
1070
  opt_paren_args: none
1081
1071
  | paren_args
@@ -2376,21 +2366,6 @@ keyword_variable: kNIL { result = s(:nil).line lexer.lineno }
2376
2366
  self.lexer.lex_state = EXPR_BEG
2377
2367
  self.lexer.command_start = true
2378
2368
  }
2379
- #if V >= 27
2380
- | tLPAREN2 args_forward rparen
2381
- {
2382
- args_rest = :"*"
2383
- kwargs_rest = :"**"
2384
- block_fwd = :"&"
2385
- self.env[args_rest] = :lvar
2386
- self.env[kwargs_rest] = :lvar
2387
- self.env[block_fwd] = :lvar
2388
-
2389
- result = s(:args, s(:forward_args)).line lexer.lineno
2390
- self.lexer.lex_state = EXPR_BEG
2391
- self.lexer.command_start = true
2392
- }
2393
- #endif
2394
2369
  | {
2395
2370
  result = self.in_kwarg
2396
2371
  self.in_kwarg = true
@@ -2490,8 +2465,6 @@ keyword_variable: kNIL { result = s(:nil).line lexer.lineno }
2490
2465
  result = args val
2491
2466
  }
2492
2467
 
2493
- args_forward: tBDOT3
2494
-
2495
2468
  f_bad_arg: tCONSTANT
2496
2469
  {
2497
2470
  yyerror "formal argument cannot be a constant"
@@ -2640,7 +2613,6 @@ keyword_variable: kNIL { result = s(:nil).line lexer.lineno }
2640
2613
  | kwrest_mark
2641
2614
  {
2642
2615
  result = :"**"
2643
- self.env[result] = :lvar
2644
2616
  }
2645
2617
 
2646
2618
  #if V == 20
@@ -29,7 +29,7 @@ class Sexp
29
29
  end
30
30
 
31
31
  module RubyParserStuff
32
- VERSION = "3.15.1"
32
+ VERSION = "3.16.0"
33
33
 
34
34
  attr_accessor :lexer, :in_def, :in_single, :file
35
35
  attr_accessor :in_kwarg
@@ -115,7 +115,7 @@ module RubyParserStuff
115
115
  def initialize(options = {})
116
116
  super()
117
117
 
118
- v = self.class.name[/2\d/]
118
+ v = self.class.name[/[23]\d/]
119
119
  raise "Bad Class name #{self.class}" unless v
120
120
 
121
121
  self.lexer = RubyLexer.new v && v.to_i
@@ -1,4 +1,4 @@
1
- #!/Users/ryan/.rubies/ruby-2.7.1/bin/ruby -ws
1
+ #!/usr/bin/env ruby -ws
2
2
 
3
3
  $d ||= false
4
4
  $p ||= false
@@ -1,3 +1,9 @@
1
+ === 4.15.3 / 2021-05-15
2
+
3
+ * 1 minor enhancement:
4
+
5
+ * Added 3.0 to pt_testcase.rb
6
+
1
7
  === 4.15.2 / 2021-01-10
2
8
 
3
9
  * 1 bug fix:
@@ -77,7 +77,7 @@ class ParseTreeTestCase < Minitest::Test
77
77
  end
78
78
 
79
79
  def self.add_19tests name, hash
80
- add_tests "#{name}__19_20_21_22_23_24_25_26_27", hash # HACK?
80
+ add_tests "#{name}__19_20_21_22_23_24_25_26_27_30", hash # HACK?
81
81
  end
82
82
 
83
83
  def self.add_19edgecases ruby, sexp, cases
@@ -102,7 +102,7 @@ class ParseTreeTestCase < Minitest::Test
102
102
  testcases[verbose][klass] = testcases[nonverbose][klass]
103
103
  end
104
104
 
105
- VER_RE = "(1[89]|2[01234567])"
105
+ VER_RE = "(1[89]|2[01234567]|3[0])"
106
106
 
107
107
  def self.generate_test klass, node, data, input_name, output_name
108
108
  klass.send :define_method, "test_#{node}" do
@@ -34,7 +34,7 @@ require "sexp"
34
34
  class SexpProcessor
35
35
 
36
36
  # duh
37
- VERSION = "4.15.2"
37
+ VERSION = "4.15.3"
38
38
 
39
39
  ##
40
40
  # Automatically shifts off the Sexp type before handing the
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