Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/bundler/audit/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class CLI < ::Thor
method_option :gemfile_lock, type: :string, aliases: '-G',
default: 'Gemfile.lock'
method_option :output, type: :string, aliases: '-o'
method_option :strict_ignore, type: :boolean, default: false

def check(dir=Dir.pwd)
unless File.directory?(dir)
Expand Down Expand Up @@ -86,6 +87,7 @@ def check(dir=Dir.pwd)
output.close if options[:output]

exit(1) if report.vulnerable?
exit(1) if options[:strict_ignore] && report.unseen_ignored_identifiers?
end

desc 'stats', 'Prints ruby-advisory-db stats'
Expand Down
4 changes: 4 additions & 0 deletions lib/bundler/audit/cli/formats/text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def print_report(report,output=$stdout)
end
end

if report.unseen_ignored_identifiers?
print_warning "These identifiers were ignored but not found: #{report.unseen_ignored_identifiers.to_a.join(', ')}"
end

if report.vulnerable?
say "Vulnerabilities found!", :red
else
Expand Down
20 changes: 20 additions & 0 deletions lib/bundler/audit/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ class Report
# @return [Array<Results::UnpatchedGems>]
attr_reader :unpatched_gems

# Identifiers of all seen vulnerabilities (including ignored vulns).
#
# @return [Set<String>]
attr_accessor :seen_identifiers

# Identifiers that were omitted from results
#
# @return [Set<String>]
attr_accessor :ignored_identifiers

#
# Initializes the report.
#
Expand All @@ -49,6 +59,8 @@ def initialize(results=[])
@results = []
@insecure_sources = []
@unpatched_gems = []
@seen_identifiers = Set.new
@ignored_identifiers = Set.new

results.each { |result| self << result }
end
Expand Down Expand Up @@ -133,6 +145,14 @@ def vulnerable_gems
@unpatched_gems.map(&:gem)
end

def unseen_ignored_identifiers?
unseen_ignored_identifiers.any?
end

def unseen_ignored_identifiers
@ignored_identifiers - @seen_identifiers
end

#
# @return [Hash{Symbol => Object}]
#
Expand Down
9 changes: 9 additions & 0 deletions lib/bundler/audit/scanner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ def report(options={})
yield result if block_given?
end

report.seen_identifiers = @seen
report.ignored_identifiers = if options[:ignore]
Set.new(options[:ignore])
else
config.ignore
end

return report
end

Expand Down Expand Up @@ -222,9 +229,11 @@ def scan_specs(options={})
else
config.ignore
end
@seen = Set.new

@lockfile.specs.each do |gem|
@database.check_gem(gem) do |advisory|
@seen.merge(advisory.identifiers)
is_ignored = ignore.intersect?(advisory.identifiers.to_set)
next if is_ignored

Expand Down
13 changes: 13 additions & 0 deletions spec/cli/formats/text_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,19 @@
end
end

context "when there are unseen ignored identifiers" do
let(:report) do
Bundler::Audit::Report.new.tap do |r|
r.ignored_identifiers = Set.new(unseen)
end
end
let(:unseen) { %w[CVE-2020-8833 OSVDB-108664] }

it "must print the unseen identifiers" do
expect(output_lines).to include("These identifiers were ignored but not found: #{unseen.join(', ')}")
end
end

it "must restore $stdout" do
expect($stdout).to_not be(stdout)
end
Expand Down
21 changes: 21 additions & 0 deletions spec/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,25 @@
end
end
end

describe "#check" do
context "--strict-ignore" do
let(:directory) { File.join("spec", "bundle", "secure") }

subject do
described_class.new([], strict_ignore: true, ignore: ["CVE-2006-1982"], format: "text", database: File.expand_path("fixtures/database/", File.dirname(__FILE__)), gemfile_lock: "Gemfile.lock", config: ".bundler-audit.yml")
end

context "when the ignored CVE is not found" do
it "exits with an error status code" do
expect {
subject.check(directory)
}.to raise_error(SystemExit) do |error|
expect(error.success?).to eq(false)
expect(error.status).to eq(1)
end
end
end
end
end
end
27 changes: 25 additions & 2 deletions spec/scanner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@
end

context "when the :ignore option is given" do
subject { super().scan(ignore: ['OSVDB-89026']) }
subject { super().scan(ignore: ['OSVDB-89025']) }

it "should ignore the specified advisories" do
ids = subject.map { |result| result.advisory.id }

expect(ids).not_to include('OSVDB-89026')
expect(ids).not_to include('OSVDB-89025')
end
end
end
Expand Down Expand Up @@ -116,6 +116,29 @@
expect(report.results).to all(be_kind_of(Bundler::Audit::Results::Result))
end

it "should return a Report containing all identifiers seen during scanning" do
report = subject.report
expected_identifiers = %w[CVE-2013-0155 CVE-2013-0276 CVE-2013-1854 CVE-2013-1856 CVE-2014-3482 CVE-2015-3227 CVE-2015-7577 OSVDB-108664 OSVDB-89025 OSVDB-90072 OSVDB-91451 OSVDB-91453]

expect(report.seen_identifiers).to contain_exactly(*expected_identifiers)
end

context "when some identifiers are ignored" do
it "should return a Report containing the seen but ignored identifiers" do
ignored_identifiers = %w[CVE-2013-0155 OSVDB-108664]
report = subject.report(ignore: ignored_identifiers)

expect(report.seen_identifiers).to include(*ignored_identifiers)
end

it "should return a Report listing the ignored identifiers" do
ignored_identifiers = %w[CVE-2013-0155 OSVDB-108664]
report = subject.report(ignore: ignored_identifiers)

expect(report.ignored_identifiers).to contain_exactly(*ignored_identifiers)
end
end

context "when given a block" do
it "should yield results" do
results = []
Expand Down