From d54208c5aa5478f8d500c0b9eb2fb8103d80c5ad Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 26 Jun 2026 15:48:00 -0600 Subject: [PATCH 1/4] RUBY-3667 BSON::ObjectId(object_id) returns its argument when it is already an ObjectId --- lib/bson.rb | 17 +++++++++++------ spec/bson_spec.rb | 20 ++++++++++++++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/bson.rb b/lib/bson.rb index 15a54f373..4e5b7f778 100644 --- a/lib/bson.rb +++ b/lib/bson.rb @@ -21,20 +21,25 @@ # @since 0.0.0 module BSON - # Create a new object id from a string using ObjectId.from_string + # Interprets the argument as an ObjectId. If given a BSON::ObjectId, this method + # returns it directly without creating a new one. Otherwise, the argument is + # interpreted as a string and parsed accordingly. # # @example Create an object id from the string. - # BSON::ObjectId(id) + # BSON::ObjectId('...') # - # @param [ String ] string The string to create the id from. + # @param [ String | BSON::ObjectId ] string_or_object_id The string to create the id from, + # or the existing object id to return. # # @raise [ BSON::Error::InvalidObjectId ] If the provided string is invalid. # - # @return [ BSON::ObjectId ] The new object id. + # @return [ BSON::ObjectId ] The new or existing object id. # # @see ObjectId.from_string - def self.ObjectId(string) - self::ObjectId.from_string(string) + def self.ObjectId(string_or_object_id) + return string_or_object_id if string_or_object_id.is_a?(self::ObjectId) + + self::ObjectId.from_string(string_or_object_id) end # Constant for binary string encoding. diff --git a/spec/bson_spec.rb b/spec/bson_spec.rb index d849b7158..d9e3d030c 100644 --- a/spec/bson_spec.rb +++ b/spec/bson_spec.rb @@ -19,11 +19,23 @@ describe ".ObjectId" do - let(:string) { "4e4d66343b39b68407000001" } + context 'when given a string' do + let(:string) { "4e4d66343b39b68407000001" } - it "returns an BSON::ObjectId from given string" do - expect(described_class::ObjectId(string)).to be_a BSON::ObjectId - expect(described_class::ObjectId(string)).to eq BSON::ObjectId.from_string(string) + it "returns an BSON::ObjectId from given string" do + expect(described_class::ObjectId(string)).to be_a BSON::ObjectId + expect(described_class::ObjectId(string)).to eq BSON::ObjectId.from_string(string) + end + end + + context 'when given an object id' do + let(:object_id) do + described_class::ObjectId.new + end + + it 'returns the same object' do + expect(described_class::ObjectId(object_id)).to be(object_id) + end end end From 0d1e90a3f0aa6620963595a44481c89f0c8dade3 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Fri, 26 Jun 2026 16:20:06 -0600 Subject: [PATCH 2/4] grammar fix Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- spec/bson_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bson_spec.rb b/spec/bson_spec.rb index d9e3d030c..3f304d173 100644 --- a/spec/bson_spec.rb +++ b/spec/bson_spec.rb @@ -22,7 +22,7 @@ context 'when given a string' do let(:string) { "4e4d66343b39b68407000001" } - it "returns an BSON::ObjectId from given string" do + it "returns a BSON::ObjectId from given string" do expect(described_class::ObjectId(string)).to be_a BSON::ObjectId expect(described_class::ObjectId(string)).to eq BSON::ObjectId.from_string(string) end From d150dbace3707bd102403a4daf82685ad08e2ed9 Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov <160598371+comandeo-mongo@users.noreply.github.com> Date: Wed, 10 Jun 2026 08:30:56 +0200 Subject: [PATCH 3/4] RUBY-3869 Validate Binary subtype 0x02 outer/inner length on decode (#370) --- lib/bson/binary.rb | 15 +++++++++++- spec/bson/binary_spec.rb | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/lib/bson/binary.rb b/lib/bson/binary.rb index e3fc78c27..74d84ffc8 100644 --- a/lib/bson/binary.rb +++ b/lib/bson/binary.rb @@ -306,7 +306,20 @@ def self.from_bson(buffer, **_options) type = type_byte end - length = buffer.get_int32 if type == :old + if type == :old + inner_length = buffer.get_int32 + unless inner_length == length - 4 + raise Error::BSONDecodeError, + "BSON binary subtype 0x02 length mismatch: outer=#{length}, inner=#{inner_length}" + end + length = inner_length + end + + if length.negative? + raise Error::BSONDecodeError, + "BSON binary length is negative: #{length}" + end + data = buffer.get_bytes(length) new(data, type) end diff --git a/spec/bson/binary_spec.rb b/spec/bson/binary_spec.rb index ded26f87d..15d5da05a 100644 --- a/spec/bson/binary_spec.rb +++ b/spec/bson/binary_spec.rb @@ -204,6 +204,58 @@ /BSON data contains unsupported binary subtype 0x10/) end end + + context 'when subtype 0x02 inner length is too long' do + let(:bson) do + ([6].pack('l<') + 2.chr + [3].pack('l<') + 'xxx').force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length mismatch.*outer=6.*inner=3/ + ) + end + end + + context 'when subtype 0x02 inner length is too short' do + let(:bson) do + ([6].pack('l<') + 2.chr + [1].pack('l<') + 'xxx').force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length mismatch.*outer=6.*inner=1/ + ) + end + end + + context 'when subtype 0x02 inner length is negative' do + let(:bson) do + ([6].pack('l<') + 2.chr + [-1].pack('l<') + 'xx').force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length mismatch.*outer=6.*inner=-1/ + ) + end + end + + context 'when non-old subtype outer length is negative' do + let(:bson) do + ([-1].pack('l<') + 0.chr).force_encoding('BINARY') + end + + it 'raises BSONDecodeError' do + expect { obj }.to raise_error( + BSON::Error::BSONDecodeError, + /length is negative.*-1/ + ) + end + end end describe "#to_bson/#from_bson" do From ef80623bf33dc6ff73ff54b9505c8cb900fb2f76 Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov <160598371+comandeo-mongo@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:17:30 +0200 Subject: [PATCH 4/4] RUBY-3872 Fix put_double TypeError message regex for Ruby head (#373) --- spec/bson/byte_buffer_write_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bson/byte_buffer_write_spec.rb b/spec/bson/byte_buffer_write_spec.rb index 0bff02c24..f39126a5c 100644 --- a/spec/bson/byte_buffer_write_spec.rb +++ b/spec/bson/byte_buffer_write_spec.rb @@ -508,7 +508,7 @@ it 'raises TypeError' do expect do modified - end.to raise_error(TypeError, /no implicit conversion to float from string|ClassCastException:.*RubyString cannot be cast to.*RubyFloat/) + end.to raise_error(TypeError, /no implicit conversion to float from string|no implicit conversion of String into Float|ClassCastException:.*RubyString cannot be cast to.*RubyFloat/) expect(buffer.write_position).to eq(0) end end