Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(NODE-6284): make sparsity and trimFactor optional #4189

Merged
merged 12 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .evergreen/install-mongodb-client-encryption.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#! /usr/bin/env bash
set +o xtrace # Do not write AWS credentials to stderr
set +o xtrace

# Initial checks for running these tests
if [ -z ${PROJECT_DIRECTORY+omitted} ]; then echo "PROJECT_DIRECTORY is unset" && exit 1; fi
Expand All @@ -9,20 +9,19 @@ source "${PROJECT_DIRECTORY}/.evergreen/init-node-and-npm-env.sh"
set -o xtrace # Write all commands first to stderr
set -o errexit # Exit the script with error if any of the commands fail

rm -rf $INSTALL_DIR
rm -rf mongodb-client-encryption
git clone https://github.com/mongodb-js/mongodb-client-encryption.git
pushd mongodb-client-encryption

if [ -n "${LIBMONGOCRYPT_VERSION}" ]; then
# nightly tests test with `latest` to test against the laster FLE build.
npm run install:libmongocrypt -- --libVersion $LIBMONGOCRYPT_VERSION
npm run install:libmongocrypt -- --build --libVersion $LIBMONGOCRYPT_VERSION
else
# otherwise use whatever is specified in the package.json.
npm run install:libmongocrypt
fi

echo "finished installing libmongocrypt"
BINDINGS_DIR=$(pwd)

popd

Expand Down
25 changes: 4 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"js-yaml": "^4.1.0",
"mocha": "^10.4.0",
"mocha-sinon": "^2.1.2",
"mongodb-client-encryption": "^6.1.0-alpha.0",
"mongodb-client-encryption": "^6.1.0",
"mongodb-legacy": "^6.0.1",
"nyc": "^15.1.0",
"prettier": "^2.8.8",
Expand Down
15 changes: 12 additions & 3 deletions src/client-side-encryption/client_encryption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@ import type {
MongoCryptOptions
} from 'mongodb-client-encryption';

import { type Binary, deserialize, type Document, type Long, serialize, type UUID } from '../bson';
import {
type Binary,
deserialize,
type Document,
type Int32,
type Long,
serialize,
type UUID
} from '../bson';
import { type AnyBulkWriteOperation, type BulkWriteResult } from '../bulk/common';
import { type ProxyOptions } from '../cmap/connection';
import { type Collection } from '../collection';
Expand Down Expand Up @@ -948,12 +956,13 @@ export interface ClientEncryptionRewrapManyDataKeyResult {
/**
* @public
* RangeOptions specifies index options for a Queryable Encryption field supporting "rangePreview" queries.
* min, max, sparsity, and range must match the values set in the encryptedFields of the destination collection.
* min, max, sparsity, trimFactor and range must match the values set in the encryptedFields of the destination collection.
* For double and decimal128, min/max/precision must all be set, or all be unset.
*/
export interface RangeOptions {
min?: any;
max?: any;
sparsity: Long;
sparsity?: Long;
trimFactor?: Int32;
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
precision?: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { type Binary, EJSON, Int32, Long } from 'bson';
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
import { expect } from 'chai';

/* eslint-disable @typescript-eslint/no-restricted-imports */
import { ClientEncryption } from '../../../src/client-side-encryption/client_encryption';
import { installNodeDNSWorkaroundHooks } from '../../tools/runner/hooks/configuration';

const metaData: MongoDBMetadataUI = {
requires: {
clientSideEncryption: '>=6.1.0',

// The Range Explicit Encryption tests require MongoDB server 7.0+ for QE v2.
// The tests must not run against a standalone.
//
// `range` is not supported on 8.0+ servers.
mongodb: '>=8.0.0',
topology: '!single'
}
};

const getKmsProviders = (): { local: { key: string } } => {
const result = EJSON.parse(process.env.CSFLE_KMS_PROVIDERS || '{}') as unknown as {
local: { key: string };
};

return { local: result.local };
};

describe('Range Explicit Encryption Defaults', function () {
installNodeDNSWorkaroundHooks();

let clientEncryption: ClientEncryption;
let keyId;
let keyVaultClient;
let payload_defaults: Binary;

beforeEach(async function () {
// Create a MongoClient named `keyVaultClient`.
keyVaultClient = this.configuration.newClient();

// Create a ClientEncryption object named `clientEncryption` with these options:
// ```typescript
// class ClientEncryptionOpts {
// keyVaultClient: keyVaultClient,
// keyVaultNamespace: "keyvault.datakeys",
// kmsProviders: { "local": { "key": "<base64 decoding of LOCAL_MASTERKEY>" } },
// }
// ```
clientEncryption = new ClientEncryption(keyVaultClient, {
keyVaultNamespace: 'keyvault.datakeys',
kmsProviders: getKmsProviders()
});

// Create a key with `clientEncryption.createDataKey`. Store the returned key ID in a variable named `keyId`.
keyId = await clientEncryption.createDataKey('local');

// Call `clientEncryption.encrypt` to encrypt the int32 value `123` with these options:
// ```typescript
// class EncryptOpts {
// keyId : keyId,
// algorithm: "Range",
// contentionFactor: 0,
// rangeOpts: RangeOpts {
// min: 0,
// max: 1000
// }
// }
// ```
// Store the result in a variable named `payload_defaults`.
payload_defaults = await clientEncryption.encrypt(new Int32(123), {
keyId,
algorithm: 'Range',
contentionFactor: 0,
rangeOptions: {
min: 0,
max: 1000
}
});
});

afterEach(async function () {
await keyVaultClient.close();
});

it('Case 1: Uses libmongocrypt defaults', metaData, async function () {
// Call `clientEncryption.encrypt` to encrypt the int32 value `123` with these options:
// ```typescript
// class EncryptOpts {
// keyId : keyId,
// algorithm: "Range",
// contentionFactor: 0,
// rangeOpts: RangeOpts {
// min: 0,
// max: 1000,
// sparsity: 2,
// trimFactor: 6
// }
// }
// ```
const encrypted = await clientEncryption.encrypt(new Int32(123), {
keyId: keyId,
algorithm: 'Range',
contentionFactor: 0,
rangeOptions: {
min: 0,
max: 1000,
sparsity: new Long(2),
trimFactor: new Int32(6)
}
});

// Assert the returned payload size equals the size of `payload_defaults`.
expect(encrypted.length()).to.equal(payload_defaults.length());
});

it('Case 2: can find encrypted range and return the maximum', metaData, async function () {
// Call `clientEncryption.encrypt` to encrypt the int32 value `123` with these options:
// ```typescript
// class EncryptOpts {
// keyId : keyId,
// algorithm: "Range",
// contentionFactor: 0,
// rangeOpts: RangeOpts {
// min: 0,
// max: 1000,
// trimFactor: 0
// }
// }
// ```
const encrypted = await clientEncryption.encrypt(new Int32(123), {
keyId: keyId,
algorithm: 'Range',
contentionFactor: 0,
rangeOptions: {
min: 0,
max: 1000,
trimFactor: new Int32(0)
}
});

// Assert the returned payload size is greater than the size of `payload_defaults`.
expect(encrypted.length()).to.be.greaterThan(payload_defaults.length());
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ describe('Client Side Encryption (Legacy)', function () {
}

if (isServerless) {
if (description === "Compact works with 'range' fields") {
return 'TODO(NODE-6332): fix compactStructuredEncryptionData against serverless';
}
// TODO(NODE-4730): Fix failing csfle tests against serverless
const isSkippedTest = [
'BypassQueryAnalysis decrypts',
Expand Down
Loading