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 +4 -4
- data/CHANGES.md +4 -0
- data/lib/brakeman.rb +4 -0
- data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
- data/lib/brakeman/checks/check_evaluation.rb +1 -1
- data/lib/brakeman/checks/check_sanitize_methods.rb +2 -1
- data/lib/brakeman/checks/check_sql.rb +15 -2
- data/lib/brakeman/checks/check_verb_confusion.rb +1 -1
- data/lib/brakeman/file_parser.rb +36 -14
- data/lib/brakeman/options.rb +1 -1
- data/lib/brakeman/processors/alias_processor.rb +52 -7
- data/lib/brakeman/processors/controller_alias_processor.rb +6 -43
- data/lib/brakeman/processors/lib/call_conversion_helper.rb +10 -0
- data/lib/brakeman/processors/library_processor.rb +9 -0
- data/lib/brakeman/report.rb +4 -1
- data/lib/brakeman/report/ignore/interactive.rb +1 -1
- data/lib/brakeman/report/report_github.rb +31 -0
- data/lib/brakeman/scanner.rb +3 -0
- data/lib/brakeman/tracker.rb +33 -4
- data/lib/brakeman/tracker/collection.rb +27 -5
- data/lib/brakeman/tracker/method_info.rb +29 -0
- data/lib/brakeman/util.rb +8 -0
- data/lib/brakeman/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d16867dd5c48de9ec2975e1dc420e3a5154939361988d70c4217f251881452ed
|
4
|
+
data.tar.gz: f5cae624d83a1298fb3f07108c76d1f55c756404d6998fccfd9e5fcfe69a068e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8724b266165ef9ed4ad926432e0786b955cb2e98b56e7100354b0ad04a51cc0eaa139343a769980852ae615bd209e8854f6f83616b0703d3a2aaf08229860c6
|
7
|
+
data.tar.gz: 963f46a856d6f943c74c6aca8ec3f3dc61ae3d82758fbfdda63bb4fc789ff95535f49cc73f9abef4cf1553323606d4fd50c8a03082178a6dd3cea0883e544a40
|
data/CHANGES.md
CHANGED
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
|
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 :
|
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
|
-
|
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
|
data/lib/brakeman/file_parser.rb
CHANGED
@@ -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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
50
|
+
begin
|
51
|
+
result = yield file, file.read
|
28
52
|
|
29
|
-
|
30
|
-
|
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
|
-
|
72
|
+
raise e.exception(e.message + "\nCould not parse #{path}")
|
46
73
|
rescue Timeout::Error => e
|
47
|
-
|
74
|
+
raise Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
|
48
75
|
rescue => e
|
49
|
-
|
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
|
data/lib/brakeman/options.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
306
|
-
|
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
|
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)
|
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
|
153
|
+
method = filter.src
|
154
154
|
|
155
|
-
if ivars = @tracker.filter_cache[[filter
|
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
|
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
|
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
|
data/lib/brakeman/report.rb
CHANGED
@@ -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
|
@@ -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
|
data/lib/brakeman/scanner.rb
CHANGED
data/lib/brakeman/tracker.rb
CHANGED
@@ -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
|
103
|
-
yield src, set_name, method_name, definition
|
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
|
289
|
-
finder.process_source src, :class => set_name, :method => method_name, :file => definition
|
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] =
|
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
|
-
|
66
|
-
|
67
|
-
|
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)
|
data/lib/brakeman/version.rb
CHANGED
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.
|
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-
|
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
|