Skip to content

Commit

Permalink
Merge pull request #1858 from presidentbeef/use_prism
Browse files Browse the repository at this point in the history
Add optional use of Prism parser
  • Loading branch information
presidentbeef authored Jul 22, 2024
2 parents 9d304ab + be79c7f commit ed7242d
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 6 deletions.
36 changes: 34 additions & 2 deletions lib/brakeman/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@ module Brakeman
class FileParser
attr_reader :file_list, :errors

def initialize app_tree, timeout, parallel = true
def initialize app_tree, timeout, parallel = true, use_prism = false
@use_prism = use_prism

if @use_prism
begin
require 'prism'
rescue LoadError => e
Brakeman.debug "Asked to use Prism, but failed to load: #{e}"
@use_prism = false
end
end

@app_tree = app_tree
@timeout = timeout
@file_list = []
Expand Down Expand Up @@ -73,8 +84,29 @@ def parse_ruby input, path
path = path.relative
end

Brakeman.debug "Parsing #{path}"

if @use_prism
begin
parse_with_prism input, path
rescue => e
Brakeman.debug "Prism failed to parse #{path}: #{e}"

parse_with_ruby_parser input, path
end
else
parse_with_ruby_parser input, path
end
end

private

def parse_with_prism input, path
Prism::Translation::RubyParser.parse(input, path)
end

def parse_with_ruby_parser input, path
begin
Brakeman.debug "Parsing #{path}"
RubyParser.new.parse input, path, @timeout
rescue Racc::ParseError => e
raise e.exception(e.message + "\nCould not parse #{path}")
Expand Down
17 changes: 17 additions & 0 deletions lib/brakeman/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,23 @@ def create_option_parser options
options[:parser_timeout] = timeout
end

opts.on "--[no-]prism", "Use the Prism parser" do |use_prism|
if use_prism
prism_version = '0.30'

begin
# Specifying minimum version here,
# since it can't be in the gem dependency list because it is optional
gem 'prism', "~>#{prism_version}"
rescue Gem::MissingSpecVersionError, Gem::MissingSpecError, Gem::LoadError => e
$stderr.puts "Please install `prism` version #{prism_version} or newer:"
raise e
end
end

options[:use_prism] = use_prism
end

opts.on "-r", "--report-direct", "Only report direct use of untrusted data" do |option|
options[:check_arguments] = !option
end
Expand Down
4 changes: 2 additions & 2 deletions lib/brakeman/scanner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def process
end

def parse_files
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout], tracker.options[:parallel_checks])
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout], tracker.options[:parallel_checks], tracker.options[:use_prism])

fp.parse_files tracker.app_tree.ruby_file_paths

Expand Down Expand Up @@ -414,7 +414,7 @@ def index_call_sites
end

def parse_ruby_file file
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout], false, tracker.options[:use_prism])
fp.parse_ruby(file.read, file)
rescue Exception => e
tracker.error(e)
Expand Down
20 changes: 19 additions & 1 deletion test/tests/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class BrakemanOptionsTest < Minitest::Test
:ensure_latest => "--ensure-latest",
:allow_check_paths_in_config => "--allow-check-paths-in-config",
:pager => "--pager",
:show_timing => "--timing",
:show_timing => "--timing",
}

ALT_OPTION_INPUTS = {
Expand Down Expand Up @@ -366,6 +366,24 @@ def test_text_report_fields
end
end

def test_use_prism
begin
# If prism is installed, test that everything is fine

gem('prism', '~>0.30')
options = setup_options_from_input('--prism')
assert options[:use_prism]
rescue Gem::MissingSpecVersionError, Gem::MissingSpecError, Gem::LoadError
# Otherwise, test the error message and exception

assert_output nil, /Please install `prism`/ do
assert_raises Gem::MissingSpecVersionError, Gem::MissingSpecError, Gem::LoadError do
setup_options_from_input('--prism')
end
end
end
end

private

def setup_options_from_input(*args)
Expand Down
2 changes: 1 addition & 1 deletion test/tests/rails8.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Rails8Tests < Minitest::Test
def report
@@report ||=
Date.stub :today, Date.parse("2024-05-13") do
BrakemanTester.run_scan "rails8", "Rails 8", run_all_checks: true
BrakemanTester.run_scan "rails8", "Rails 8", run_all_checks: true, use_prism: true
end
end

Expand Down

0 comments on commit ed7242d

Please sign in to comment.