RUBY-3903 Fix libmongocrypt version floor, ClientEncryption timeout_ms and missing range_opts - #3096
Merged
Merged
Conversation
The text algorithm binding added for QE text queries attaches mongocrypt_ctx_setopt_algorithm_text unconditionally, but the version gate still allowed 1.12.0. Older libmongocrypt passed the gate and then failed with a raw FFI::NotFoundError instead of the version error. 1.20.0 is what the GA text fixtures require (QE-Text-substring.yml, MONGOCRYPT-936) and matches the pinned libmongocrypt-helper.
ClientEncryption documents :timeout_ms but never forwarded it, so the timeout was silently ignored for every key management operation.
Encrypting with the Range algorithm and no :range_opts raised NoMethodError from nil.dup. Match the String algorithm, which reports the missing option. Also pins trim_factor: 0 with a spec: 0 is truthy in Ruby, so it is passed through, but the guard reads as if it might not be.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR applies three correctness fixes to the driver’s client-side encryption (Queryable Encryption) support: enforcing an appropriate libmongocrypt minimum version, ensuring ClientEncryption operation timeouts are actually applied, and improving the error surfaced when required Range algorithm options are missing.
Changes:
- Raise the minimum supported libmongocrypt version to 1.20.0 to match required QE text fixtures/bindings.
- Thread
:timeout_msfromMongo::ClientEncryptionintoCrypt::ExplicitEncrypterso CSOT is honored. - Raise a clear
ArgumentErrorwhenalgorithm: "Range"is used without:range_opts, and add specs for this behavior (includingtrim_factor: 0).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
lib/mongo/crypt/binding.rb |
Updates the libmongocrypt minimum version gate to prevent late FFI symbol failures. |
lib/mongo/client_encryption.rb |
Passes :timeout_ms into the explicit encrypter so timeouts take effect. |
lib/mongo/crypt/explicit_encryption_context.rb |
Adds an explicit ArgumentError when Range encryption is configured without :range_opts. |
spec/mongo/client_encryption_spec.rb |
Adds a spec that timeout_ms is propagated to the encrypter. |
spec/mongo/crypt/explicit_encryption_context_spec.rb |
Adds specs covering Range context initialization, trim_factor: 0, and missing :range_opts. |
Comments suppressed due to low confidence (1)
lib/mongo/crypt/explicit_encryption_context.rb:156
- In
convert_range_opts, theif opts[:trim_factor]guard is easy to misread as potentially dropping0values (even though0is truthy in Ruby), and it also won’t delete:trim_factorif the caller explicitly providestrim_factor: nil. Consider switching to akey?check and only settingtrimFactorwhen non-nil, to make intent unambiguous and keep the resulting options hash free of unexpected keys.
range_opts.dup.tap do |opts|
opts[:sparsity] = BSON::Int64.new(opts[:sparsity]) if opts[:sparsity] && !opts[:sparsity].is_a?(BSON::Int64)
opts[:trimFactor] = opts.delete(:trim_factor) if opts[:trim_factor]
end
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
jamis
approved these changes
Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three small QE fixes found while auditing the driver against the client-side-encryption
spec. Each is a separate commit.
Require libmongocrypt 1.20.0
#3088 attaches
mongocrypt_ctx_setopt_algorithm_textunconditionally, butMIN_LIBMONGOCRYPT_VERSIONstayed at 1.12.0. The version check runs atbinding.rb:136, well before thatattach_functionat line 1891, so an olderlibmongocrypt passes the gate and then dies with
instead of the intended "libmongocrypt version X or above is required". 1.20.0 is what
the GA text fixtures require (
QE-Text-substring.yml, MONGOCRYPT-936) and matches thelibmongocrypt-helper ~> 1.20.1pin.version_spec.rbderives its cases from theconstant, so it needs no change.
Pass timeout_ms from ClientEncryption to the encrypter
ClientEncryption#initializedocuments:timeout_msbut calledExplicitEncrypter.newwith four arguments, leaving the fifth (timeout_ms) nil.ExplicitEncrypterthreads@timeout_msinto every key management call, so CSOT onClientEncryptionwas silently dead. The new spec fails on master and passes here.Raise ArgumentError when range_opts is missing
encrypt(algorithm: 'Range')without:range_optsraisedNoMethodError: undefined method '[]' for nilout ofnil.dup.tap. Now it reports themissing option, matching how the
Stringalgorithm handles a missing:string_opts.The same commit adds a spec pinning
trim_factor: 0. The guardif opts[:trim_factor]reads like it would drop 0, but 0 is truthy in Ruby, so thevalue is passed through — the spec keeps it that way.