From 91260060647e6f0fdeb81fb909b25becfa2be47c Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Mon, 28 Jul 2025 08:53:20 -0400 Subject: [PATCH 01/22] draft options for QE text API --- .../client-side-encryption.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index 6e62c1f78b..9d581d8614 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -1256,6 +1256,7 @@ class EncryptOpts { contentionFactor: Optional, queryType: Optional rangeOpts: Optional + textOpts: Optional } // RangeOpts specifies index options for a Queryable Encryption field supporting "range" queries. @@ -1273,6 +1274,48 @@ class RangeOpts { // precision determines the number of significant digits after the decimal point. May only be set for double or decimal128. precision: Optional } + +// TextOpts specifies options for a Queryable Encryption field supporting "textPreview" queries. +// NOTE: TextOpts is currently unstable API and subject to backwards breaking changes. +class TextOpts { + // substring contains further options to support substring queries. + substring: Optional, + // prefix contains further options to support prefix queries. + prefix: Optional, + // suffix contains further options to support suffix queries. + suffix: Optional, + // caseSensitive determines whether text indexes for this field are case sensitive. + caseSensitive: bool, + // diacriticSensitive determines whether text indexes for this field are diacritic sensitive. + diacriticSensitive: bool +} + +// NOTE: SubstringOpts is currently unstable API and subject to backwards breaking changes. +class SubstringOpts { + // strMaxLength is the maximum allowed length to insert. Inserting longer strings will error. + strMaxLength: Int32, + // strMinQueryLength is the minimum allowed query length. Querying with a shorter string will error. + strMinQueryLength: Int32, + // strMaxQueryLength is the maximum allowed query length. Querying with a longer string will error. + strMaxQueryLength: Int32, +} + +// NOTE: PrefixOpts is currently unstable API and subject to backwards breaking changes. +class PrefixOpts { + // strMinQueryLength is the minimum allowed query length. Querying with a shorter string will error. + strMinQueryLength: Int32, + // strMaxQueryLength is the maximum allowed query length. Querying with a longer string will error. + strMaxQueryLength: Int32, +} + +// NOTE: SuffixOpts is currently unstable API and subject to backwards breaking changes. +class SuffixOpts { + // strMinQueryLength is the minimum allowed query length. Querying with a shorter string will error. + strMinQueryLength: Int32, + // strMaxQueryLength is the maximum allowed query length. Querying with a longer string will error. + strMaxQueryLength: Int32, +} + ``` Explicit encryption requires a key and algorithm. Keys are either identified by `_id` or by alternate name. Exactly one From 10d34d7eb217404711858fa506a55cf85ccb3a93 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Wed, 6 Aug 2025 00:12:52 -0700 Subject: [PATCH 02/22] tests draft --- source/client-side-encryption/tests/README.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index b56160d62f..6642e5c02f 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3764,3 +3764,110 @@ class AutoEncryptionOpts { ``` Assert that an error is thrown. + +### 27. Text Explicit Encryption + +The Text Explicit Encryption tests utilize Queryable Encryption (QE) range protocol V2 and require MongoDB server +8.2.0+ and libmongocrypt 1.15.0+. The tests must not run against a standalone. + +Before running each of the following test cases, perform the following Test Setup. + +#### Test Setup + +Load the file `encryptedFields-text.json` as `encryptedFields`. + +Load the file +[key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) +as `key1Document`. + +Read the `"_id"` field of `key1Document` as `key1ID`. + +Drop and create the collection `db.explicit_encryption` using `encryptedFields` as an option. See +[FLE 2 CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). + +Drop and create the collection `keyvault.datakeys`. + +Insert `key1Document` in `keyvault.datakeys` with majority write concern. + +Create a MongoClient named `keyVaultClient`. + +Create a ClientEncryption object named `clientEncryption` with these options: + +```typescript +class ClientEncryptionOpts { + keyVaultClient: , + keyVaultNamespace: "keyvault.datakeys", + kmsProviders: { "local": { "key": } }, +} +``` + +Create a MongoClient named `encryptedClient` with these `AutoEncryptionOpts`: + +```typescript +class AutoEncryptionOpts { + keyVaultNamespace: "keyvault.datakeys", + kmsProviders: { "local": { "key": } }, + bypassQueryAnalysis: true, +} +``` + +The remaining tasks require setting `TextOpts`. [Test Setup: TextOpts](#test-setup-textopts) lists the values to use +for `RangeOpts` for each of the supported data types. + +#### Test Setup: TextOpts + +This section lists the values to use for `TextOpts` for each query type. + +1. Prefix + + ```typescript + class PrefixOpts { + strMaxQueryLength: 3, + strMinQueryLength: 1, + } + ``` + +2. Suffix + + ```typescript + class SuffixOpts { + strMaxQueryLength: 3, + strMinQueryLength: 1, + } + ``` + +3. Substring + + ```typescript + class SubstringOpts { + strMaxLength: 10, + strMaxQueryLength: 3, + strMinQueryLength: 1, + } + ``` + +Use `clientEncryption` to encrypt the string "foobarbaz". Ensure the type matches that of the encrypted field. +For example, if the encrypted field is `encryptedDoubleNoPrecision` encrypt the value 6.0. + +Encrypt using the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + prefix: , + suffix: + }, +} +``` + +Use `encryptedClient` to insert the following document into `db.explicit_encryption`: + +```javascript +{ "_id": 0, "encryptedText": } +``` + From a36e1d04b20577d8eebdda48e4d3012e2a3f87cc Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Wed, 6 Aug 2025 08:09:55 -0400 Subject: [PATCH 03/22] update CHANGELOG and server support history --- source/client-side-encryption/client-side-encryption.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index 9d581d8614..7e522d0d3b 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -48,6 +48,8 @@ QEv1 and QEv2 are incompatible. MongoDB 8.0 dropped `queryType=rangePreview` and added `queryType=range` ([SPM-3583](https://jira.mongodb.org/browse/SPM-3583)). +MongoDB 8.2 added unstable support for QE text queries ([SPM-2880](https://jira.mongodb.org/browse/SPM-2880)) + ## META The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and @@ -2506,6 +2508,8 @@ explicit session parameter as described in the [Drivers Sessions Specification]( ## Changelog +- 2025-08-06: Add `TextPreview` algorithm. + - 2024-02-19: Add custom options AWS credential provider. - 2024-10-09: Add retry prose test. From 3f08d6d7fd801506484b58903b4926aa0ab2dc45 Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Wed, 6 Aug 2025 08:12:02 -0400 Subject: [PATCH 04/22] refer to text options in other sections --- .../client-side-encryption.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index 7e522d0d3b..878a4d3806 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -1340,17 +1340,18 @@ One of the strings: - "Indexed" - "Unindexed" - "Range" +- "TextPreview" -The result of explicit encryption with the "Indexed" or "Range" algorithm must be processed by the server to insert or +The result of explicit encryption with the "Indexed", "Range", or "TextPreview" algorithm must be processed by the server to insert or query. Drivers MUST document the following behavior: -> To insert or query with an "Indexed" or "Range" encrypted payload, use a `MongoClient` configured with +> To insert or query with an "Indexed", "Range", or "TextPreview" encrypted payload, use a `MongoClient` configured with > `AutoEncryptionOpts`. `AutoEncryptionOpts.bypassQueryAnalysis` may be true. `AutoEncryptionOpts.bypassAutoEncryption` > must be false. #### contentionFactor -contentionFactor may be used to tune performance. Only applies when algorithm is "Indexed" or "Range". libmongocrypt +contentionFactor may be used to tune performance. Only applies when algorithm is "Indexed", "Range", or "TextPreview". libmongocrypt returns an error if contentionFactor is set for a non-applicable algorithm. #### queryType @@ -1359,8 +1360,11 @@ One of the strings: - "equality" - "range" +- "prefixPreview" +- "suffixPreview" +- "substringPreview" -queryType only applies when algorithm is "Indexed" or "Range". libmongocrypt returns an error if queryType is set for a +queryType only applies when algorithm is "Indexed", "Range", or "TextPreview". libmongocrypt returns an error if queryType is set for a non-applicable queryType. #### rangeOpts @@ -1368,6 +1372,10 @@ non-applicable queryType. rangeOpts only applies when algorithm is "Range". libmongocrypt returns an error if rangeOpts is set for a non-applicable algorithm. +#### textOpts + +textOpts only applies when algorithm is "TextPreview". libmongocrypt returns an error if textOpts is set for a non-applicable algorithm. + ## User facing API: When Auto Encryption Fails Auto encryption requires parsing the MongoDB query language client side (with the [mongocryptd](#mongocryptd) process or From 8b74c4a987f837f2160cbb4f3e8aaef6fe181d43 Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Wed, 6 Aug 2025 08:12:24 -0400 Subject: [PATCH 05/22] fix comment There is no query type "textPreview". Use more generic term. --- source/client-side-encryption/client-side-encryption.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index 878a4d3806..31b34daba2 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -1277,7 +1277,7 @@ class RangeOpts { precision: Optional } -// TextOpts specifies options for a Queryable Encryption field supporting "textPreview" queries. +// TextOpts specifies options for a Queryable Encryption field supporting text queries. // NOTE: TextOpts is currently unstable API and subject to backwards breaking changes. class TextOpts { // substring contains further options to support substring queries. From 7bacf36706700efdf6e5b43309a6ce324552e76a Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Wed, 6 Aug 2025 08:26:06 -0400 Subject: [PATCH 06/22] format --- .../client-side-encryption.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index 31b34daba2..ff2f0fe8a5 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -1342,8 +1342,8 @@ One of the strings: - "Range" - "TextPreview" -The result of explicit encryption with the "Indexed", "Range", or "TextPreview" algorithm must be processed by the server to insert or -query. Drivers MUST document the following behavior: +The result of explicit encryption with the "Indexed", "Range", or "TextPreview" algorithm must be processed by the +server to insert or query. Drivers MUST document the following behavior: > To insert or query with an "Indexed", "Range", or "TextPreview" encrypted payload, use a `MongoClient` configured with > `AutoEncryptionOpts`. `AutoEncryptionOpts.bypassQueryAnalysis` may be true. `AutoEncryptionOpts.bypassAutoEncryption` @@ -1351,8 +1351,8 @@ query. Drivers MUST document the following behavior: #### contentionFactor -contentionFactor may be used to tune performance. Only applies when algorithm is "Indexed", "Range", or "TextPreview". libmongocrypt -returns an error if contentionFactor is set for a non-applicable algorithm. +contentionFactor may be used to tune performance. Only applies when algorithm is "Indexed", "Range", or "TextPreview". +libmongocrypt returns an error if contentionFactor is set for a non-applicable algorithm. #### queryType @@ -1364,8 +1364,8 @@ One of the strings: - "suffixPreview" - "substringPreview" -queryType only applies when algorithm is "Indexed", "Range", or "TextPreview". libmongocrypt returns an error if queryType is set for a -non-applicable queryType. +queryType only applies when algorithm is "Indexed", "Range", or "TextPreview". libmongocrypt returns an error if +queryType is set for a non-applicable queryType. #### rangeOpts @@ -1374,7 +1374,8 @@ non-applicable algorithm. #### textOpts -textOpts only applies when algorithm is "TextPreview". libmongocrypt returns an error if textOpts is set for a non-applicable algorithm. +textOpts only applies when algorithm is "TextPreview". libmongocrypt returns an error if textOpts is set for a +non-applicable algorithm. ## User facing API: When Auto Encryption Fails From 541c35873109578e31187d010a598aa67e0c4398 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Wed, 6 Aug 2025 12:25:43 -0700 Subject: [PATCH 07/22] prefix and suffix tests --- source/client-side-encryption/tests/README.md | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 6642e5c02f..a3c0d597b4 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3846,8 +3846,7 @@ This section lists the values to use for `TextOpts` for each query type. } ``` -Use `clientEncryption` to encrypt the string "foobarbaz". Ensure the type matches that of the encrypted field. -For example, if the encrypted field is `encryptedDoubleNoPrecision` encrypt the value 6.0. +Use `clientEncryption` to encrypt the string "foobarbaz". Encrypt using the following `EncryptOpts`: @@ -3871,3 +3870,58 @@ Use `encryptedClient` to insert the following document into `db.explicit_encrypt { "_id": 0, "encryptedText": } ``` +#### Case 1: can find a document by prefix + +Use `clientEncryption.encryptExpression()` to encrypt this query: +```javascript +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": "foo"}, } } +``` + +Store the result in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Assert the following document is returned: + +```javascript +{ "_id": 0, "encryptedText": "foobarbaz" } +``` + +#### Case 2: can find a document by suffix + +Use `clientEncryption.encryptExpression()` to encrypt this query: +```javascript +{ "$expr": { "$encStrEndsWith": {"input": "encryptedText", "suffix": "baz"}, } } +``` + +Store the result in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Assert the following document is returned: + +```javascript +{ "_id": 0, "encryptedText": "foobarbaz" } +``` + +#### Case 3: assert no document found by prefix + +Use `clientEncryption.encryptExpression()` to encrypt this query: +```javascript +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": "baz"}, } } +``` + +Store the result in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Assert that no documents are returned. + +#### Case 4: assert no document found by suffix + +Use `clientEncryption.encryptExpression()` to encrypt this query: +```javascript +{ "$expr": { "$encStrEndsWith": {"input": "encryptedText", "suffix": "baz"}, } } +``` + +Store the result in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Assert that no documents are returned. \ No newline at end of file From 6b560e17ff6bad2d2ce3e9ea6ce1382542d8a780 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Wed, 6 Aug 2025 20:06:09 -0700 Subject: [PATCH 08/22] encrypt just the value, not query --- .../data/encryptedFields-prefix-suffix.json | 38 ++++++ .../etc/data/encryptedFields-substring.json | 30 +++++ source/client-side-encryption/tests/README.md | 123 +++++++++++++++--- 3 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json create mode 100644 source/client-side-encryption/etc/data/encryptedFields-substring.json diff --git a/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json b/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json new file mode 100644 index 0000000000..8c52b6dd0a --- /dev/null +++ b/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json @@ -0,0 +1,38 @@ +{ + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encrypted-textPreview", + "bsonType": "string", + "queries": [ + { + "queryType": "prefixPreview", + "strMinQueryLength": { + "$numberInt": "2" + }, + "strMaxQueryLength": { + "$numberInt": "10" + }, + "caseSensitive": true, + "diacriticSensitive": true + }, + { + "queryType": "suffixPreview", + "strMinQueryLength": { + "$numberInt": "2" + }, + "strMaxQueryLength": { + "$numberInt": "10" + }, + "caseSensitive": true, + "diacriticSensitive": true + } + ] + } + ] +} diff --git a/source/client-side-encryption/etc/data/encryptedFields-substring.json b/source/client-side-encryption/etc/data/encryptedFields-substring.json new file mode 100644 index 0000000000..cb97a16717 --- /dev/null +++ b/source/client-side-encryption/etc/data/encryptedFields-substring.json @@ -0,0 +1,30 @@ +{ + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encrypted-textPreview", + "bsonType": "string", + "queries": [ + { + "queryType": "substringPreview", + "strMaxLength": { + "$numberInt": "10" + }, + "strMinQueryLength": { + "$numberInt": "2" + }, + "strMaxQueryLength": { + "$numberInt": "10" + }, + "caseSensitive": true, + "diacriticSensitive": true + } + ] + } + ] +} diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index a3c0d597b4..bddd1f1b24 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3774,7 +3774,7 @@ Before running each of the following test cases, perform the following Test Setu #### Test Setup -Load the file `encryptedFields-text.json` as `encryptedFields`. +Load the file `encryptedFields-prefix-suffix.json` as `encryptedFields`. Load the file [key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) @@ -3812,18 +3812,32 @@ class AutoEncryptionOpts { ``` The remaining tasks require setting `TextOpts`. [Test Setup: TextOpts](#test-setup-textopts) lists the values to use -for `RangeOpts` for each of the supported data types. +for `TextOpts` for each of the supported data types. #### Test Setup: TextOpts -This section lists the values to use for `TextOpts` for each query type. +This section lists the values to use for `TextOpts` for each query type. Include the matching options in the following +`EncryptOpts` for each query: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + : + }, +} +``` 1. Prefix ```typescript class PrefixOpts { - strMaxQueryLength: 3, - strMinQueryLength: 1, + strMaxQueryLength: 10, + strMinQueryLength: 2, } ``` @@ -3831,8 +3845,8 @@ This section lists the values to use for `TextOpts` for each query type. ```typescript class SuffixOpts { - strMaxQueryLength: 3, - strMinQueryLength: 1, + strMaxQueryLength: 10, + strMinQueryLength: 2, } ``` @@ -3841,12 +3855,12 @@ This section lists the values to use for `TextOpts` for each query type. ```typescript class SubstringOpts { strMaxLength: 10, - strMaxQueryLength: 3, - strMinQueryLength: 1, + strMaxQueryLength: 10, + strMinQueryLength: 2, } ``` -Use `clientEncryption` to encrypt the string "foobarbaz". +Use `clientEncryption` to encrypt the string `"foobarbaz"`. Encrypt using the following `EncryptOpts`: @@ -3872,12 +3886,12 @@ Use `encryptedClient` to insert the following document into `db.explicit_encrypt #### Case 1: can find a document by prefix -Use `clientEncryption.encryptExpression()` to encrypt this query: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: + +Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": "foo"}, } } +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` - -Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. Assert the following document is returned: @@ -3888,9 +3902,11 @@ Assert the following document is returned: #### Case 2: can find a document by suffix -Use `clientEncryption.encryptExpression()` to encrypt this query: +Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: + +Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrEndsWith": {"input": "encryptedText", "suffix": "baz"}, } } +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. @@ -3904,9 +3920,11 @@ Assert the following document is returned: #### Case 3: assert no document found by prefix -Use `clientEncryption.encryptExpression()` to encrypt this query: +Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: + +Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": "baz"}, } } +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. @@ -3916,9 +3934,74 @@ Assert that no documents are returned. #### Case 4: assert no document found by suffix -Use `clientEncryption.encryptExpression()` to encrypt this query: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: + +Store this query in `findPayload`. +```javascript +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "suffix": }, } } +``` + +Store the result in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Assert that no documents are returned. + +#### Substring test setup +Load the file `encryptedFields-substring.json` as `encryptedFields`. + +Load the file +[key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) +as `key1Document`. + +Drop and create the collection `db.explicit_encryption` using `encryptedFields` as an option. + +Use `clientEncryption` to encrypt the string `"foobarbaz"`. + +Encrypt using the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + substring: + }, +} +``` + +Use `encryptedClient` to insert the following document into `db.explicit_encryption`: + +```javascript +{ "_id": 0, "encryptedText": } +``` + +#### Case 5: can find a document by substring +Use `clientEncryption.encrypt()` to encrypt the string `"bar"`: + +Store this query in `findPayload`. +```javascript +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } +``` + +Store the result in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Assert the following document is returned: + +```javascript +{ "_id": 0, "encryptedText": "foobarbaz" } +``` + +#### Case 6: assert no document found by substring + +Use `clientEncryption.encrypt()` to encrypt the string `"qux"`: + +Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrEndsWith": {"input": "encryptedText", "suffix": "baz"}, } } +{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. From 21ad2cc8d0e248232ec787a6f49382641efc4813 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Wed, 6 Aug 2025 20:19:57 -0700 Subject: [PATCH 09/22] format --- source/client-side-encryption/tests/README.md | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index bddd1f1b24..a4d1285d49 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3767,8 +3767,8 @@ Assert that an error is thrown. ### 27. Text Explicit Encryption -The Text Explicit Encryption tests utilize Queryable Encryption (QE) range protocol V2 and require MongoDB server -8.2.0+ and libmongocrypt 1.15.0+. The tests must not run against a standalone. +The Text Explicit Encryption tests utilize Queryable Encryption (QE) range protocol V2 and require MongoDB server 8.2.0+ +and libmongocrypt 1.15.0+. The tests must not run against a standalone. Before running each of the following test cases, perform the following Test Setup. @@ -3811,8 +3811,8 @@ class AutoEncryptionOpts { } ``` -The remaining tasks require setting `TextOpts`. [Test Setup: TextOpts](#test-setup-textopts) lists the values to use -for `TextOpts` for each of the supported data types. +The remaining tasks require setting `TextOpts`. [Test Setup: TextOpts](#test-setup-textopts) lists the values to use for +`TextOpts` for each of the supported data types. #### Test Setup: TextOpts @@ -3889,10 +3889,13 @@ Use `encryptedClient` to insert the following document into `db.explicit_encrypt Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: Store this query in `findPayload`. + ```javascript { "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. + +Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter +`findPayload`. Assert the following document is returned: @@ -3905,12 +3908,13 @@ Assert the following document is returned: Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: Store this query in `findPayload`. + ```javascript { "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. +Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` +collection with the filter `findPayload`. Assert the following document is returned: @@ -3923,12 +3927,13 @@ Assert the following document is returned: Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: Store this query in `findPayload`. + ```javascript { "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. +Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` +collection with the filter `findPayload`. Assert that no documents are returned. @@ -3937,16 +3942,18 @@ Assert that no documents are returned. Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: Store this query in `findPayload`. + ```javascript { "$expr": { "$encStrStartsWith": {"input": "encryptedText", "suffix": }, } } ``` -Store the result in `findPayload`. -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. +Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` +collection with the filter `findPayload`. Assert that no documents are returned. #### Substring test setup + Load the file `encryptedFields-substring.json` as `encryptedFields`. Load the file @@ -3979,15 +3986,17 @@ Use `encryptedClient` to insert the following document into `db.explicit_encrypt ``` #### Case 5: can find a document by substring + Use `clientEncryption.encrypt()` to encrypt the string `"bar"`: Store this query in `findPayload`. + ```javascript { "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. +Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` +collection with the filter `findPayload`. Assert the following document is returned: @@ -4000,11 +4009,12 @@ Assert the following document is returned: Use `clientEncryption.encrypt()` to encrypt the string `"qux"`: Store this query in `findPayload`. + ```javascript { "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter `findPayload`. +Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` +collection with the filter `findPayload`. -Assert that no documents are returned. \ No newline at end of file +Assert that no documents are returned. From 1169224f005aa97a7db433adf140b3796423866a Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Wed, 6 Aug 2025 20:30:42 -0700 Subject: [PATCH 10/22] changelog --- source/client-side-encryption/client-side-encryption.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index ff2f0fe8a5..e475f3dc2b 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -2517,6 +2517,8 @@ explicit session parameter as described in the [Drivers Sessions Specification]( ## Changelog +- 2025-08-06: Add `TextPreview` prose tests. + - 2025-08-06: Add `TextPreview` algorithm. - 2024-02-19: Add custom options AWS credential provider. From 6d144d4b7e7af602707d6d4f7a605680d11d9dd3 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Thu, 7 Aug 2025 23:38:31 -0700 Subject: [PATCH 11/22] wording suggestions --- .../client-side-encryption.md | 7 +-- source/client-side-encryption/tests/README.md | 51 ++++++++++--------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index e475f3dc2b..7531b98fe8 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -1348,6 +1348,9 @@ server to insert or query. Drivers MUST document the following behavior: > To insert or query with an "Indexed", "Range", or "TextPreview" encrypted payload, use a `MongoClient` configured with > `AutoEncryptionOpts`. `AutoEncryptionOpts.bypassQueryAnalysis` may be true. `AutoEncryptionOpts.bypassAutoEncryption` > must be false. +> The "TextPreview" algorithm is in preview and should be used for experimental workloads only. These features are +> unstable and their security is not guaranteed until released as Generally Available (GA). The GA version of these +> features may not be backwards compatible with the preview version. #### contentionFactor @@ -1365,7 +1368,7 @@ One of the strings: - "substringPreview" queryType only applies when algorithm is "Indexed", "Range", or "TextPreview". libmongocrypt returns an error if -queryType is set for a non-applicable queryType. +queryType is set for a non-applicable algorithm. #### rangeOpts @@ -2517,8 +2520,6 @@ explicit session parameter as described in the [Drivers Sessions Specification]( ## Changelog -- 2025-08-06: Add `TextPreview` prose tests. - - 2025-08-06: Add `TextPreview` algorithm. - 2024-02-19: Add custom options AWS credential provider. diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index a4d1285d49..ce0fabb3f8 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3783,7 +3783,7 @@ as `key1Document`. Read the `"_id"` field of `key1Document` as `key1ID`. Drop and create the collection `db.explicit_encryption` using `encryptedFields` as an option. See -[FLE 2 CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). +[QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). Drop and create the collection `keyvault.datakeys`. @@ -3811,6 +3811,30 @@ class AutoEncryptionOpts { } ``` +Use `clientEncryption` to encrypt the string `"foobarbaz"`. + +Encrypt using the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + prefix: , + suffix: + }, +} +``` + +Use `encryptedClient` to insert the following document into `db.explicit_encryption`: + +```javascript +{ "_id": 0, "encryptedText": } +``` + The remaining tasks require setting `TextOpts`. [Test Setup: TextOpts](#test-setup-textopts) lists the values to use for `TextOpts` for each of the supported data types. @@ -3823,6 +3847,7 @@ This section lists the values to use for `TextOpts` for each query type. Include class EncryptOpts { keyId : , algorithm: "TextPreview", + queryType: "Preview", contentionFactor: 0, textOpts: TextOpts { caseSensitive: true, @@ -3860,30 +3885,6 @@ class EncryptOpts { } ``` -Use `clientEncryption` to encrypt the string `"foobarbaz"`. - -Encrypt using the following `EncryptOpts`: - -```typescript -class EncryptOpts { - keyId : , - algorithm: "TextPreview", - contentionFactor: 0, - textOpts: TextOpts { - caseSensitive: true, - diacriticSensitive: true, - prefix: , - suffix: - }, -} -``` - -Use `encryptedClient` to insert the following document into `db.explicit_encryption`: - -```javascript -{ "_id": 0, "encryptedText": } -``` - #### Case 1: can find a document by prefix Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: From eaa1d254dee51bfd7b43076dbc91e9aeb1183cb8 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Thu, 7 Aug 2025 23:39:36 -0700 Subject: [PATCH 12/22] input field needs dollar sign --- source/client-side-encryption/tests/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index ce0fabb3f8..49434b3494 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3892,7 +3892,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter @@ -3911,7 +3911,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` @@ -3930,7 +3930,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` @@ -3945,7 +3945,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "suffix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "suffix": }, } } ``` Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` @@ -3993,7 +3993,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"bar"`: Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` @@ -4012,7 +4012,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"qux"`: Store this query in `findPayload`. ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` From 8605a541c00811af99acc0ce458104dbd2f34cca Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Thu, 7 Aug 2025 23:51:55 -0700 Subject: [PATCH 13/22] use separate collections for prefix/suffix and substring --- source/client-side-encryption/tests/README.md | 121 +++++++----------- 1 file changed, 49 insertions(+), 72 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 49434b3494..0638133614 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3774,7 +3774,9 @@ Before running each of the following test cases, perform the following Test Setu #### Test Setup -Load the file `encryptedFields-prefix-suffix.json` as `encryptedFields`. +Load the file `encryptedFields-prefix-suffix.json` as `encryptedFields-prefix-suffix`. + +Load the file `encryptedFields-substring.json` as `encryptedFields-substring`. Load the file [key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) @@ -3782,7 +3784,10 @@ as `key1Document`. Read the `"_id"` field of `key1Document` as `key1ID`. -Drop and create the collection `db.explicit_encryption` using `encryptedFields` as an option. See +Drop and create the collection `db.prefix-suffix` using `encryptedFields-prefix-suffix` as an option. See +[QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). + +Drop and create the collection `db.substring` using `encryptedFields-substring` as an option. See [QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). Drop and create the collection `keyvault.datakeys`. @@ -3829,7 +3834,30 @@ class EncryptOpts { } ``` -Use `encryptedClient` to insert the following document into `db.explicit_encryption`: +Use `encryptedClient` to insert the following document into `db.prefix-suffix`: + +```javascript +{ "_id": 0, "encryptedText": } +``` + +Use `clientEncryption` to encrypt the string `"foobarbaz"`. + +Encrypt using the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + substring: + }, +} +``` + +Use `encryptedClient` to insert the following document into `db.substring`: ```javascript { "_id": 0, "encryptedText": } @@ -3887,17 +3915,14 @@ class EncryptOpts { #### Case 1: can find a document by prefix -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. -Store this query in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` -Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` collection with the filter -`findPayload`. - Assert the following document is returned: ```javascript @@ -3906,17 +3931,14 @@ Assert the following document is returned: #### Case 2: can find a document by suffix -Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. -Store this query in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` -collection with the filter `findPayload`. - Assert the following document is returned: ```javascript @@ -3925,80 +3947,38 @@ Assert the following document is returned: #### Case 3: assert no document found by prefix -Use `clientEncryption.encrypt()` to encrypt the string `"baz"`: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. -Store this query in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` -collection with the filter `findPayload`. - Assert that no documents are returned. #### Case 4: assert no document found by suffix -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. -Store this query in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "suffix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "suffix": }, } } ``` -Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` -collection with the filter `findPayload`. - Assert that no documents are returned. -#### Substring test setup - -Load the file `encryptedFields-substring.json` as `encryptedFields`. - -Load the file -[key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) -as `key1Document`. - -Drop and create the collection `db.explicit_encryption` using `encryptedFields` as an option. - -Use `clientEncryption` to encrypt the string `"foobarbaz"`. - -Encrypt using the following `EncryptOpts`: - -```typescript -class EncryptOpts { - keyId : , - algorithm: "TextPreview", - contentionFactor: 0, - textOpts: TextOpts { - caseSensitive: true, - diacriticSensitive: true, - substring: - }, -} -``` - -Use `encryptedClient` to insert the following document into `db.explicit_encryption`: - -```javascript -{ "_id": 0, "encryptedText": } -``` - #### Case 5: can find a document by substring -Use `clientEncryption.encrypt()` to encrypt the string `"bar"`: +Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. -Store this query in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` -collection with the filter `findPayload`. - Assert the following document is returned: ```javascript @@ -4007,15 +3987,12 @@ Assert the following document is returned: #### Case 6: assert no document found by substring -Use `clientEncryption.encrypt()` to encrypt the string `"qux"`: +Use `clientEncryption.encrypt()` to encrypt the string `"qux"`. Store the resulting payload in `findPayload`. -Store this query in `findPayload`. +Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } ``` -Store the result in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.explicit_encryption` -collection with the filter `findPayload`. - Assert that no documents are returned. From 0ffe96c507cb63c861ddb2a2ff4300c9094ab08e Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Fri, 8 Aug 2025 00:04:06 -0700 Subject: [PATCH 14/22] format --- source/client-side-encryption/client-side-encryption.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/client-side-encryption/client-side-encryption.md b/source/client-side-encryption/client-side-encryption.md index 7531b98fe8..29f7e4eba3 100644 --- a/source/client-side-encryption/client-side-encryption.md +++ b/source/client-side-encryption/client-side-encryption.md @@ -1347,10 +1347,9 @@ server to insert or query. Drivers MUST document the following behavior: > To insert or query with an "Indexed", "Range", or "TextPreview" encrypted payload, use a `MongoClient` configured with > `AutoEncryptionOpts`. `AutoEncryptionOpts.bypassQueryAnalysis` may be true. `AutoEncryptionOpts.bypassAutoEncryption` -> must be false. -> The "TextPreview" algorithm is in preview and should be used for experimental workloads only. These features are -> unstable and their security is not guaranteed until released as Generally Available (GA). The GA version of these -> features may not be backwards compatible with the preview version. +> must be false. The "TextPreview" algorithm is in preview and should be used for experimental workloads only. These +> features are unstable and their security is not guaranteed until released as Generally Available (GA). The GA version +> of these features may not be backwards compatible with the preview version. #### contentionFactor From f2b247882c7f97594908fc60d4c5238c5aba577f Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:17:04 -0700 Subject: [PATCH 15/22] format --- .../data/encryptedFields-prefix-suffix.json | 2 +- .../etc/data/encryptedFields-substring.json | 2 +- source/client-side-encryption/tests/README.md | 74 ++++++++++--------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json b/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json index 8c52b6dd0a..ec4489fa09 100644 --- a/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json +++ b/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json @@ -7,7 +7,7 @@ "subType": "04" } }, - "path": "encrypted-textPreview", + "path": "encryptedText", "bsonType": "string", "queries": [ { diff --git a/source/client-side-encryption/etc/data/encryptedFields-substring.json b/source/client-side-encryption/etc/data/encryptedFields-substring.json index cb97a16717..ee22def77b 100644 --- a/source/client-side-encryption/etc/data/encryptedFields-substring.json +++ b/source/client-side-encryption/etc/data/encryptedFields-substring.json @@ -7,7 +7,7 @@ "subType": "04" } }, - "path": "encrypted-textPreview", + "path": "encryptedText", "bsonType": "string", "queries": [ { diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 0638133614..86287782f4 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3834,6 +3834,36 @@ class EncryptOpts { } ``` +Where prefix, suffix, or substring options are required, use the following: + +1. Prefix + + ```typescript + class PrefixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + ``` + +2. Suffix + + ```typescript + class SuffixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + ``` + +3. Substring + + ```typescript + class SubstringOpts { + strMaxLength: 10, + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + ``` + Use `encryptedClient` to insert the following document into `db.prefix-suffix`: ```javascript @@ -3885,34 +3915,6 @@ class EncryptOpts { } ``` -1. Prefix - - ```typescript - class PrefixOpts { - strMaxQueryLength: 10, - strMinQueryLength: 2, - } - ``` - -2. Suffix - - ```typescript - class SuffixOpts { - strMaxQueryLength: 10, - strMinQueryLength: 2, - } - ``` - -3. Substring - - ```typescript - class SubstringOpts { - strMaxLength: 10, - strMaxQueryLength: 10, - strMinQueryLength: 2, - } - ``` - #### Case 1: can find a document by prefix Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. @@ -3920,7 +3922,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: }, } } ``` Assert the following document is returned: @@ -3931,12 +3933,12 @@ Assert the following document is returned: #### Case 2: can find a document by suffix -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"baz"`. Store the resulting payload in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: }, } } ``` Assert the following document is returned: @@ -3947,12 +3949,12 @@ Assert the following document is returned: #### Case 3: assert no document found by prefix -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"baz"`. Store the resulting payload in `findPayload`. Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: }, } } ``` Assert that no documents are returned. @@ -3964,7 +3966,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "suffix": }, } } +{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: }, } } ``` Assert that no documents are returned. @@ -3976,7 +3978,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ $expr: { $encStrContains: {input: '$encryptedText', substring: }, } } ``` Assert the following document is returned: @@ -3992,7 +3994,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"qux"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ "$expr": { "$encStrStartsWith": {"input": "$encryptedText", "prefix": }, } } +{ $expr: { $encStrContains: {input: '$encryptedText', substring: }, } } ``` Assert that no documents are returned. From 190bf16a22b60382cdb03ff7b00fa21a3f25bfb2 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:22:51 -0700 Subject: [PATCH 16/22] move per index opts --- source/client-side-encryption/tests/README.md | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 86287782f4..674c028ee3 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3816,24 +3816,6 @@ class AutoEncryptionOpts { } ``` -Use `clientEncryption` to encrypt the string `"foobarbaz"`. - -Encrypt using the following `EncryptOpts`: - -```typescript -class EncryptOpts { - keyId : , - algorithm: "TextPreview", - contentionFactor: 0, - textOpts: TextOpts { - caseSensitive: true, - diacriticSensitive: true, - prefix: , - suffix: - }, -} -``` - Where prefix, suffix, or substring options are required, use the following: 1. Prefix @@ -3864,6 +3846,24 @@ Where prefix, suffix, or substring options are required, use the following: } ``` +Use `clientEncryption` to encrypt the string `"foobarbaz"`. + +Encrypt using the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + prefix: , + suffix: + }, +} +``` + Use `encryptedClient` to insert the following document into `db.prefix-suffix`: ```javascript @@ -3922,7 +3922,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: }, } } +{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: } } } ``` Assert the following document is returned: @@ -3938,7 +3938,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"baz"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: }, } } +{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: } } } ``` Assert the following document is returned: @@ -3954,7 +3954,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"baz"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: }, } } +{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: } } } ``` Assert that no documents are returned. @@ -3966,7 +3966,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: }, } } +{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: } } } ``` Assert that no documents are returned. @@ -3978,7 +3978,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ $expr: { $encStrContains: {input: '$encryptedText', substring: }, } } +{ $expr: { $encStrContains: {input: '$encryptedText', substring: } } } ``` Assert the following document is returned: @@ -3994,7 +3994,7 @@ Use `clientEncryption.encrypt()` to encrypt the string `"qux"`. Store the result Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ $expr: { $encStrContains: {input: '$encryptedText', substring: }, } } +{ $expr: { $encStrContains: {input: '$encryptedText', substring: } } } ``` Assert that no documents are returned. From 6a652876087eb29b9458c44b1ef25d1c8b003b22 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:23:50 -0700 Subject: [PATCH 17/22] require libmongocrypt 1.15.1 --- source/client-side-encryption/tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 674c028ee3..b43cdec401 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3768,7 +3768,7 @@ Assert that an error is thrown. ### 27. Text Explicit Encryption The Text Explicit Encryption tests utilize Queryable Encryption (QE) range protocol V2 and require MongoDB server 8.2.0+ -and libmongocrypt 1.15.0+. The tests must not run against a standalone. +and libmongocrypt 1.15.1+. The tests must not run against a standalone. Before running each of the following test cases, perform the following Test Setup. From bfbac44bb4412c97ebea0fe5c68df3eee1afd88e Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:06:59 -0700 Subject: [PATCH 18/22] simplifications Co-authored-by: Kevin Albertson --- source/client-side-encryption/tests/README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index b43cdec401..a62cbda72b 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3846,9 +3846,7 @@ Where prefix, suffix, or substring options are required, use the following: } ``` -Use `clientEncryption` to encrypt the string `"foobarbaz"`. - -Encrypt using the following `EncryptOpts`: +Use `clientEncryption` to encrypt the string `"foobarbaz"` with the following `EncryptOpts`: ```typescript class EncryptOpts { @@ -3870,9 +3868,7 @@ Use `encryptedClient` to insert the following document into `db.prefix-suffix`: { "_id": 0, "encryptedText": } ``` -Use `clientEncryption` to encrypt the string `"foobarbaz"`. - -Encrypt using the following `EncryptOpts`: +Use `clientEncryption` to encrypt the string `"foobarbaz"` with the following `EncryptOpts`: ```typescript class EncryptOpts { From 8c4d5c8b32efc644bf76b50a72415be37999a97d Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:27:22 -0700 Subject: [PATCH 19/22] test structure suggestions --- source/client-side-encryption/tests/README.md | 186 +++++++++++++----- 1 file changed, 132 insertions(+), 54 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index a62cbda72b..21e30ee7ee 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3774,9 +3774,9 @@ Before running each of the following test cases, perform the following Test Setu #### Test Setup -Load the file `encryptedFields-prefix-suffix.json` as `encryptedFields-prefix-suffix`. - -Load the file `encryptedFields-substring.json` as `encryptedFields-substring`. +Using [QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper), drop and create the following collections: +- `db.prefix-suffix` using the `encryptedFields` option set to the contents of [encryptedFields-prefix-suffix.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json) +- `db.substring` using the `encryptedFields` option set to the contents of [encryptedFields-substring.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-substring.json) Load the file [key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) @@ -3784,12 +3784,6 @@ as `key1Document`. Read the `"_id"` field of `key1Document` as `key1ID`. -Drop and create the collection `db.prefix-suffix` using `encryptedFields-prefix-suffix` as an option. See -[QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). - -Drop and create the collection `db.substring` using `encryptedFields-substring` as an option. See -[QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper). - Drop and create the collection `keyvault.datakeys`. Insert `key1Document` in `keyvault.datakeys` with majority write concern. @@ -3816,36 +3810,6 @@ class AutoEncryptionOpts { } ``` -Where prefix, suffix, or substring options are required, use the following: - -1. Prefix - - ```typescript - class PrefixOpts { - strMaxQueryLength: 10, - strMinQueryLength: 2, - } - ``` - -2. Suffix - - ```typescript - class SuffixOpts { - strMaxQueryLength: 10, - strMinQueryLength: 2, - } - ``` - -3. Substring - - ```typescript - class SubstringOpts { - strMaxLength: 10, - strMaxQueryLength: 10, - strMinQueryLength: 2, - } - ``` - Use `clientEncryption` to encrypt the string `"foobarbaz"` with the following `EncryptOpts`: ```typescript @@ -3856,8 +3820,14 @@ class EncryptOpts { textOpts: TextOpts { caseSensitive: true, diacriticSensitive: true, - prefix: , - suffix: + prefix: PrefixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + }, + suffix: SuffixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + }, }, } ``` @@ -3878,7 +3848,11 @@ class EncryptOpts { textOpts: TextOpts { caseSensitive: true, diacriticSensitive: true, - substring: + substring: SubstringOpts { + strMaxLength: 10, + strMaxQueryLength: 10, + strMinQueryLength: 2, + } }, } ``` @@ -3913,12 +3887,29 @@ class EncryptOpts { #### Case 1: can find a document by prefix -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"foo"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "prefixPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + prefix: PrefixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: } } } +{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: } } } ``` Assert the following document is returned: @@ -3929,12 +3920,29 @@ Assert the following document is returned: #### Case 2: can find a document by suffix -Use `clientEncryption.encrypt()` to encrypt the string `"baz"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"baz"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "suffixPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + suffix: SuffixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: } } } +{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: } } } ``` Assert the following document is returned: @@ -3945,36 +3953,88 @@ Assert the following document is returned: #### Case 3: assert no document found by prefix -Use `clientEncryption.encrypt()` to encrypt the string `"baz"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"baz"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "prefixPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + prefix: PrefixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: } } } +{ $expr: { $encStrStartsWith: {input: '$encryptedText', prefix: } } } ``` Assert that no documents are returned. #### Case 4: assert no document found by suffix -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"foo"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "suffixPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + suffix: SuffixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` Use `encryptedClient` to run a "find" operation on the `db.prefix-suffix` collection with the following filter: ```javascript -{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: } } } +{ $expr: { $encStrEndsWith: {input: '$encryptedText', suffix: } } } ``` Assert that no documents are returned. #### Case 5: can find a document by substring -Use `clientEncryption.encrypt()` to encrypt the string `"foo"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"bar"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "substringPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + substring: SubstringOpts { + strMaxLength: 10, + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ $expr: { $encStrContains: {input: '$encryptedText', substring: } } } +{ $expr: { $encStrContains: {input: '$encryptedText', substring: } } } ``` Assert the following document is returned: @@ -3985,12 +4045,30 @@ Assert the following document is returned: #### Case 6: assert no document found by substring -Use `clientEncryption.encrypt()` to encrypt the string `"qux"`. Store the resulting payload in `findPayload`. +Use `clientEncryption.encrypt()` to encrypt the string `"qux"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "substringPreview", + contentionFactor: 0, + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + substring: SubstringOpts { + strMaxLength: 10, + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` Use `encryptedClient` to run a "find" operation on the `db.substring` collection with the following filter: ```javascript -{ $expr: { $encStrContains: {input: '$encryptedText', substring: } } } +{ $expr: { $encStrContains: {input: '$encryptedText', substring: } } } ``` Assert that no documents are returned. From c0ad54038d79758518d04d998d606cefa6a69408 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:29:47 -0700 Subject: [PATCH 20/22] contentionFactor required test --- source/client-side-encryption/tests/README.md | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 21e30ee7ee..09a3ef4f1c 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3774,9 +3774,13 @@ Before running each of the following test cases, perform the following Test Setu #### Test Setup -Using [QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper), drop and create the following collections: -- `db.prefix-suffix` using the `encryptedFields` option set to the contents of [encryptedFields-prefix-suffix.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json) -- `db.substring` using the `encryptedFields` option set to the contents of [encryptedFields-substring.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-substring.json) +Using [QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper), drop and +create the following collections: + +- `db.prefix-suffix` using the `encryptedFields` option set to the contents of + [encryptedFields-prefix-suffix.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json) +- `db.substring` using the `encryptedFields` option set to the contents of + [encryptedFields-substring.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-substring.json) Load the file [key1-document.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/keys/key1-document.json) @@ -4072,3 +4076,26 @@ Use `encryptedClient` to run a "find" operation on the `db.substring` collection ``` Assert that no documents are returned. + +#### Case 7: assert `contentionFactor` is required + +Use `clientEncryption.encrypt()` to encrypt the string `"foo"` with the following `EncryptOpts`: + +```typescript +class EncryptOpts { + keyId : , + algorithm: "TextPreview", + queryType: "prefixPreview", + textOpts: TextOpts { + caseSensitive: true, + diacriticSensitive: true, + prefix: PrefixOpts { + strMaxQueryLength: 10, + strMinQueryLength: 2, + } + }, +} +``` + +Expect an error from libmongocrypt with a message containing the string: "contention factor is required for textPreview +algorithm". From a9815436994dcdad5e21c5287c55a520bf4af139 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:35:16 -0700 Subject: [PATCH 21/22] remove redundant textOpts section --- source/client-side-encryption/tests/README.md | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 09a3ef4f1c..4fe82dfb9a 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3839,7 +3839,7 @@ class EncryptOpts { Use `encryptedClient` to insert the following document into `db.prefix-suffix`: ```javascript -{ "_id": 0, "encryptedText": } +{ "_id": 0, "encryptedText": } ``` Use `clientEncryption` to encrypt the string `"foobarbaz"` with the following `EncryptOpts`: @@ -3864,29 +3864,7 @@ class EncryptOpts { Use `encryptedClient` to insert the following document into `db.substring`: ```javascript -{ "_id": 0, "encryptedText": } -``` - -The remaining tasks require setting `TextOpts`. [Test Setup: TextOpts](#test-setup-textopts) lists the values to use for -`TextOpts` for each of the supported data types. - -#### Test Setup: TextOpts - -This section lists the values to use for `TextOpts` for each query type. Include the matching options in the following -`EncryptOpts` for each query: - -```typescript -class EncryptOpts { - keyId : , - algorithm: "TextPreview", - queryType: "Preview", - contentionFactor: 0, - textOpts: TextOpts { - caseSensitive: true, - diacriticSensitive: true, - : - }, -} +{ "_id": 0, "encryptedText": } ``` #### Case 1: can find a document by prefix From 848cdf279ce35cec6f7e074557b4cef5281ab780 Mon Sep 17 00:00:00 2001 From: mdb-ad <198671546+mdb-ad@users.noreply.github.com> Date: Tue, 12 Aug 2025 15:04:37 -0700 Subject: [PATCH 22/22] majority write concern --- source/client-side-encryption/tests/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/client-side-encryption/tests/README.md b/source/client-side-encryption/tests/README.md index 4fe82dfb9a..e0677bbab7 100644 --- a/source/client-side-encryption/tests/README.md +++ b/source/client-side-encryption/tests/README.md @@ -3775,7 +3775,7 @@ Before running each of the following test cases, perform the following Test Setu #### Test Setup Using [QE CreateCollection() and Collection.Drop()](../client-side-encryption.md#create-collection-helper), drop and -create the following collections: +create the following collections with majority write concern: - `db.prefix-suffix` using the `encryptedFields` option set to the contents of [encryptedFields-prefix-suffix.json](https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/etc/data/encryptedFields-prefix-suffix.json) @@ -3836,7 +3836,7 @@ class EncryptOpts { } ``` -Use `encryptedClient` to insert the following document into `db.prefix-suffix`: +Use `encryptedClient` to insert the following document into `db.prefix-suffix` with majority write concern: ```javascript { "_id": 0, "encryptedText": } @@ -3861,7 +3861,7 @@ class EncryptOpts { } ``` -Use `encryptedClient` to insert the following document into `db.substring`: +Use `encryptedClient` to insert the following document into `db.substring` with majority write concern: ```javascript { "_id": 0, "encryptedText": }