From 263beb06f44e4c18c6cb170b71c1330008474908 Mon Sep 17 00:00:00 2001 From: bailey Date: Mon, 29 Sep 2025 14:51:11 -0600 Subject: [PATCH 1/2] wrap FLE errors in MongoCryptErrors --- src/client-side-encryption/auto_encrypter.ts | 13 +++++-------- src/client-side-encryption/client_encryption.ts | 7 ++++--- src/client-side-encryption/errors.ts | 3 +++ ...ption.prose.22.range_explicit_encryption.test.ts | 2 +- .../client_side_encryption.prose.25.lookup.test.ts | 10 ++++++++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/client-side-encryption/auto_encrypter.ts b/src/client-side-encryption/auto_encrypter.ts index da70bf5cba4..ec4798c7b5f 100644 --- a/src/client-side-encryption/auto_encrypter.ts +++ b/src/client-side-encryption/auto_encrypter.ts @@ -1,8 +1,4 @@ -import { - type MongoCrypt, - type MongoCryptConstructor, - type MongoCryptOptions -} from 'mongodb-client-encryption'; +import { type MongoCrypt, type MongoCryptOptions } from 'mongodb-client-encryption'; import * as net from 'net'; import { deserialize, type Document, serialize } from '../bson'; @@ -15,7 +11,7 @@ import { type Abortable } from '../mongo_types'; import { MongoDBCollectionNamespace } from '../utils'; import { autoSelectSocketOptions } from './client_encryption'; import * as cryptoCallbacks from './crypto_callbacks'; -import { MongoCryptInvalidArgumentError } from './errors'; +import { defaultErrorWrapper, MongoCryptInvalidArgumentError } from './errors'; import { MongocryptdManager } from './mongocryptd_manager'; import { type CredentialProviders, @@ -183,7 +179,7 @@ export class AutoEncrypter { [kDecorateResult] = false; /** @internal */ - static getMongoCrypt(): MongoCryptConstructor { + static getMongoCrypt(): typeof MongoCrypt { const encryption = getMongoDBClientEncryption(); if ('kModuleError' in encryption) { throw encryption.kModuleError; @@ -259,7 +255,8 @@ export class AutoEncrypter { const mongoCryptOptions: MongoCryptOptions = { enableMultipleCollinfo: true, - cryptoCallbacks + cryptoCallbacks, + errorWrapper: defaultErrorWrapper }; if (options.schemaMap) { mongoCryptOptions.schemaMap = Buffer.isBuffer(options.schemaMap) diff --git a/src/client-side-encryption/client_encryption.ts b/src/client-side-encryption/client_encryption.ts index 0fda0a32334..c40b3b8c526 100644 --- a/src/client-side-encryption/client_encryption.ts +++ b/src/client-side-encryption/client_encryption.ts @@ -1,7 +1,6 @@ import type { ExplicitEncryptionContextOptions, MongoCrypt, - MongoCryptConstructor, MongoCryptOptions } from 'mongodb-client-encryption'; @@ -28,6 +27,7 @@ import { type CSOTTimeoutContext, TimeoutContext } from '../timeout'; import { MongoDBCollectionNamespace, resolveTimeoutOptions } from '../utils'; import * as cryptoCallbacks from './crypto_callbacks'; import { + defaultErrorWrapper, MongoCryptCreateDataKeyError, MongoCryptCreateEncryptedCollectionError, MongoCryptInvalidArgumentError @@ -87,7 +87,7 @@ export class ClientEncryption { _credentialProviders?: CredentialProviders; /** @internal */ - static getMongoCrypt(): MongoCryptConstructor { + static getMongoCrypt(): typeof MongoCrypt { const encryption = getMongoDBClientEncryption(); if ('kModuleError' in encryption) { throw encryption.kModuleError; @@ -147,7 +147,8 @@ export class ClientEncryption { cryptoCallbacks, kmsProviders: !Buffer.isBuffer(this._kmsProviders) ? (serialize(this._kmsProviders) as Buffer) - : this._kmsProviders + : this._kmsProviders, + errorWrapper: defaultErrorWrapper }; this._keyVaultNamespace = options.keyVaultNamespace; diff --git a/src/client-side-encryption/errors.ts b/src/client-side-encryption/errors.ts index 7ab70748a84..08a31e9db9d 100644 --- a/src/client-side-encryption/errors.ts +++ b/src/client-side-encryption/errors.ts @@ -26,6 +26,9 @@ export class MongoCryptError extends MongoError { } } +export const defaultErrorWrapper = (error: Error) => + new MongoCryptError(error.message, { cause: error }); + /** * @public * diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.22.range_explicit_encryption.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.22.range_explicit_encryption.test.ts index 08ab2bb096b..c78fb4a9fab 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.22.range_explicit_encryption.test.ts +++ b/test/integration/client-side-encryption/client_side_encryption.prose.22.range_explicit_encryption.test.ts @@ -537,7 +537,7 @@ describe('Range Explicit Encryption', function () { }) .catch(e => e); - expect(resultOrError).to.be.instanceOf(TypeError); + expect(resultOrError).to.be.instanceOf(MongoCryptError); } ); }); diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts index d4365ac6d6d..063761c781f 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts +++ b/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts @@ -6,7 +6,13 @@ import { type MongoCryptOptions } from 'mongodb-client-encryption'; import * as sinon from 'sinon'; import { getCSFLEKMSProviders } from '../../csfle-kms-providers'; -import { AutoEncrypter, BSON, type Document, type MongoClient } from '../../mongodb'; +import { + AutoEncrypter, + BSON, + type Document, + type MongoClient, + MongoCryptError +} from '../../mongodb'; import { type TestConfiguration } from '../../tools/runner/config'; import { getEncryptExtraOptions } from '../../tools/utils'; @@ -421,7 +427,7 @@ describe('$lookup support', defaultMetadata, function () { .toArray() .catch(error => error); - expect(actual).to.be.instanceOf(TypeError); + expect(actual).to.be.instanceOf(MongoCryptError); expect(actual.message).to.match( /libmongocrypt is not configured to support encrypting a command with multiple collections/i ); From 354a8998d749cd7a54bc23578611693498ce8231 Mon Sep 17 00:00:00 2001 From: bailey Date: Tue, 30 Sep 2025 10:55:46 -0600 Subject: [PATCH 2/2] adopt changes from FLE --- .../install-mongodb-client-encryption.sh | 2 +- src/client-side-encryption/auto_encrypter.ts | 1 - ...nt_side_encryption.prose.25.lookup.test.ts | 67 ------------------- 3 files changed, 1 insertion(+), 69 deletions(-) diff --git a/.evergreen/install-mongodb-client-encryption.sh b/.evergreen/install-mongodb-client-encryption.sh index 46d7dd0a629..40b5d7f68ea 100644 --- a/.evergreen/install-mongodb-client-encryption.sh +++ b/.evergreen/install-mongodb-client-encryption.sh @@ -9,7 +9,7 @@ if [ -z ${PROJECT_DIRECTORY+omitted} ]; then echo "PROJECT_DIRECTORY is unset" & source $DRIVERS_TOOLS/.evergreen/init-node-and-npm-env.sh rm -rf mongodb-client-encryption -git clone https://github.com/mongodb-js/mongodb-client-encryption.git +git clone https://github.com/baileympearson/mongodb-client-encryption.git -b NODE-7043 pushd mongodb-client-encryption node --version diff --git a/src/client-side-encryption/auto_encrypter.ts b/src/client-side-encryption/auto_encrypter.ts index ec4798c7b5f..20cf4608963 100644 --- a/src/client-side-encryption/auto_encrypter.ts +++ b/src/client-side-encryption/auto_encrypter.ts @@ -254,7 +254,6 @@ export class AutoEncrypter { } const mongoCryptOptions: MongoCryptOptions = { - enableMultipleCollinfo: true, cryptoCallbacks, errorWrapper: defaultErrorWrapper }; diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts index 063761c781f..f30a862816e 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts +++ b/test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts @@ -368,71 +368,4 @@ describe('$lookup support', defaultMetadata, function () { /Upgrade/i, { requires: { ...defaultMetadata.requires, mongodb: '>=7.0.0 <8.1.0' } } ); - - describe('Node.js custom test', function () { - describe('when enableMultipleCollinfo is off and a $lookup is run', function () { - let client: MongoClient; - - beforeEach(async function () { - const mochaTest = { metadata: defaultMetadata }; - - if (!this.configuration.filters.MongoDBVersionFilter.filter(mochaTest)) { - return; - } - - if (!this.configuration.filters.MongoDBTopologyFilter.filter(mochaTest)) { - return; - } - - if (!this.configuration.filters.ClientSideEncryptionFilter.filter(mochaTest)) { - return; - } - - const getMongoCrypt = sinon.stub(AutoEncrypter, 'getMongoCrypt').callsFake(function () { - const MongoCrypt = getMongoCrypt.wrappedMethod.call(this); - return class extends MongoCrypt { - constructor(options: MongoCryptOptions) { - expect(options).to.have.property('enableMultipleCollinfo', true); // assert invariant - options.enableMultipleCollinfo = false; - super(options); - } - }; - }); - - client = newEncryptedClient(this); - }); - - afterEach(async function () { - sinon.restore(); - await client?.close(); - }); - - it( - 'throws a TypeError about libmongocrypt not enabled to support multiple collections', - defaultMetadata, - async () => { - const collection = client.db('db').collection('csfle'); - const actual = await collection - .aggregate([ - { $match: { csfle: 'csfle' } }, - { - $lookup: { - from: 'csfle2', - as: 'matched', - pipeline: [{ $match: { csfle2: 'csfle2' } }, { $project: { _id: 0 } }] - } - }, - { $project: { _id: 0 } } - ]) - .toArray() - .catch(error => error); - - expect(actual).to.be.instanceOf(MongoCryptError); - expect(actual.message).to.match( - /libmongocrypt is not configured to support encrypting a command with multiple collections/i - ); - } - ); - }); - }); });