diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 1661ba87c4..1204adad36 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -2204,7 +2204,7 @@ tasks: - func: bootstrap kms servers - func: run custom csfle tests vars: - CSFLE_GIT_REF: 67bec571c0c21f4db8a96b6bd61cb24dfc87a223 + CSFLE_GIT_REF: 77b51c00ab4ff58916dd39f55657e1ecc0af281c - name: run-custom-csfle-tests-5.0-master tags: - run-custom-dependency-tests @@ -2234,7 +2234,7 @@ tasks: - func: bootstrap kms servers - func: run custom csfle tests vars: - CSFLE_GIT_REF: 67bec571c0c21f4db8a96b6bd61cb24dfc87a223 + CSFLE_GIT_REF: 77b51c00ab4ff58916dd39f55657e1ecc0af281c - name: run-custom-csfle-tests-rapid-master tags: - run-custom-dependency-tests @@ -2264,7 +2264,7 @@ tasks: - func: bootstrap kms servers - func: run custom csfle tests vars: - CSFLE_GIT_REF: 67bec571c0c21f4db8a96b6bd61cb24dfc87a223 + CSFLE_GIT_REF: 77b51c00ab4ff58916dd39f55657e1ecc0af281c - name: run-custom-csfle-tests-latest-master tags: - run-custom-dependency-tests diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index b06ed36fd7..596c31a0f4 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -622,8 +622,10 @@ const oneOffFuncAsTasks = oneOffFuncs.map(oneOffFunc => ({ ] })); +const FLE_PINNED_COMMIT = '77b51c00ab4ff58916dd39f55657e1ecc0af281c' + for (const version of ['5.0', 'rapid', 'latest']) { - for (const ref of ['67bec571c0c21f4db8a96b6bd61cb24dfc87a223', 'master']) { + for (const ref of [FLE_PINNED_COMMIT, 'master']) { oneOffFuncAsTasks.push({ name: `run-custom-csfle-tests-${version}-${ref === 'master' ? ref : 'pinned-commit'}`, tags: ['run-custom-dependency-tests'], diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index b39576c5a8..dd52f2215f 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -52,7 +52,7 @@ else source "$DRIVERS_TOOLS"/.evergreen/csfle/set-temp-creds.sh fi -npm install mongodb-client-encryption@"2.4.0" +npm install mongodb-client-encryption@"2.5.0" npm install @mongodb-js/zstd npm install snappy diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.21.automatic_data_encryption_keys.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.21.automatic_data_encryption_keys.test.ts new file mode 100644 index 0000000000..c05962176c --- /dev/null +++ b/test/integration/client-side-encryption/client_side_encryption.prose.21.automatic_data_encryption_keys.test.ts @@ -0,0 +1,158 @@ +import { expect } from 'chai'; + +import { BSON, Collection, Db, MongoServerError } from '../../../src'; +import { installNodeDNSWorkaroundHooks } from '../../tools/runner/hooks/configuration'; + +const metadata = { + requires: { + clientSideEncryption: true, + mongodb: '>=6.0.0', + topology: '!single' + } +} as const; + +const documentValidationFailureCode = 121; +const typeMismatchCode = 14; + +describe('21. Automatic Data Encryption Keys', () => { + installNodeDNSWorkaroundHooks(); + + let db: Db; + let clientEncryption; + let client; + let MongoCryptCreateEncryptedCollectionError; + + const runProseTestsFor = provider => { + const masterKey = { + aws: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' + }, + local: null + }[provider]; + beforeEach(async function () { + client = this.configuration.newClient(); + const { + ClientEncryption, + MongoCryptCreateEncryptedCollectionError: MongoCryptCreateEncryptedCollectionErrorCtor + } = this.configuration.mongodbClientEncryption; + MongoCryptCreateEncryptedCollectionError = MongoCryptCreateEncryptedCollectionErrorCtor; + + if (typeof process.env.CSFLE_KMS_PROVIDERS !== 'string') { + if (this.currentTest) { + this.currentTest.skipReason = 'This test requires env CSFLE_KMS_PROVIDERS to be set'; + } + return this.currentTest?.skip(); + } + + const { aws, local } = BSON.EJSON.parse(process.env.CSFLE_KMS_PROVIDERS); + + clientEncryption = new ClientEncryption(client, { + keyVaultClient: client, + keyVaultNamespace: 'keyvault.datakeys', + kmsProviders: { aws, local } + }); + + db = client.db('automatic_data_encryption_keys'); + await db.dropDatabase().catch(() => null); + }); + + afterEach(async function () { + await db?.dropDatabase().catch(() => null); + await client?.close(); + }); + + it('Case 1: Simple Creation and Validation', metadata, async () => { + const createCollectionOptions = { + encryptedFields: { fields: [{ path: 'ssn', bsonType: 'string', keyId: null }] } + }; + + const { collection } = await clientEncryption.createEncryptedCollection(db, 'testing1', { + provider, + createCollectionOptions, + masterKey + }); + + expect(collection).to.be.instanceOf(Collection); + expect(collection.namespace).to.equal('automatic_data_encryption_keys.testing1'); + + const result = await collection.insertOne({ ssn: '123-45-6789' }).catch(error => error); + expect(result).to.be.instanceOf(MongoServerError); + expect(result).to.have.property('code', documentValidationFailureCode); + }); + + it('Case 2: Missing encryptedFields', metadata, async () => { + const createCollectionOptions = {}; + + const result = await clientEncryption + .createEncryptedCollection(db, 'testing1', { + provider, + createCollectionOptions, + masterKey + }) + .catch(error => error); + + expect(result).to.be.instanceOf(TypeError); + }); + + it('Case 3: Invalid keyId', metadata, async () => { + const createCollectionOptions = { + encryptedFields: { fields: [{ path: 'ssn', bsonType: 'string', keyId: false }] } + }; + + const result = await clientEncryption + .createEncryptedCollection(db, 'testing1', { + provider, + createCollectionOptions, + masterKey + }) + .catch(error => error); + + expect(result).to.be.instanceOf(MongoCryptCreateEncryptedCollectionError); + expect(result).nested.property('cause.code', typeMismatchCode); + // BSON field 'create.encryptedFields.fields.keyId' is the wrong type 'bool', expected type 'binData' + expect(result.cause.message) + .to.match(/bool/i) + .and.match(/binData/i) + .and.match(/keyId/i); + }); + + it('Case 4: Insert encrypted value', metadata, async () => { + const createCollectionOptions = { + encryptedFields: { fields: [{ path: 'ssn', bsonType: 'string', keyId: null }] } + }; + + const { collection, encryptedFields } = await clientEncryption.createEncryptedCollection( + db, + 'testing1', + { + provider, + createCollectionOptions, + masterKey + } + ); + + expect(collection).to.be.instanceOf(Collection); + expect(collection.namespace).to.equal('automatic_data_encryption_keys.testing1'); + + const ssn = clientEncryption.encrypt('123-45-6789', { + algorithm: 'Unindexed', + keyId: encryptedFields.fields[0].keyId + }); + + const result = await collection.insertOne({ ssn }).catch(error => error); + expect(result).to.be.instanceOf(MongoServerError); + expect(result).to.have.property('code', documentValidationFailureCode); + expect(result).to.have.nested.property( + 'errInfo.details.schemaRulesNotSatisfied[0].propertiesNotSatisfied[0].propertyName', + 'ssn' + ); + }); + }; + + for (const provider of ['local', 'aws']) { + context(`${provider}`, () => { + runProseTestsFor(provider); + }); + } +}); 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 581047869c..cd96078c59 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 @@ -27,7 +27,7 @@ const metaData: MongoDBMetadataUI = { }; /** - * a comparitor function to sort two documents by their _id + * a comparator function to sort two documents by their _id */ function byId(a, b) { if (a._id > b._id) return 1;