Skip to content

Commit 7607fe4

Browse files
kurotakyhsbt
authored andcommitted
Deprecate parsing non-lockfile content in LockfileParser
Bundler::LockfileParser#initialize silently accepted any string input, including Gemfiles or arbitrary text, producing an empty parser with no indication that the input was invalid. This caused downstream tooling like bundler-audit to operate on unvalidated content. Detect non-lockfile content by checking for any of the known section headers; empty input is left untouched for backward compatibility. Rather than raising immediately, emit a deprecation warning via SharedHelpers.feature_deprecated! announcing that a future Bundler version will raise LockfileError. Expose LockfileParser#valid? so callers can branch on the result without string-matching the message. Fixes #8932
1 parent c01e3b9 commit 7607fe4

2 files changed

Lines changed: 76 additions & 0 deletions

File tree

bundler/lib/bundler/lockfile_parser.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ def initialize(lockfile, strict: false)
115115
"Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock."
116116
end
117117

118+
@valid = lockfile.strip.empty? ||
119+
lockfile.split(/(?:\r?\n)+/).any? {|l| KNOWN_SECTIONS.include?(l) }
120+
121+
unless @valid
122+
SharedHelpers.feature_deprecated!(
123+
"Your #{@lockfile_path} does not appear to be a valid lockfile. " \
124+
"Run `rm #{@lockfile_path}` and then `bundle install` to generate a new lockfile. " \
125+
"This will raise a LockfileError in a future version of Bundler."
126+
)
127+
end
128+
118129
lockfile.split(/((?:\r?\n)+)/) do |line|
119130
# split alternates between the line and the following whitespace
120131
next @pos.advance!(line) if line.match?(/^\s*$/)
@@ -164,6 +175,10 @@ def may_include_redundant_platform_specific_gems?
164175
bundler_version.nil? || bundler_version < Gem::Version.new("1.16.2")
165176
end
166177

178+
def valid?
179+
@valid
180+
end
181+
167182
private
168183

169184
TYPES = {

spec/bundler/lockfile_parser_spec.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129

130130
shared_examples_for "parsing" do
131131
it "parses correctly" do
132+
expect(subject.valid?).to be(true)
132133
expect(subject.sources).to eq sources
133134
expect(subject.dependencies).to eq dependencies
134135
expect(subject.specs).to eq specs
@@ -191,6 +192,66 @@
191192
include_examples "parsing"
192193
end
193194

195+
context "when the content does not contain any recognized lockfile sections" do
196+
let(:lockfile_contents) { "hello world\nlorem ipsum\n" }
197+
198+
it "does not raise, is not valid, and deprecates" do
199+
expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
200+
/does not appear to be a valid lockfile.*future version of Bundler/m
201+
)
202+
parser = described_class.new(lockfile_contents)
203+
expect(parser.valid?).to be(false)
204+
expect(parser.specs).to eq([])
205+
expect(parser.dependencies).to eq({})
206+
end
207+
208+
it "does not raise when strict: true, and still deprecates" do
209+
expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
210+
/does not appear to be a valid lockfile.*future version of Bundler/m
211+
)
212+
parser = described_class.new(lockfile_contents, strict: true)
213+
expect(parser.valid?).to be(false)
214+
expect(parser.specs).to eq([])
215+
expect(parser.dependencies).to eq({})
216+
end
217+
end
218+
219+
context "when the content looks like a Gemfile DSL" do
220+
let(:lockfile_contents) { <<~G }
221+
source "https://rubygems.org"
222+
gem "rake"
223+
G
224+
225+
it "does not raise, is not valid, and deprecates" do
226+
expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
227+
/does not appear to be a valid lockfile.*future version of Bundler/m
228+
)
229+
parser = described_class.new(lockfile_contents)
230+
expect(parser.valid?).to be(false)
231+
expect(parser.specs).to eq([])
232+
expect(parser.dependencies).to eq({})
233+
end
234+
235+
it "does not raise when strict: true, and still deprecates" do
236+
expect(Bundler::SharedHelpers).to receive(:feature_deprecated!).with(
237+
/does not appear to be a valid lockfile.*future version of Bundler/m
238+
)
239+
parser = described_class.new(lockfile_contents, strict: true)
240+
expect(parser.valid?).to be(false)
241+
expect(parser.specs).to eq([])
242+
expect(parser.dependencies).to eq({})
243+
end
244+
end
245+
246+
context "when the content is empty" do
247+
let(:lockfile_contents) { "" }
248+
249+
it "does not raise and is valid" do
250+
expect { subject }.not_to raise_error
251+
expect(subject.valid?).to be(true)
252+
end
253+
end
254+
194255
context "when CHECKSUMS has duplicate checksums in the lockfile that don't match" do
195256
let(:bad_checksum) { "sha256=c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11" }
196257
let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) #{bad_checksum}\n").join }

0 commit comments

Comments
 (0)