From 263beb06f44e4c18c6cb170b71c1330008474908 Mon Sep 17 00:00:00 2001 From: bailey Date: Mon, 29 Sep 2025 14:51:11 -0600 Subject: [PATCH 01/12] 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 02/12] 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 - ); - } - ); - }); - }); }); From 00cf2cd037b6f5bf472fc8c40a0813b3dff2da4f Mon Sep 17 00:00:00 2001 From: Bailey Pearson Date: Wed, 1 Oct 2025 12:40:25 -0600 Subject: [PATCH 03/12] feat(NODE-7043)!: remove crypto callbacks (#4706) --- .../install-mongodb-client-encryption.sh | 2 +- src/client-side-encryption/auto_encrypter.ts | 2 - .../client_encryption.ts | 2 - .../crypto_callbacks.ts | 87 ------------------- test/mongodb.ts | 1 - .../client_encryption.test.ts | 61 ------------- 6 files changed, 1 insertion(+), 154 deletions(-) delete mode 100644 src/client-side-encryption/crypto_callbacks.ts diff --git a/.evergreen/install-mongodb-client-encryption.sh b/.evergreen/install-mongodb-client-encryption.sh index 40b5d7f68ea..499af6276ba 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/baileympearson/mongodb-client-encryption.git -b NODE-7043 +git clone https://github.com/mongodb-js/mongodb-client-encryption.git -b NODE-6297 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 20cf4608963..fc9a9b39c84 100644 --- a/src/client-side-encryption/auto_encrypter.ts +++ b/src/client-side-encryption/auto_encrypter.ts @@ -10,7 +10,6 @@ import { MongoClient, type MongoClientOptions } from '../mongo_client'; import { type Abortable } from '../mongo_types'; import { MongoDBCollectionNamespace } from '../utils'; import { autoSelectSocketOptions } from './client_encryption'; -import * as cryptoCallbacks from './crypto_callbacks'; import { defaultErrorWrapper, MongoCryptInvalidArgumentError } from './errors'; import { MongocryptdManager } from './mongocryptd_manager'; import { @@ -254,7 +253,6 @@ export class AutoEncrypter { } const mongoCryptOptions: MongoCryptOptions = { - cryptoCallbacks, errorWrapper: defaultErrorWrapper }; if (options.schemaMap) { diff --git a/src/client-side-encryption/client_encryption.ts b/src/client-side-encryption/client_encryption.ts index c40b3b8c526..2494a1941bf 100644 --- a/src/client-side-encryption/client_encryption.ts +++ b/src/client-side-encryption/client_encryption.ts @@ -25,7 +25,6 @@ import { type CreateCollectionOptions } from '../operations/create_collection'; import { type DeleteResult } from '../operations/delete'; import { type CSOTTimeoutContext, TimeoutContext } from '../timeout'; import { MongoDBCollectionNamespace, resolveTimeoutOptions } from '../utils'; -import * as cryptoCallbacks from './crypto_callbacks'; import { defaultErrorWrapper, MongoCryptCreateDataKeyError, @@ -144,7 +143,6 @@ export class ClientEncryption { const mongoCryptOptions: MongoCryptOptions = { ...options, - cryptoCallbacks, kmsProviders: !Buffer.isBuffer(this._kmsProviders) ? (serialize(this._kmsProviders) as Buffer) : this._kmsProviders, diff --git a/src/client-side-encryption/crypto_callbacks.ts b/src/client-side-encryption/crypto_callbacks.ts deleted file mode 100644 index 1e2f1f7f070..00000000000 --- a/src/client-side-encryption/crypto_callbacks.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as crypto from 'crypto'; - -type AES256Callback = (key: Buffer, iv: Buffer, input: Buffer, output: Buffer) => number | Error; - -export function makeAES256Hook( - method: 'createCipheriv' | 'createDecipheriv', - mode: 'aes-256-cbc' | 'aes-256-ctr' -): AES256Callback { - return function (key: Buffer, iv: Buffer, input: Buffer, output: Buffer): number | Error { - let result; - - try { - const cipher = crypto[method](mode, key, iv); - cipher.setAutoPadding(false); - result = cipher.update(input); - const final = cipher.final(); - if (final.length > 0) { - result = Buffer.concat([result, final]); - } - } catch (e) { - return e; - } - - result.copy(output); - return result.length; - }; -} - -export function randomHook(buffer: Buffer, count: number): number | Error { - try { - crypto.randomFillSync(buffer, 0, count); - } catch (e) { - return e; - } - return count; -} - -export function sha256Hook(input: Buffer, output: Buffer): number | Error { - let result; - try { - result = crypto.createHash('sha256').update(input).digest(); - } catch (e) { - return e; - } - - result.copy(output); - return result.length; -} - -type HMACHook = (key: Buffer, input: Buffer, output: Buffer) => number | Error; -export function makeHmacHook(algorithm: 'sha512' | 'sha256'): HMACHook { - return (key: Buffer, input: Buffer, output: Buffer): number | Error => { - let result; - try { - result = crypto.createHmac(algorithm, key).update(input).digest(); - } catch (e) { - return e; - } - - result.copy(output); - return result.length; - }; -} - -export function signRsaSha256Hook(key: Buffer, input: Buffer, output: Buffer): number | Error { - let result; - try { - const signer = crypto.createSign('sha256WithRSAEncryption'); - const privateKey = Buffer.from( - `-----BEGIN PRIVATE KEY-----\n${key.toString('base64')}\n-----END PRIVATE KEY-----\n` - ); - - result = signer.update(input).end().sign(privateKey); - } catch (e) { - return e; - } - - result.copy(output); - return result.length; -} - -export const aes256CbcEncryptHook = makeAES256Hook('createCipheriv', 'aes-256-cbc'); -export const aes256CbcDecryptHook = makeAES256Hook('createDecipheriv', 'aes-256-cbc'); -export const aes256CtrEncryptHook = makeAES256Hook('createCipheriv', 'aes-256-ctr'); -export const aes256CtrDecryptHook = makeAES256Hook('createDecipheriv', 'aes-256-ctr'); -export const hmacSha512Hook = makeHmacHook('sha512'); -export const hmacSha256Hook = makeHmacHook('sha256'); diff --git a/test/mongodb.ts b/test/mongodb.ts index 4be7c6d2ce3..ec5a7d8ad3f 100644 --- a/test/mongodb.ts +++ b/test/mongodb.ts @@ -104,7 +104,6 @@ export * from '../src/bulk/unordered'; export * from '../src/change_stream'; export * from '../src/client-side-encryption/auto_encrypter'; export * from '../src/client-side-encryption/client_encryption'; -export * from '../src/client-side-encryption/crypto_callbacks'; export * from '../src/client-side-encryption/errors'; export * from '../src/client-side-encryption/mongocryptd_manager'; export * from '../src/client-side-encryption/providers/aws'; diff --git a/test/unit/client-side-encryption/client_encryption.test.ts b/test/unit/client-side-encryption/client_encryption.test.ts index c178231139d..95bf548be9c 100644 --- a/test/unit/client-side-encryption/client_encryption.test.ts +++ b/test/unit/client-side-encryption/client_encryption.test.ts @@ -5,7 +5,6 @@ import { resolve } from 'path'; import * as sinon from 'sinon'; import { ClientEncryption } from '../../../src/client-side-encryption/client_encryption'; -import * as cryptoCallbacks from '../../../src/client-side-encryption/crypto_callbacks'; import { MongoCryptCreateDataKeyError, MongoCryptCreateEncryptedCollectionError @@ -35,66 +34,6 @@ class MockClient { describe('ClientEncryption', function () { this.timeout(12000); - context('with stubbed key material and fixed random source', function () { - const sandbox = sinon.createSandbox(); - - afterEach(() => { - sandbox.restore(); - }); - beforeEach(() => { - const rndData = Buffer.from( - '\x4d\x06\x95\x64\xf5\xa0\x5e\x9e\x35\x23\xb9\x8f\x57\x5a\xcb\x15', - 'latin1' - ); - let rndPos = 0; - sandbox.stub(cryptoCallbacks, 'randomHook').callsFake((buffer, count) => { - if (rndPos + count > rndData.length) { - return new Error('Out of fake random data'); - } - buffer.set(rndData.subarray(rndPos, rndPos + count)); - rndPos += count; - return count; - }); - - // stubbed out for AWS unit testing below - sandbox.stub(StateMachine.prototype, 'fetchKeys').callsFake((client, ns, filter) => { - filter = deserialize(filter); - const keyIds = filter.$or[0]._id.$in.map(key => key.toString('hex')); - const fileNames = keyIds.map(keyId => - resolve(`${__dirname}/data/keys/${keyId.toUpperCase()}-local-document.json`) - ); - const contents = fileNames.map(filename => - EJSON.parse(fs.readFileSync(filename, { encoding: 'utf-8' })) - ); - return Promise.resolve(contents); - }); - }); - - // This exactly matches _test_encrypt_fle2_explicit from the C tests - it('should explicitly encrypt and decrypt with the "local" KMS provider (FLE2, exact result)', function () { - const encryption = new ClientEncryption(new MockClient(), { - keyVaultNamespace: 'client.encryption', - kmsProviders: { local: { key: Buffer.alloc(96) } } - }); - - const encryptOptions = { - keyId: new Binary(Buffer.from('ABCDEFAB123498761234123456789012', 'hex'), 4), - algorithm: 'Unindexed' - }; - - return encryption - .encrypt('value123', encryptOptions) - .then(encrypted => { - expect(encrypted._bsontype).to.equal('Binary'); - expect(encrypted.sub_type).to.equal(6); - return encryption.decrypt(encrypted); - }) - .then(decrypted => { - expect(decrypted).to.equal('value123'); - }); - }); - }); - it('should provide the libmongocrypt version', function () { expect(ClientEncryption.libmongocryptVersion).to.be.a('string'); }); From fb64abd5eaec79a740695b18c32c6cad1d605d20 Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 1 Oct 2025 13:32:30 -0600 Subject: [PATCH 04/12] use main again --- .evergreen/install-mongodb-client-encryption.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/install-mongodb-client-encryption.sh b/.evergreen/install-mongodb-client-encryption.sh index 499af6276ba..46d7dd0a629 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 -b NODE-6297 +git clone https://github.com/mongodb-js/mongodb-client-encryption.git pushd mongodb-client-encryption node --version From cf9baec9c65e981447373e59eed1f2a690e045f1 Mon Sep 17 00:00:00 2001 From: bailey Date: Wed, 1 Oct 2025 15:02:36 -0600 Subject: [PATCH 05/12] adopt mongodb-cient-encryption alpha --- package-lock.json | 116 ++++++++++-------- package.json | 6 +- ...nt_side_encryption.prose.25.lookup.test.ts | 10 +- .../client_encryption.test.ts | 7 +- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4db68a81d74..87aed87afc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "js-yaml": "^4.1.0", "mocha": "^11.7.1", "mocha-sinon": "^2.1.2", - "mongodb-client-encryption": "^6.5.0", + "mongodb-client-encryption": "^7.0.0-alpha", "mongodb-legacy": "^6.1.3", "nyc": "^15.1.0", "prettier": "^3.6.2", @@ -73,7 +73,7 @@ "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", + "mongodb-client-encryption": "^7.0.0-alpha", "snappy": "^7.3.2", "socks": "^2.7.1" }, @@ -7056,66 +7056,29 @@ "node": ">=12" } }, - "node_modules/mongodb": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.16.0.tgz", - "integrity": "sha512-D1PNcdT0y4Grhou5Zi/qgipZOYeWrhLEpk33n3nm6LGtz61jvO88WlrWCK/bigMjpnOdAUKKQwsGIl0NtWMyYw==", + "node_modules/mongodb-client-encryption": { + "version": "7.0.0-alpha", + "resolved": "https://registry.npmjs.org/mongodb-client-encryption/-/mongodb-client-encryption-7.0.0-alpha.tgz", + "integrity": "sha512-IiAK6MN074yc2mq9XbAmWS4hkbgozp0/wm0iPHwX1MGie/6hmpXOxvDJuODz3fi+N618B+HQxS6NkVqME7fsDg==", "dev": true, + "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@mongodb-js/saslprep": "^1.1.9", - "bson": "^6.10.3", - "mongodb-connection-string-url": "^3.0.0" + "node-addon-api": "^8.5.0", + "prebuild-install": "^7.1.3" }, "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } + "node": ">=20.19.0" } }, - "node_modules/mongodb-client-encryption": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/mongodb-client-encryption/-/mongodb-client-encryption-6.5.0.tgz", - "integrity": "sha512-Gj8EeyYKsssdko0NKhWRBGDif6uVFBbv+e+Nyn7E316UmRzApc4IP+p2NLm+av+fU+dFHVT5WqfzaQVDTh8i9w==", + "node_modules/mongodb-client-encryption/node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.1.3" - }, + "license": "MIT", "engines": { - "node": ">=16.20.1" + "node": "^18 || ^20 || >= 21" } }, "node_modules/mongodb-connection-string-url": { @@ -7150,6 +7113,53 @@ "node": ">=16.20.1" } }, + "node_modules/mongodb-legacy/node_modules/mongodb": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz", + "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.2" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index ed2c126a8bb..4449d82bb00 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", + "mongodb-client-encryption": "^7.0.0-alpha", "snappy": "^7.3.2", "socks": "^2.7.1" }, @@ -96,7 +96,7 @@ "js-yaml": "^4.1.0", "mocha": "^11.7.1", "mocha-sinon": "^2.1.2", - "mongodb-client-encryption": "^6.5.0", + "mongodb-client-encryption": "^7.0.0-alpha", "mongodb-legacy": "^6.1.3", "nyc": "^15.1.0", "prettier": "^3.6.2", @@ -174,4 +174,4 @@ "moduleResolution": "node" } } -} \ No newline at end of file +} 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 f30a862816e..0c873ee1ccd 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 @@ -2,17 +2,9 @@ import * as fs from 'node:fs/promises'; import * as path from 'node:path'; import { expect } from 'chai'; -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, - MongoCryptError -} from '../../mongodb'; +import { BSON, type Document, type MongoClient } from '../../mongodb'; import { type TestConfiguration } from '../../tools/runner/config'; import { getEncryptExtraOptions } from '../../tools/utils'; diff --git a/test/unit/client-side-encryption/client_encryption.test.ts b/test/unit/client-side-encryption/client_encryption.test.ts index 95bf548be9c..1f9c416c136 100644 --- a/test/unit/client-side-encryption/client_encryption.test.ts +++ b/test/unit/client-side-encryption/client_encryption.test.ts @@ -1,7 +1,5 @@ -import { Binary, BSON, deserialize } from 'bson'; +import { Binary } from 'bson'; import { expect } from 'chai'; -import * as fs from 'fs'; -import { resolve } from 'path'; import * as sinon from 'sinon'; import { ClientEncryption } from '../../../src/client-side-encryption/client_encryption'; @@ -9,11 +7,8 @@ import { MongoCryptCreateDataKeyError, MongoCryptCreateEncryptedCollectionError } from '../../../src/client-side-encryption/errors'; -import { StateMachine } from '../../../src/client-side-encryption/state_machine'; import { MongoClient } from '../../../src/mongo_client'; -const { EJSON } = BSON; - class MockClient { options: any; s: { options: any }; From a70b1f5093f9d7e4a57d63e1e5feef081d62c065 Mon Sep 17 00:00:00 2001 From: bailey Date: Thu, 2 Oct 2025 15:37:03 -0600 Subject: [PATCH 06/12] use alpha.1 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87aed87afc9..b0b32264517 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "js-yaml": "^4.1.0", "mocha": "^11.7.1", "mocha-sinon": "^2.1.2", - "mongodb-client-encryption": "^7.0.0-alpha", + "mongodb-client-encryption": "^7.0.0-alpha.1", "mongodb-legacy": "^6.1.3", "nyc": "^15.1.0", "prettier": "^3.6.2", @@ -7057,9 +7057,9 @@ } }, "node_modules/mongodb-client-encryption": { - "version": "7.0.0-alpha", - "resolved": "https://registry.npmjs.org/mongodb-client-encryption/-/mongodb-client-encryption-7.0.0-alpha.tgz", - "integrity": "sha512-IiAK6MN074yc2mq9XbAmWS4hkbgozp0/wm0iPHwX1MGie/6hmpXOxvDJuODz3fi+N618B+HQxS6NkVqME7fsDg==", + "version": "7.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/mongodb-client-encryption/-/mongodb-client-encryption-7.0.0-alpha.1.tgz", + "integrity": "sha512-099wjk7zkEKOL19td0z+ie4OO4t3cPdbT4EjC6M2K0RbBMD0J/9T7M9LsLxdPAYhQA7yTdwUdMQqzrXhmJWosw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", diff --git a/package.json b/package.json index 4449d82bb00..83c4fbc862e 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "js-yaml": "^4.1.0", "mocha": "^11.7.1", "mocha-sinon": "^2.1.2", - "mongodb-client-encryption": "^7.0.0-alpha", + "mongodb-client-encryption": "^7.0.0-alpha.1", "mongodb-legacy": "^6.1.3", "nyc": "^15.1.0", "prettier": "^3.6.2", From 8278fb5f96e7593515a55f65c81f92f2665e65eb Mon Sep 17 00:00:00 2001 From: bailey Date: Thu, 2 Oct 2025 16:01:07 -0600 Subject: [PATCH 07/12] fix --- test/integration/node-specific/client_encryption.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/integration/node-specific/client_encryption.test.ts b/test/integration/node-specific/client_encryption.test.ts index 90800f92903..51f7b9f650f 100644 --- a/test/integration/node-specific/client_encryption.test.ts +++ b/test/integration/node-specific/client_encryption.test.ts @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { readFileSync } from 'fs'; import * as sinon from 'sinon'; +import { MongoCryptError } from '../../../src'; import { ClientEncryption, type DataKey @@ -391,7 +392,7 @@ describe('ClientEncryption integration tests', function () { .encryptExpression(expression, completeOptions) .catch(e => e); - expect(errorOrResult).to.be.instanceof(TypeError); + expect(errorOrResult).to.be.instanceof(MongoCryptError); }); it('throws if algorithm is not provided', metadata, async function () { @@ -400,7 +401,7 @@ describe('ClientEncryption integration tests', function () { .encryptExpression(expression, completeOptions) .catch(e => e); - expect(errorOrResult).to.be.instanceof(TypeError); + expect(errorOrResult).to.be.instanceof(MongoCryptError); }); it(`throws if algorithm does not equal 'range'`, metadata, async function () { @@ -409,7 +410,7 @@ describe('ClientEncryption integration tests', function () { .encryptExpression(expression, completeOptions) .catch(e => e); - expect(errorOrResult).to.be.instanceof(TypeError); + expect(errorOrResult).to.be.instanceof(MongoCryptError); }); it(`works with any casing of 'range'`, metadata, async function () { From a9142eda3766d9d49f9674b9baf54626de7ca011 Mon Sep 17 00:00:00 2001 From: bailey Date: Fri, 3 Oct 2025 08:34:59 -0600 Subject: [PATCH 08/12] remove failing task --- .evergreen/config.yml | 19 ------------ .evergreen/generate_evergreen_tasks.js | 43 +++++++++++++------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index b42c08070c0..5613675c5b5 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1994,24 +1994,6 @@ tasks: - func: install mongodb-client-encryption from source - func: assume secrets manager role - func: run custom csfle tests - - name: test-latest-driver-mongodb-client-encryption-6.0.0 - tags: - - run-custom-dependency-tests - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: NODE_LTS_VERSION, value: 20.19.0} - - {key: VERSION, value: '7.0'} - - {key: TOPOLOGY, value: replica_set} - - {key: CLIENT_ENCRYPTION, value: 'true'} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: install package - vars: - PACKAGE: mongodb-client-encryption@6.0.0 - - func: run tests - name: test-alpine-fle tags: - alpine-fle @@ -3205,7 +3187,6 @@ buildvariants: - run-custom-csfle-tests-5.0 - run-custom-csfle-tests-rapid - run-custom-csfle-tests-latest - - test-latest-driver-mongodb-client-encryption-6.0.0 - name: rhel8-test-gcp-kms display_name: GCP KMS Test run_on: debian11-small diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index 82449fb623f..c7f761daa6d 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -623,27 +623,28 @@ for (const serverVersion of ['5.0', 'rapid', 'latest']) { }); } -customDependencyTests.push({ - name: `test-latest-driver-mongodb-client-encryption-6.0.0`, - tags: ['run-custom-dependency-tests'], - commands: [ - updateExpansions({ - NODE_LTS_VERSION: LOWEST_LTS, - VERSION: '7.0', - TOPOLOGY: 'replica_set', - CLIENT_ENCRYPTION: true - }), - { func: 'install dependencies' }, - { func: 'bootstrap mongo-orchestration' }, - { - func: 'install package', - vars: { - PACKAGE: 'mongodb-client-encryption@6.0.0' - } - }, - { func: 'run tests' } - ] -}); +// TODO(NODE-6997): update to 7.0.0 after release +// customDependencyTests.push({ +// name: `test-latest-driver-mongodb-client-encryption-6.0.0`, +// tags: ['run-custom-dependency-tests'], +// commands: [ +// updateExpansions({ +// NODE_LTS_VERSION: LOWEST_LTS, +// VERSION: '7.0', +// TOPOLOGY: 'replica_set', +// CLIENT_ENCRYPTION: true +// }), +// { func: 'install dependencies' }, +// { func: 'bootstrap mongo-orchestration' }, +// { +// func: 'install package', +// vars: { +// PACKAGE: 'mongodb-client-encryption@6.0.0' +// } +// }, +// { func: 'run tests' } +// ] +// }); const coverageTask = { name: 'download and merge coverage'.split(' ').join('-'), From b904bb14b5080378726eba60e323da5e4e497651 Mon Sep 17 00:00:00 2001 From: bailey Date: Fri, 3 Oct 2025 09:57:53 -0600 Subject: [PATCH 09/12] fix dependency test --- test/action/dependency.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/action/dependency.test.ts b/test/action/dependency.test.ts index c0c4206fe68..bd1f33a5fa1 100644 --- a/test/action/dependency.test.ts +++ b/test/action/dependency.test.ts @@ -57,8 +57,10 @@ describe('package.json', function () { .split('\n') .join(''); - for (const [depName, depVersion] of Object.entries(peerDependencies)) { - const depMajor = depVersion.split('.')[0]; + for (const [depName, depVersion] of Object.entries(peerDependencies as Record)) { + // If a dependency specifies `alpha|beta`, the major version will fail to install because + // an alpha < the major of that version (ex: mongodb-client-encryption@7.0.0-alpha < mongodb-client-encryption@7.0.0) + const depInstallSpecifier = /alpha|beta/.test(depVersion) ? depVersion : depVersion.split('.')[0]; context(`when ${depName} is NOT installed`, () => { beforeEach(async () => { @@ -91,7 +93,7 @@ describe('package.json', function () { context(`when ${depName} is installed`, () => { beforeEach(async function () { - execSync(`npm install --no-save -D "${depName}"@"${depMajor}"`); + execSync(`npm install --no-save -D "${depName}"@"${depInstallSpecifier}"`); }); it(`driver is importable`, () => { From 9bd578ddd0efeeb32152f63a7dfb7591a82bce86 Mon Sep 17 00:00:00 2001 From: bailey Date: Fri, 3 Oct 2025 10:35:36 -0600 Subject: [PATCH 10/12] fix lint --- test/action/dependency.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/action/dependency.test.ts b/test/action/dependency.test.ts index bd1f33a5fa1..e21059b1100 100644 --- a/test/action/dependency.test.ts +++ b/test/action/dependency.test.ts @@ -57,10 +57,14 @@ describe('package.json', function () { .split('\n') .join(''); - for (const [depName, depVersion] of Object.entries(peerDependencies as Record)) { - // If a dependency specifies `alpha|beta`, the major version will fail to install because + for (const [depName, depVersion] of Object.entries( + peerDependencies as Record + )) { + // If a dependency specifies `alpha|beta`, the major version will fail to install because // an alpha < the major of that version (ex: mongodb-client-encryption@7.0.0-alpha < mongodb-client-encryption@7.0.0) - const depInstallSpecifier = /alpha|beta/.test(depVersion) ? depVersion : depVersion.split('.')[0]; + const depInstallSpecifier = /alpha|beta/.test(depVersion) + ? depVersion + : depVersion.split('.')[0]; context(`when ${depName} is NOT installed`, () => { beforeEach(async () => { From 7b59d217f1971184e60dc783ea26b01960790bed Mon Sep 17 00:00:00 2001 From: bailey Date: Fri, 3 Oct 2025 15:46:25 -0600 Subject: [PATCH 11/12] comments --- .evergreen/config.in.yml | 3 +++ .evergreen/config.yml | 3 +++ test/tools/unified-spec-runner/match.ts | 15 +-------------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.evergreen/config.in.yml b/.evergreen/config.in.yml index 1a1d3fc24ca..2b5fa1eada1 100644 --- a/.evergreen/config.in.yml +++ b/.evergreen/config.in.yml @@ -617,6 +617,9 @@ functions: export AWS_ACCESS_KEY_ID=${aws_key} export AWS_SECRET_ACCESS_KEY=${aws_secret} + # use Node20 + export PATH=/opt/devtools/node20/bin:/opt/dev/tools/bin:$PATH + # Download all the task coverage files. # NOTE: All coverage files are too large for V8 to handle the resulting call to # JSON.stringify from within nyc, so with stick to Fermiun to include the diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 5613675c5b5..ff30804760c 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -556,6 +556,9 @@ functions: export AWS_ACCESS_KEY_ID=${aws_key} export AWS_SECRET_ACCESS_KEY=${aws_secret} + # use Node20 + export PATH=/opt/devtools/node20/bin:/opt/dev/tools/bin:$PATH + # Download all the task coverage files. # NOTE: All coverage files are too large for V8 to handle the resulting call to # JSON.stringify from within nyc, so with stick to Fermiun to include the diff --git a/test/tools/unified-spec-runner/match.ts b/test/tools/unified-spec-runner/match.ts index a2cf880a286..112748a10a8 100644 --- a/test/tools/unified-spec-runner/match.ts +++ b/test/tools/unified-spec-runner/match.ts @@ -771,20 +771,7 @@ export function compareLogs( } function isMongoCryptError(err): boolean { - if (err.constructor.name === 'MongoCryptError') { - return true; - } - - // TODO(NODE-7043): remove special handling for FLE errors in the UTR - if ( - err instanceof TypeError && - err.message.includes( - `csfle "analyze_query" failed: JSON schema keyword 'required' is only allowed with a remote schema` - ) - ) { - return true; - } - return err.stack.includes('at ClientEncryption'); + return err.constructor.name === 'MongoCryptError'; } export function expectErrorCheck( From 124ccadaa4a9d70fe52b45fecfd057ebba298822 Mon Sep 17 00:00:00 2001 From: bailey Date: Mon, 6 Oct 2025 09:42:54 -0600 Subject: [PATCH 12/12] fix custom FLE tests --- .evergreen/install-mongodb-client-encryption.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.evergreen/install-mongodb-client-encryption.sh b/.evergreen/install-mongodb-client-encryption.sh index 6bb89ac0191..2deacd37c21 100644 --- a/.evergreen/install-mongodb-client-encryption.sh +++ b/.evergreen/install-mongodb-client-encryption.sh @@ -12,8 +12,7 @@ rm -rf mongodb-client-encryption git clone https://github.com/mongodb-js/mongodb-client-encryption.git pushd mongodb-client-encryption -# TODO(NODE-7218): test against latest mongodb-client-encryption -git checkout aa61a35f5e174cd1c1e247e036093e18c88268c6 +git checkout main node --version npm --version