Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add target matching by regex to CallIndex #1358

Merged
merged 1 commit into from May 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 44 additions & 15 deletions lib/brakeman/call_index.rb
Expand Up @@ -27,14 +27,20 @@ def find_calls options
if options[:chained]
return find_chain options
#Find by narrowest category
elsif target and method and target.is_a? Array and method.is_a? Array
elsif target.is_a? Array and method.is_a? Array
if target.length > method.length
calls = filter_by_target calls_by_methods(method), target
else
calls = calls_by_targets(target)
calls = filter_by_method calls, method
end

elsif target.is_a? Regexp and method
calls = filter_by_target(calls_by_method(method), target)

elsif method.is_a? Regexp and target
calls = filter_by_method(calls_by_target(target), method)

#Find by target, then by methods, if provided
elsif target
calls = calls_by_target target
Expand Down Expand Up @@ -116,8 +122,11 @@ def find_chain options
end

def calls_by_target target
if target.is_a? Array
case target
when Array
calls_by_targets target
when Regexp
calls_by_targets_regex target
else
@calls_by_target[target] || []
end
Expand All @@ -133,10 +142,24 @@ def calls_by_targets targets
calls
end

def calls_by_targets_regex targets_regex
calls = []

@calls_by_target.each do |key, value|
case key
when String, Symbol
calls.concat value if key.match targets_regex
end
end

calls
end

def calls_by_method method
if method.is_a? Array
case method
when Array
calls_by_methods method
elsif method.is_a? Regexp
when Regexp
calls_by_methods_regex method
else
@calls_by_method[method.to_sym] || []
Expand All @@ -156,26 +179,28 @@ def calls_by_methods methods

def calls_by_methods_regex methods_regex
calls = []

@calls_by_method.each do |key, value|
calls.concat value if key.to_s.match methods_regex
calls.concat value if key.match methods_regex
end
calls
end

def calls_with_no_target
@calls_by_target[nil]
calls
end

def filter calls, key, value
if value.is_a? Array
case value
when Array
values = Set.new value

calls.select do |call|
values.include? call[key]
end
elsif value.is_a? Regexp
when Regexp
calls.select do |call|
call[key].to_s.match value
case call[key]
when String, Symbol
call[key].match value
end
end
else
calls.select do |call|
Expand All @@ -197,15 +222,19 @@ def filter_nested calls
end

def filter_by_chain calls, target
if target.is_a? Array
case target
when Array
targets = Set.new target

calls.select do |call|
targets.include? call[:chain].first
end
elsif target.is_a? Regexp
when Regexp
calls.select do |call|
call[:chain].first.to_s.match target
case call[:chain].first
when String, Symbol
call[:chain].first.match target
end
end
else
calls.select do |call|
Expand Down
28 changes: 28 additions & 0 deletions test/tests/call_index.rb
Expand Up @@ -47,6 +47,7 @@ def assert_found num, opts

def test_find_by_method_regex
assert_found 2, :method => %r{do_it(?:_now)?}
assert_found 2, :target => :world, :method => %r{oo}
end

def test_find_by_method
Expand All @@ -57,6 +58,20 @@ def test_find_by_target
assert_found 3, :target => :world
end

def test_find_by_target_regex
# x.y.z
assert_found 1, :targets => %r{^x\.y$}

# x.y.z
# params[].y.z
assert_found 2, :targets => %r{\.y$}


# the_bar.foo
# the_baz.foo
assert_found 2, :targets => %r{^the}, methods: [:foo, :goodbye]
end

def test_find_by_methods
assert_found 5, :methods => [:foo, :hello, :goodbye]
end
Expand All @@ -77,6 +92,14 @@ def test_find_by_targets_and_method
assert_found 2, :target => [:world, :the_bar], :methods => :foo
end

def test_find_by_more_targets
assert_found 2, :target => [:world, :the_bar], :methods => [:foo]
end

def test_find_by_more_methods
assert_found 2, :target => [:world], :methods => [:foo, :hello]
end

def test_find_by_no_target_and_method
assert_found 1, :target => nil, :method => :do_it
assert_found 0, :targets => nil, :method => :with_target
Expand All @@ -96,6 +119,11 @@ def test_find_params_and_method_in_chain
assert_found 1, :target => :params, :method => :z, :chained => true
end

def test_filter_by_chain
assert_found 1, :target => [:params], :method => :z, :chained => true
assert_found 1, :target => /^x$/, :method => :z, :chained => true
end

def test_find_class_scope_call_by_method
assert_found 1, :method => :do_a_thing
end
Expand Down