Skip to content

Commit d964d9e

Browse files
committed
Fix #403: exit with error when --gemfile-lock is not a valid lock file
Bundler::LockfileParser silently accepts any file (Gemfile, README.md, etc.) and returns empty results, causing bundle-audit to exit 0 with 'No vulnerabilities found' even when given the wrong file. Changes: - Add Scanner::InvalidGemfileLock exception class - Add LOCKFILE_HEADER_RE regexp to validate lock file content before parsing - Raise InvalidGemfileLock in Scanner#initialize when file does not start with a recognised Bundler lockfile section header - Rescue InvalidGemfileLock in CLI#check and exit with status 1 plus a descriptive stderr message - Add spec for Scanner#initialize raising InvalidGemfileLock - Add specs for CLI#check printing error to stderr and exiting with 1 Fixes #403
1 parent f8b06eb commit d964d9e

4 files changed

Lines changed: 57 additions & 1 deletion

File tree

lib/bundler/audit/cli.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ def check(dir=Dir.pwd)
7171
rescue Bundler::GemfileLockNotFound => exception
7272
say exception.message, :red
7373
exit 1
74+
rescue Scanner::InvalidGemfileLock => exception
75+
say_error exception.message, :red
76+
exit 1
7477
end
7578

7679
report = scanner.report(ignore: options.ignore)

lib/bundler/audit/scanner.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ module Audit
3636
#
3737
class Scanner
3838

39+
# Raised when the given file is not a valid Bundler lockfile.
40+
class InvalidGemfileLock < StandardError; end
41+
42+
# Regexp matching the first line of every valid Bundler lockfile.
43+
LOCKFILE_HEADER_RE = /\A(GEM|GIT|PATH|PLUGIN SOURCE|PLATFORMS|DEPENDENCIES|BUNDLED WITH)\b/
44+
3945
# The advisory database.
4046
#
4147
# @return [Database]
@@ -84,7 +90,13 @@ def initialize(root=Dir.pwd,gemfile_lock='Gemfile.lock',database=Database.new,co
8490
raise(Bundler::GemfileLockNotFound,"Could not find #{gemfile_lock.inspect} in #{@root.inspect}")
8591
end
8692

87-
@lockfile = LockfileParser.new(File.read(gemfile_lock_path))
93+
lock_file_content = File.read(gemfile_lock_path)
94+
95+
unless lock_file_content =~ LOCKFILE_HEADER_RE
96+
raise(InvalidGemfileLock,"#{gemfile_lock.inspect} is not a valid Gemfile.lock")
97+
end
98+
99+
@lockfile = LockfileParser.new(lock_file_content)
88100

89101
config_dot_file_full_path = File.absolute_path(config_dot_file, @root)
90102

spec/cli_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,35 @@
161161
end
162162
end
163163
end
164+
165+
describe "#check" do
166+
context "when --gemfile-lock is not a valid lock file" do
167+
let(:bundle_dir) { File.expand_path(File.join('spec','bundle','unpatched_gems')) }
168+
let(:database_path) { Fixtures::Database::PATH }
169+
170+
it "must print an error message to stderr" do
171+
expect {
172+
begin
173+
described_class.start ['check', bundle_dir,
174+
'--gemfile-lock', 'Gemfile',
175+
'--database', database_path,
176+
'--no-update']
177+
rescue SystemExit
178+
end
179+
}.to output(/is not a valid Gemfile\.lock/).to_stderr
180+
end
181+
182+
it "must exit with status 1" do
183+
expect {
184+
described_class.start ['check', bundle_dir,
185+
'--gemfile-lock', 'Gemfile',
186+
'--database', database_path,
187+
'--no-update']
188+
}.to raise_error(SystemExit) do |error|
189+
expect(error.success?).to eq(false)
190+
expect(error.status).to eq(1)
191+
end
192+
end
193+
end
194+
end
164195
end

spec/scanner_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@
77

88
subject { described_class.new(directory) }
99

10+
describe "#initialize" do
11+
context "when given a non-lock file as gemfile_lock" do
12+
it "should raise InvalidGemfileLock" do
13+
expect {
14+
described_class.new(directory, 'Gemfile')
15+
}.to raise_error(Scanner::InvalidGemfileLock,/is not a valid Gemfile\.lock/)
16+
end
17+
end
18+
end
19+
1020
describe "#scan" do
1121
it "should yield results" do
1222
results = []

0 commit comments

Comments
 (0)