brakeman 4.10.1 → 5.0.0.pre1
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 +4 -4
- data/CHANGES.md +9 -7
- data/README.md +1 -1
- data/bundle/load.rb +8 -9
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/CHANGELOG.md +1 -8
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/FAQ.md +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/Gemfile +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/MIT-LICENSE +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/README.md +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/REFERENCE.md +5 -9
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/TODO +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/haml.gemspec +1 -1
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/attribute_builder.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/attribute_compiler.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/attribute_parser.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/buffer.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/compiler.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/engine.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/error.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/escapable.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/exec.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/filters.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/generator.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/action_view_extensions.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/action_view_mods.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/action_view_xss_mods.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/safe_erubi_template.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/safe_erubis_template.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/xss_mods.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/options.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/parser.rb +3 -31
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/plugin.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/railtie.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/sass_rails_filter.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/template.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/template/options.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/temple_engine.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/temple_line_counter.rb +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/util.rb +1 -1
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/version.rb +1 -1
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/yard/default/fulldoc/html/css/common.sass +0 -0
- data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/yard/default/layout/html/footer.erb +0 -0
- data/lib/brakeman.rb +6 -0
- data/lib/brakeman/app_tree.rb +36 -3
- data/lib/brakeman/checks/check_execute.rb +1 -1
- data/lib/brakeman/checks/check_regex_dos.rb +1 -1
- data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
- data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
- data/lib/brakeman/file_parser.rb +19 -23
- data/lib/brakeman/options.rb +5 -1
- data/lib/brakeman/parsers/template_parser.rb +2 -3
- data/lib/brakeman/processors/alias_processor.rb +2 -2
- data/lib/brakeman/processors/controller_processor.rb +1 -1
- data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
- data/lib/brakeman/processors/output_processor.rb +1 -1
- data/lib/brakeman/processors/template_alias_processor.rb +0 -5
- data/lib/brakeman/report.rb +8 -0
- data/lib/brakeman/report/report_sonar.rb +38 -0
- data/lib/brakeman/rescanner.rb +7 -5
- data/lib/brakeman/scanner.rb +42 -18
- data/lib/brakeman/tracker.rb +6 -0
- data/lib/brakeman/tracker/controller.rb +1 -1
- data/lib/brakeman/util.rb +9 -4
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +2 -0
- data/lib/ruby_parser/bm_sexp.rb +9 -9
- metadata +49 -99
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/Gemfile +0 -6
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/LICENSE.txt +0 -22
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/NEWS.md +0 -141
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/README.md +0 -60
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attlistdecl.rb +0 -63
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attribute.rb +0 -205
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/cdata.rb +0 -68
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/child.rb +0 -97
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/comment.rb +0 -80
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/doctype.rb +0 -287
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/document.rb +0 -291
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/attlistdecl.rb +0 -11
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/dtd.rb +0 -47
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/elementdecl.rb +0 -18
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/entitydecl.rb +0 -57
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/notationdecl.rb +0 -40
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/element.rb +0 -1269
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/encoding.rb +0 -51
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/entity.rb +0 -171
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/default.rb +0 -116
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/pretty.rb +0 -142
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/transitive.rb +0 -58
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/functions.rb +0 -447
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/instruction.rb +0 -79
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/light/node.rb +0 -196
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/namespace.rb +0 -59
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/node.rb +0 -76
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/output.rb +0 -30
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parent.rb +0 -166
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parseexception.rb +0 -52
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/baseparser.rb +0 -594
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/lightparser.rb +0 -59
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/pullparser.rb +0 -197
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/sax2parser.rb +0 -273
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/streamparser.rb +0 -61
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/treeparser.rb +0 -101
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/ultralightparser.rb +0 -57
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/xpathparser.rb +0 -675
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/quickpath.rb +0 -266
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/rexml.rb +0 -32
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/sax2listener.rb +0 -98
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/security.rb +0 -28
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/source.rb +0 -298
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/streamlistener.rb +0 -93
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/text.rb +0 -424
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/undefinednamespaceexception.rb +0 -9
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/relaxng.rb +0 -539
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validation.rb +0 -144
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validationexception.rb +0 -10
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmldecl.rb +0 -130
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmltokens.rb +0 -85
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath.rb +0 -81
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath_parser.rb +0 -968
- data/bundle/ruby/2.7.0/gems/rexml-3.2.4/rexml.gemspec +0 -84
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'brakeman/checks/base_check'
|
2
|
+
|
3
|
+
class Brakeman::CheckVerbConfusion < Brakeman::BaseCheck
|
4
|
+
Brakeman::Checks.add self
|
5
|
+
|
6
|
+
@description = "Check for uses of `request.get?` that might have unintentional behavior"
|
7
|
+
|
8
|
+
#Process calls
|
9
|
+
def run_check
|
10
|
+
calls = tracker.find_call(target: :request, methods: [:get?])
|
11
|
+
|
12
|
+
calls.each do |call|
|
13
|
+
process_result call
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_result result
|
18
|
+
@current_result = result
|
19
|
+
@matched_call = result[:call]
|
20
|
+
klass = tracker.find_class(result[:location][:class])
|
21
|
+
|
22
|
+
# TODO: abstract into tracker.find_location ?
|
23
|
+
if klass.nil?
|
24
|
+
Brakeman.debug "No class found: #{result[:location][:class]}"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
method = klass.get_method(result[:location][:method])
|
29
|
+
|
30
|
+
if method.nil?
|
31
|
+
Brakeman.debug "No method found: #{result[:location][:method]}"
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
process method[:src]
|
36
|
+
end
|
37
|
+
|
38
|
+
def process_if exp
|
39
|
+
if exp.condition == @matched_call
|
40
|
+
# Found `if request.get?`
|
41
|
+
|
42
|
+
# Do not warn if there is an `elsif` clause
|
43
|
+
if node_type? exp.else_clause, :if
|
44
|
+
return exp
|
45
|
+
end
|
46
|
+
|
47
|
+
warn_about_result @current_result, exp
|
48
|
+
end
|
49
|
+
|
50
|
+
exp
|
51
|
+
end
|
52
|
+
|
53
|
+
def warn_about_result result, code
|
54
|
+
return unless original? result
|
55
|
+
|
56
|
+
confidence = :weak
|
57
|
+
message = msg('Potential HTTP verb confusion. ',
|
58
|
+
msg_code('HEAD'),
|
59
|
+
' is routed like ',
|
60
|
+
msg_code('GET'),
|
61
|
+
' but ',
|
62
|
+
msg_code('request.get?'),
|
63
|
+
' will return ',
|
64
|
+
msg_code('false')
|
65
|
+
)
|
66
|
+
|
67
|
+
warn :result => result,
|
68
|
+
:warning_type => "HTTP Verb Confusion",
|
69
|
+
:warning_code => :http_verb_confusion,
|
70
|
+
:message => message,
|
71
|
+
:code => code,
|
72
|
+
:user_input => result[:call],
|
73
|
+
:confidence => confidence
|
74
|
+
end
|
75
|
+
end
|
data/lib/brakeman/file_parser.rb
CHANGED
@@ -3,55 +3,51 @@ module Brakeman
|
|
3
3
|
|
4
4
|
# This class handles reading and parsing files.
|
5
5
|
class FileParser
|
6
|
-
attr_reader :file_list
|
6
|
+
attr_reader :file_list, :errors
|
7
7
|
|
8
|
-
def initialize
|
9
|
-
@
|
10
|
-
@timeout =
|
11
|
-
@
|
12
|
-
@
|
8
|
+
def initialize app_tree, timeout
|
9
|
+
@app_tree = app_tree
|
10
|
+
@timeout = timeout
|
11
|
+
@file_list = []
|
12
|
+
@errors = []
|
13
13
|
end
|
14
14
|
|
15
|
-
def parse_files list
|
16
|
-
read_files list
|
15
|
+
def parse_files list
|
16
|
+
read_files list do |path, contents|
|
17
17
|
if ast = parse_ruby(contents, path.relative)
|
18
18
|
ASTFile.new(path, ast)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def read_files list
|
24
|
-
@file_list[type] ||= []
|
25
|
-
|
23
|
+
def read_files list
|
26
24
|
list.each do |path|
|
27
25
|
file = @app_tree.file_path(path)
|
28
26
|
|
29
27
|
result = yield file, file.read
|
28
|
+
|
30
29
|
if result
|
31
|
-
@file_list
|
30
|
+
@file_list << result
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
36
|
-
# _path_ can be a string or a Brakeman::FilePath
|
37
35
|
def parse_ruby input, path
|
38
|
-
if path.is_a? Brakeman::FilePath
|
39
|
-
path = path.relative
|
40
|
-
end
|
41
|
-
|
42
36
|
begin
|
43
37
|
Brakeman.debug "Parsing #{path}"
|
44
38
|
RubyParser.new.parse input, path, @timeout
|
45
39
|
rescue Racc::ParseError => e
|
46
|
-
|
47
|
-
nil
|
40
|
+
error e.exception(e.message + "\nCould not parse #{path}")
|
48
41
|
rescue Timeout::Error => e
|
49
|
-
|
50
|
-
nil
|
42
|
+
error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
|
51
43
|
rescue => e
|
52
|
-
|
53
|
-
nil
|
44
|
+
error e.exception(e.message + "\nWhile processing #{path}")
|
54
45
|
end
|
55
46
|
end
|
47
|
+
|
48
|
+
def error exception
|
49
|
+
@errors << exception
|
50
|
+
nil
|
51
|
+
end
|
56
52
|
end
|
57
53
|
end
|
data/lib/brakeman/options.rb
CHANGED
@@ -166,6 +166,10 @@ module Brakeman::Options
|
|
166
166
|
options[:only_files].merge files
|
167
167
|
end
|
168
168
|
|
169
|
+
opts.on "--[no-]skip-vendor", "Skip processing vendor directory (Default)" do |skip|
|
170
|
+
options[:skip_vendor] = skip
|
171
|
+
end
|
172
|
+
|
169
173
|
opts.on "--skip-libs", "Skip processing lib directory" do
|
170
174
|
options[:skip_libs] = true
|
171
175
|
end
|
@@ -229,7 +233,7 @@ module Brakeman::Options
|
|
229
233
|
|
230
234
|
opts.on "-f",
|
231
235
|
"--format TYPE",
|
232
|
-
[:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif],
|
236
|
+
[:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar],
|
233
237
|
"Specify output formats. Default is text" do |type|
|
234
238
|
|
235
239
|
type = "s" if type == :text
|
@@ -9,7 +9,6 @@ module Brakeman
|
|
9
9
|
def initialize tracker, file_parser
|
10
10
|
@tracker = tracker
|
11
11
|
@file_parser = file_parser
|
12
|
-
@file_parser.file_list[:templates] ||= []
|
13
12
|
end
|
14
13
|
|
15
14
|
def parse_template path, text
|
@@ -33,7 +32,7 @@ module Brakeman
|
|
33
32
|
end
|
34
33
|
|
35
34
|
if src and ast = @file_parser.parse_ruby(src, path)
|
36
|
-
@file_parser.file_list
|
35
|
+
@file_parser.file_list << TemplateFile.new(path, ast, name, type)
|
37
36
|
end
|
38
37
|
rescue Racc::ParseError => e
|
39
38
|
tracker.error e, "Could not parse #{path}"
|
@@ -97,7 +96,7 @@ module Brakeman
|
|
97
96
|
end
|
98
97
|
|
99
98
|
def self.parse_inline_erb tracker, text
|
100
|
-
fp = Brakeman::FileParser.new(tracker)
|
99
|
+
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
|
101
100
|
tp = self.new(tracker, fp)
|
102
101
|
src = tp.parse_erb '_inline_', text
|
103
102
|
type = tp.erubis? ? :erubis : :erb
|
@@ -236,7 +236,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
236
236
|
env[target_var] = target
|
237
237
|
return target
|
238
238
|
elsif string? target and string_interp? first_arg
|
239
|
-
exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg
|
239
|
+
exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg[2..-1])
|
240
240
|
env[target_var] = exp
|
241
241
|
elsif string? first_arg and string_interp? target
|
242
242
|
if string? target.last
|
@@ -941,7 +941,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
941
941
|
args = exp.args
|
942
942
|
exp.pop # remove last arg
|
943
943
|
if args.length > 1
|
944
|
-
exp.arglist = args
|
944
|
+
exp.arglist = args[1..-1]
|
945
945
|
end
|
946
946
|
end
|
947
947
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Brakeman
|
2
|
+
class FileTypeDetector < BaseProcessor
|
3
|
+
def initialize
|
4
|
+
super(nil)
|
5
|
+
reset
|
6
|
+
end
|
7
|
+
|
8
|
+
def detect_type(file)
|
9
|
+
reset
|
10
|
+
process(file.ast)
|
11
|
+
|
12
|
+
if @file_type.nil?
|
13
|
+
@file_type = guess_from_path(file.path.relative)
|
14
|
+
end
|
15
|
+
|
16
|
+
@file_type || :libs
|
17
|
+
end
|
18
|
+
|
19
|
+
MODEL_CLASSES = [
|
20
|
+
:'ActiveRecord::Base',
|
21
|
+
:ApplicationRecord
|
22
|
+
]
|
23
|
+
|
24
|
+
def process_class exp
|
25
|
+
name = class_name(exp.class_name)
|
26
|
+
parent = class_name(exp.parent_name)
|
27
|
+
|
28
|
+
if name.match(/Controller$/)
|
29
|
+
@file_type = :controllers
|
30
|
+
return exp
|
31
|
+
elsif MODEL_CLASSES.include? parent
|
32
|
+
@file_type = :models
|
33
|
+
return exp
|
34
|
+
end
|
35
|
+
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def guess_from_path path
|
40
|
+
case
|
41
|
+
when path.include?('app/models')
|
42
|
+
:models
|
43
|
+
when path.include?('app/controllers')
|
44
|
+
:controllers
|
45
|
+
when path.include?('config/initializers')
|
46
|
+
:initializers
|
47
|
+
when path.include?('lib/')
|
48
|
+
:libs
|
49
|
+
when path.match?(%r{config/environments/(?!production\.rb)$})
|
50
|
+
:skip
|
51
|
+
when path.match?(%r{environments/production\.rb$})
|
52
|
+
:skip
|
53
|
+
when path.match?(%r{application\.rb$})
|
54
|
+
:skip
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def reset
|
61
|
+
@file_type = nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -20,11 +20,6 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
|
|
20
20
|
|
21
21
|
#Process template
|
22
22
|
def process_template name, args, _, line = nil
|
23
|
-
# Strip forward slash from beginning of template path.
|
24
|
-
# This also happens in RenderHelper#process_template but
|
25
|
-
# we need it here too to accurately avoid circular renders below.
|
26
|
-
name = name.to_s.gsub(/^\//, "")
|
27
|
-
|
28
23
|
if @called_from
|
29
24
|
if @called_from.include_template? name
|
30
25
|
Brakeman.debug "Skipping circular render from #{@template.name} to #{name}"
|
data/lib/brakeman/report.rb
CHANGED
@@ -45,6 +45,9 @@ class Brakeman::Report
|
|
45
45
|
Brakeman::Report::JUnit
|
46
46
|
when :to_sarif
|
47
47
|
return self.to_sarif
|
48
|
+
when :to_sonar
|
49
|
+
require_report 'sonar'
|
50
|
+
Brakeman::Report::Sonar
|
48
51
|
else
|
49
52
|
raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
|
50
53
|
end
|
@@ -69,6 +72,11 @@ class Brakeman::Report
|
|
69
72
|
generate Brakeman::Report::JSON
|
70
73
|
end
|
71
74
|
|
75
|
+
def to_sonar
|
76
|
+
require_report 'sonar'
|
77
|
+
generate Brakeman::Report::Sonar
|
78
|
+
end
|
79
|
+
|
72
80
|
def to_table
|
73
81
|
require_report 'table'
|
74
82
|
generate Brakeman::Report::Table
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Brakeman::Report::Sonar < Brakeman::Report::Base
|
2
|
+
def generate_report
|
3
|
+
report_object = {
|
4
|
+
issues: all_warnings.map { |warning| issue_json(warning) }
|
5
|
+
}
|
6
|
+
return JSON.pretty_generate report_object
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def issue_json(warning)
|
12
|
+
{
|
13
|
+
engineId: "Brakeman",
|
14
|
+
ruleId: warning.warning_code,
|
15
|
+
type: "VULNERABILITY",
|
16
|
+
severity: severity_level_for(warning.confidence),
|
17
|
+
primaryLocation: {
|
18
|
+
message: warning.message,
|
19
|
+
filePath: warning.file.relative,
|
20
|
+
textRange: {
|
21
|
+
"startLine": warning.line || 1,
|
22
|
+
"endLine": warning.line || 1,
|
23
|
+
}
|
24
|
+
},
|
25
|
+
effortMinutes: (4 - warning.confidence) * 15
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def severity_level_for(confidence)
|
30
|
+
if confidence == 0
|
31
|
+
"CRITICAL"
|
32
|
+
elsif confidence == 1
|
33
|
+
"MAJOR"
|
34
|
+
else
|
35
|
+
"MINOR"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/brakeman/rescanner.rb
CHANGED
@@ -132,10 +132,11 @@ class Brakeman::Rescanner < Brakeman::Scanner
|
|
132
132
|
template_name = template_path_to_name(path)
|
133
133
|
|
134
134
|
tracker.reset_template template_name
|
135
|
-
fp = Brakeman::FileParser.new(tracker)
|
135
|
+
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
|
136
136
|
template_parser = Brakeman::TemplateParser.new(tracker, fp)
|
137
137
|
template_parser.parse_template path, path.read
|
138
|
-
|
138
|
+
tracker.add_errors(fp.errors)
|
139
|
+
process_template fp.file_list.first
|
139
140
|
|
140
141
|
@processor.process_template_alias tracker.templates[template_name]
|
141
142
|
|
@@ -390,9 +391,10 @@ class Brakeman::Rescanner < Brakeman::Scanner
|
|
390
391
|
|
391
392
|
def parse_ruby_files list
|
392
393
|
paths = list.select(&:exists?)
|
393
|
-
file_parser = Brakeman::FileParser.new(tracker)
|
394
|
-
file_parser.parse_files paths
|
395
|
-
file_parser.
|
394
|
+
file_parser = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
|
395
|
+
file_parser.parse_files paths
|
396
|
+
tracker.add_errors(file_parser.errors)
|
397
|
+
file_parser.file_list
|
396
398
|
end
|
397
399
|
end
|
398
400
|
|
data/lib/brakeman/scanner.rb
CHANGED
@@ -7,6 +7,7 @@ begin
|
|
7
7
|
require 'brakeman/app_tree'
|
8
8
|
require 'brakeman/file_parser'
|
9
9
|
require 'brakeman/parsers/template_parser'
|
10
|
+
require 'brakeman/processors/lib/file_type_detector'
|
10
11
|
rescue LoadError => e
|
11
12
|
$stderr.puts e.message
|
12
13
|
$stderr.puts "Please install the appropriate dependency."
|
@@ -23,7 +24,10 @@ class Brakeman::Scanner
|
|
23
24
|
@app_tree = Brakeman::AppTree.from_options(options)
|
24
25
|
|
25
26
|
if (!@app_tree.root || !@app_tree.exists?("app")) && !options[:force_scan]
|
26
|
-
|
27
|
+
message = "Please supply the path to a Rails application (looking in #{@app_tree.root}).\n" <<
|
28
|
+
" Use `--force` to run a scan anyway - for example if there are many applications in one directory."
|
29
|
+
|
30
|
+
raise Brakeman::NoApplication, message
|
27
31
|
end
|
28
32
|
|
29
33
|
@processor = processor || Brakeman::Processor.new(@app_tree, options)
|
@@ -43,6 +47,8 @@ class Brakeman::Scanner
|
|
43
47
|
process_config
|
44
48
|
Brakeman.notify "Parsing files..."
|
45
49
|
parse_files
|
50
|
+
Brakeman.notify "Detecting file types..."
|
51
|
+
detect_file_types
|
46
52
|
Brakeman.notify "Processing initializers..."
|
47
53
|
process_initializers
|
48
54
|
Brakeman.notify "Processing libs..."
|
@@ -65,29 +71,47 @@ class Brakeman::Scanner
|
|
65
71
|
end
|
66
72
|
|
67
73
|
def parse_files
|
68
|
-
fp = Brakeman::FileParser.new tracker
|
69
|
-
|
70
|
-
files = {
|
71
|
-
:initializers => @app_tree.initializer_paths,
|
72
|
-
:controllers => @app_tree.controller_paths,
|
73
|
-
:models => @app_tree.model_paths
|
74
|
-
}
|
75
|
-
|
76
|
-
unless options[:skip_libs]
|
77
|
-
files[:libs] = @app_tree.lib_paths
|
78
|
-
end
|
74
|
+
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
|
79
75
|
|
80
|
-
|
81
|
-
fp.parse_files paths, name
|
82
|
-
end
|
76
|
+
fp.parse_files tracker.app_tree.ruby_file_paths
|
83
77
|
|
84
78
|
template_parser = Brakeman::TemplateParser.new(tracker, fp)
|
85
79
|
|
86
|
-
fp.read_files(@app_tree.template_paths
|
80
|
+
fp.read_files(@app_tree.template_paths) do |path, contents|
|
87
81
|
template_parser.parse_template path, contents
|
88
82
|
end
|
89
83
|
|
90
|
-
|
84
|
+
# Collect errors raised during parsing
|
85
|
+
tracker.add_errors(fp.errors)
|
86
|
+
|
87
|
+
@parsed_files = fp.file_list
|
88
|
+
end
|
89
|
+
|
90
|
+
def detect_file_types
|
91
|
+
@file_list = {
|
92
|
+
controllers: [],
|
93
|
+
initializers: [],
|
94
|
+
libs: [],
|
95
|
+
models: [],
|
96
|
+
templates: [],
|
97
|
+
}
|
98
|
+
|
99
|
+
detector = Brakeman::FileTypeDetector.new
|
100
|
+
|
101
|
+
@parsed_files.each do |file|
|
102
|
+
if file.is_a? Brakeman::TemplateParser::TemplateFile
|
103
|
+
@file_list[:templates] << file
|
104
|
+
else
|
105
|
+
type = detector.detect_type(file)
|
106
|
+
unless type == :skip
|
107
|
+
if @file_list[type].nil?
|
108
|
+
raise type.to_s
|
109
|
+
else
|
110
|
+
@file_list[type] << file
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
91
115
|
end
|
92
116
|
|
93
117
|
#Process config/environment.rb and config/gems.rb
|
@@ -325,7 +349,7 @@ class Brakeman::Scanner
|
|
325
349
|
end
|
326
350
|
|
327
351
|
def parse_ruby_file file
|
328
|
-
fp = Brakeman::FileParser.new(
|
352
|
+
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
|
329
353
|
fp.parse_ruby(file.read, file)
|
330
354
|
end
|
331
355
|
end
|