Skip to content

Commit 9220255

Browse files
Merge branch 'main' into NODE-2422/validate_that_mongocryptd_not_spawned_if_bypassAutoEncrypt_is_true
2 parents 8ceb8bf + 41d4f0d commit 9220255

File tree

241 files changed

+4987
-11063
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

241 files changed

+4987
-11063
lines changed

.evergreen/run-kms-servers.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#!/bin/bash
2+
13
cd ${DRIVERS_TOOLS}/.evergreen/csfle
24
. ./activate-kmstlsvenv.sh
35
# by default it always runs on port 5698

.evergreen/run-typescript.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fi
2222

2323
function get_ts_version() {
2424
if [ "$TS_VERSION" == "current" ]; then
25-
echo $(node -e "console.log(require('./package-lock.json').dependencies.typescript.version)")
25+
echo $(node -e "console.log(require('./package-lock.json').packages['node_modules/typescript'].version)")
2626
else
2727
echo $TS_VERSION
2828
fi
@@ -31,7 +31,8 @@ function get_ts_version() {
3131
export TSC="./node_modules/typescript/bin/tsc"
3232
export TS_VERSION=$(get_ts_version)
3333

34-
npm install --no-save --force typescript@"$TS_VERSION"
34+
# On old versions of TS we need to put the node types back to 18.11.19
35+
npm install --no-save --force typescript@"$TS_VERSION" "$(if [[ $TS_VERSION == '4.1.6' ]]; then echo "@types/node@18.11.19"; else echo ""; fi)"
3536

3637
echo "Typescript $($TSC -v)"
3738

package-lock.json

Lines changed: 1083 additions & 8539 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,27 @@
5151
"devDependencies": {
5252
"@iarna/toml": "^2.2.5",
5353
"@istanbuljs/nyc-config-typescript": "^1.0.2",
54-
"@microsoft/api-extractor": "^7.34.4",
54+
"@microsoft/api-extractor": "^7.34.8",
5555
"@microsoft/tsdoc-config": "^0.16.2",
5656
"@mongodb-js/zstd": "^1.1.0",
57-
"@types/chai": "^4.3.4",
57+
"@types/chai": "^4.3.5",
5858
"@types/chai-subset": "^1.3.3",
5959
"@types/express": "^4.17.17",
60-
"@types/kerberos": "^1.1.1",
60+
"@types/kerberos": "^1.1.2",
6161
"@types/mocha": "^10.0.1",
62-
"@types/node": "^18.11.19",
62+
"@types/node": "^20.1.0",
6363
"@types/saslprep": "^1.0.1",
64-
"@types/semver": "^7.3.13",
65-
"@types/sinon": "^10.0.13",
64+
"@types/semver": "^7.5.0",
65+
"@types/sinon": "^10.0.14",
6666
"@types/sinon-chai": "^3.2.9",
6767
"@types/whatwg-url": "^11.0.0",
68-
"@typescript-eslint/eslint-plugin": "^5.55.0",
69-
"@typescript-eslint/parser": "^5.55.0",
68+
"@typescript-eslint/eslint-plugin": "^5.59.5",
69+
"@typescript-eslint/parser": "^5.59.5",
7070
"chai": "^4.3.7",
7171
"chai-subset": "^1.6.0",
7272
"chalk": "^4.1.2",
73-
"eslint": "^8.36.0",
74-
"eslint-config-prettier": "^8.7.0",
73+
"eslint": "^8.40.0",
74+
"eslint-config-prettier": "^8.8.0",
7575
"eslint-plugin-import": "^2.27.5",
7676
"eslint-plugin-prettier": "^4.2.1",
7777
"eslint-plugin-simple-import-sort": "^10.0.0",
@@ -82,9 +82,9 @@
8282
"mocha-sinon": "^2.1.2",
8383
"mongodb-legacy": "^5.0.0",
8484
"nyc": "^15.1.0",
85-
"prettier": "^2.8.4",
86-
"semver": "^7.3.8",
87-
"sinon": "^15.0.2",
85+
"prettier": "^2.8.8",
86+
"semver": "^7.5.0",
87+
"sinon": "^15.0.4",
8888
"sinon-chai": "^3.7.0",
8989
"snappy": "^7.2.2",
9090
"source-map-support": "^0.5.21",
@@ -94,8 +94,7 @@
9494
"typescript": "^4.9.5",
9595
"typescript-cached-transpile": "^0.0.6",
9696
"v8-heapsnapshot": "^1.2.0",
97-
"xml2js": "^0.4.23",
98-
"yargs": "^17.7.1"
97+
"yargs": "^17.7.2"
9998
},
10099
"license": "Apache-2.0",
101100
"engines": {

src/cmap/connection_pool.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,11 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
251251
this[kMetrics] = new ConnectionPoolMetrics();
252252
this[kProcessingWaitQueue] = false;
253253

254+
this.mongoLogger = this[kServer].topology.client.mongoLogger;
255+
this.component = 'connection';
256+
254257
process.nextTick(() => {
255-
this.emit(ConnectionPool.CONNECTION_POOL_CREATED, new ConnectionPoolCreatedEvent(this));
258+
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CREATED, new ConnectionPoolCreatedEvent(this));
256259
});
257260
}
258261

@@ -337,7 +340,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
337340
return;
338341
}
339342
this[kPoolState] = PoolState.ready;
340-
this.emit(ConnectionPool.CONNECTION_POOL_READY, new ConnectionPoolReadyEvent(this));
343+
this.emitAndLog(ConnectionPool.CONNECTION_POOL_READY, new ConnectionPoolReadyEvent(this));
341344
clearTimeout(this[kMinPoolSizeTimer]);
342345
this.ensureMinPoolSize();
343346
}
@@ -348,7 +351,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
348351
* explicitly destroyed by the new owner.
349352
*/
350353
checkOut(callback: Callback<Connection>): void {
351-
this.emit(
354+
this.emitAndLog(
352355
ConnectionPool.CONNECTION_CHECK_OUT_STARTED,
353356
new ConnectionCheckOutStartedEvent(this)
354357
);
@@ -360,7 +363,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
360363
waitQueueMember[kCancelled] = true;
361364
waitQueueMember.timer = undefined;
362365

363-
this.emit(
366+
this.emitAndLog(
364367
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
365368
new ConnectionCheckOutFailedEvent(this, 'timeout')
366369
);
@@ -398,7 +401,10 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
398401
}
399402

400403
this[kCheckedOut].delete(connection);
401-
this.emit(ConnectionPool.CONNECTION_CHECKED_IN, new ConnectionCheckedInEvent(this, connection));
404+
this.emitAndLog(
405+
ConnectionPool.CONNECTION_CHECKED_IN,
406+
new ConnectionCheckedInEvent(this, connection)
407+
);
402408

403409
if (willDestroy) {
404410
const reason = connection.closed ? 'error' : poolClosed ? 'poolClosed' : 'stale';
@@ -437,7 +443,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
437443
// Increment the generation for the service id.
438444
this.serviceGenerations.set(sid, generation + 1);
439445
}
440-
this.emit(
446+
this.emitAndLog(
441447
ConnectionPool.CONNECTION_POOL_CLEARED,
442448
new ConnectionPoolClearedEvent(this, { serviceId })
443449
);
@@ -452,9 +458,11 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
452458

453459
this.clearMinPoolSizeTimer();
454460
if (!alreadyPaused) {
455-
this.emit(
461+
this.emitAndLog(
456462
ConnectionPool.CONNECTION_POOL_CLEARED,
457-
new ConnectionPoolClearedEvent(this, { interruptInUseConnections })
463+
new ConnectionPoolClearedEvent(this, {
464+
interruptInUseConnections
465+
})
458466
);
459467
}
460468

@@ -509,15 +517,15 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
509517
eachAsync<Connection>(
510518
this[kConnections].toArray(),
511519
(conn, cb) => {
512-
this.emit(
520+
this.emitAndLog(
513521
ConnectionPool.CONNECTION_CLOSED,
514522
new ConnectionClosedEvent(this, conn, 'poolClosed')
515523
);
516524
conn.destroy({ force: !!options.force }, cb);
517525
},
518526
err => {
519527
this[kConnections].clear();
520-
this.emit(ConnectionPool.CONNECTION_POOL_CLOSED, new ConnectionPoolClosedEvent(this));
528+
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CLOSED, new ConnectionPoolClosedEvent(this));
521529
callback(err);
522530
}
523531
);
@@ -645,7 +653,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
645653
connection: Connection,
646654
reason: 'error' | 'idle' | 'stale' | 'poolClosed'
647655
) {
648-
this.emit(
656+
this.emitAndLog(
649657
ConnectionPool.CONNECTION_CLOSED,
650658
new ConnectionClosedEvent(this, connection, reason)
651659
);
@@ -694,15 +702,15 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
694702

695703
this[kPending]++;
696704
// This is our version of a "virtual" no-I/O connection as the spec requires
697-
this.emit(
705+
this.emitAndLog(
698706
ConnectionPool.CONNECTION_CREATED,
699707
new ConnectionCreatedEvent(this, { id: connectOptions.id })
700708
);
701709

702710
connect(connectOptions, (err, connection) => {
703711
if (err || !connection) {
704712
this[kPending]--;
705-
this.emit(
713+
this.emitAndLog(
706714
ConnectionPool.CONNECTION_CLOSED,
707715
new ConnectionClosedEvent(
708716
this,
@@ -750,7 +758,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
750758
}
751759

752760
connection.markAvailable();
753-
this.emit(ConnectionPool.CONNECTION_READY, new ConnectionReadyEvent(this, connection));
761+
this.emitAndLog(ConnectionPool.CONNECTION_READY, new ConnectionReadyEvent(this, connection));
754762

755763
this[kPending]--;
756764
callback(undefined, connection);
@@ -819,7 +827,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
819827
if (this[kPoolState] !== PoolState.ready) {
820828
const reason = this.closed ? 'poolClosed' : 'connectionError';
821829
const error = this.closed ? new PoolClosedError(this) : new PoolClearedError(this);
822-
this.emit(
830+
this.emitAndLog(
823831
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
824832
new ConnectionCheckOutFailedEvent(this, reason, error)
825833
);
@@ -842,7 +850,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
842850

843851
if (!this.destroyConnectionIfPerished(connection)) {
844852
this[kCheckedOut].add(connection);
845-
this.emit(
853+
this.emitAndLog(
846854
ConnectionPool.CONNECTION_CHECKED_OUT,
847855
new ConnectionCheckedOutEvent(this, connection)
848856
);
@@ -872,14 +880,14 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
872880
}
873881
} else {
874882
if (err) {
875-
this.emit(
883+
this.emitAndLog(
876884
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
877885
// TODO(NODE-5192): Remove this cast
878886
new ConnectionCheckOutFailedEvent(this, 'connectionError', err as MongoError)
879887
);
880888
} else if (connection) {
881889
this[kCheckedOut].add(connection);
882-
this.emit(
890+
this.emitAndLog(
883891
ConnectionPool.CONNECTION_CHECKED_OUT,
884892
new ConnectionCheckedOutEvent(this, connection)
885893
);

src/cmap/handshake/client_metadata.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ export function getFAASEnv(): Map<string, string | Int32> | null {
176176
VERCEL_REGION = ''
177177
} = process.env;
178178

179-
const isAWSFaaS = AWS_EXECUTION_ENV.length > 0 || AWS_LAMBDA_RUNTIME_API.length > 0;
179+
const isAWSFaaS =
180+
AWS_EXECUTION_ENV.startsWith('AWS_Lambda_') || AWS_LAMBDA_RUNTIME_API.length > 0;
180181
const isAzureFaaS = FUNCTIONS_WORKER_RUNTIME.length > 0;
181182
const isGCPFaaS = K_SERVICE.length > 0 || FUNCTION_NAME.length > 0;
182183
const isVercelFaaS = VERCEL.length > 0;

src/cmap/wire_protocol/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export const MIN_SUPPORTED_SERVER_VERSION = '3.6';
22
export const MAX_SUPPORTED_SERVER_VERSION = '7.0';
33
export const MIN_SUPPORTED_WIRE_VERSION = 6;
44
export const MAX_SUPPORTED_WIRE_VERSION = 21;
5+
export const MIN_SUPPORTED_QE_WIRE_VERSION = 21;
6+
export const MIN_SUPPORTED_QE_SERVER_VERSION = '7.0';
57
export const OP_REPLY = 1;
68
export const OP_UPDATE = 2001;
79
export const OP_INSERT = 2002;

src/deps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,11 @@ export interface AutoEncryptionOptions {
309309
* Other validation rules in the JSON schema will not be enforced by the driver and will result in an error.
310310
*/
311311
schemaMap?: Document;
312-
/** @experimental Public Technical Preview: Supply a schema for the encrypted fields in the document */
312+
/** Supply a schema for the encrypted fields in the document */
313313
encryptedFieldsMap?: Document;
314314
/** Allows the user to bypass auto encryption, maintaining implicit decryption */
315315
bypassAutoEncryption?: boolean;
316-
/** @experimental Public Technical Preview: Allows users to bypass query analysis */
316+
/** Allows users to bypass query analysis */
317317
bypassQueryAnalysis?: boolean;
318318
options?: {
319319
/** An optional hook to catch logging messages from the underlying encryption engine */

src/mongo_client.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> {
325325
/** @internal */
326326
topology?: Topology;
327327
/** @internal */
328-
readonly mongoLogger: MongoLogger;
328+
override readonly mongoLogger: MongoLogger;
329329
/** @internal */
330330
private connectionLock?: Promise<this>;
331331

@@ -471,23 +471,21 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> {
471471
}
472472
}
473473

474-
const topology = new Topology(options.hosts, options);
474+
this.topology = new Topology(this, options.hosts, options);
475475
// Events can be emitted before initialization is complete so we have to
476476
// save the reference to the topology on the client ASAP if the event handlers need to access it
477-
this.topology = topology;
478-
topology.client = this;
479477

480-
topology.once(Topology.OPEN, () => this.emit('open', this));
478+
this.topology.once(Topology.OPEN, () => this.emit('open', this));
481479

482480
for (const event of MONGO_CLIENT_EVENTS) {
483-
topology.on(event, (...args: any[]) => this.emit(event, ...(args as any)));
481+
this.topology.on(event, (...args: any[]) => this.emit(event, ...(args as any)));
484482
}
485483

486484
const topologyConnect = async () => {
487485
try {
488-
await promisify(callback => topology.connect(options, callback))();
486+
await promisify(callback => this.topology?.connect(options, callback))();
489487
} catch (error) {
490-
topology.close({ force: true });
488+
this.topology?.close({ force: true });
491489
throw error;
492490
}
493491
};

src/mongo_types.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
ObjectId,
1313
Timestamp
1414
} from './bson';
15+
import type { MongoLoggableComponent, MongoLogger } from './mongo_logger';
1516
import type { Sort } from './sort';
1617

1718
/** @internal */
@@ -397,8 +398,21 @@ export declare interface TypedEventEmitter<Events extends EventsDescription> ext
397398
* Typescript type safe event emitter
398399
* @public
399400
*/
400-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
401-
export class TypedEventEmitter<Events extends EventsDescription> extends EventEmitter {}
401+
402+
export class TypedEventEmitter<Events extends EventsDescription> extends EventEmitter {
403+
/** @internal */
404+
protected mongoLogger?: MongoLogger;
405+
/** @internal */
406+
protected component?: MongoLoggableComponent;
407+
/** @internal */
408+
protected emitAndLog<EventKey extends keyof Events>(
409+
event: EventKey | symbol,
410+
...args: Parameters<Events[EventKey]>
411+
): void {
412+
this.emit(event, ...args);
413+
if (this.component) this.mongoLogger?.debug(this.component, args[0]);
414+
}
415+
}
402416

403417
/** @public */
404418
export class CancellationToken extends TypedEventEmitter<{ cancel(): void }> {}

src/operations/create_collection.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import type { Document } from '../bson';
2+
import {
3+
MIN_SUPPORTED_QE_SERVER_VERSION,
4+
MIN_SUPPORTED_QE_WIRE_VERSION
5+
} from '../cmap/wire_protocol/constants';
26
import { Collection } from '../collection';
37
import type { Db } from '../db';
8+
import { MongoCompatibilityError } from '../error';
49
import type { PkFactory } from '../mongo_client';
510
import type { Server } from '../sdam/server';
611
import type { ClientSession } from '../sessions';
@@ -98,6 +103,10 @@ export interface CreateCollectionOptions extends CommandOperationOptions {
98103
changeStreamPreAndPostImages?: { enabled: boolean };
99104
}
100105

106+
/* @internal */
107+
const INVALID_QE_VERSION =
108+
'Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.';
109+
101110
/** @internal */
102111
export class CreateCollectionOperation extends CommandOperation<Collection> {
103112
override options: CreateCollectionOptions;
@@ -127,12 +136,17 @@ export class CreateCollectionOperation extends CommandOperation<Collection> {
127136
db.s.client.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
128137

129138
if (encryptedFields) {
139+
// Creating a QE collection required min server of 7.0.0
140+
if (server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION) {
141+
throw new MongoCompatibilityError(
142+
`${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
143+
);
144+
}
130145
// Create auxilliary collections for queryable encryption support.
131146
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
132-
const eccCollection = encryptedFields.eccCollection ?? `enxcol_.${name}.ecc`;
133147
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
134148

135-
for (const collectionName of [escCollection, eccCollection, ecocCollection]) {
149+
for (const collectionName of [escCollection, ecocCollection]) {
136150
const createOp = new CreateCollectionOperation(db, collectionName, {
137151
clusteredIndex: {
138152
key: { _id: 1 },

0 commit comments

Comments
 (0)