Skip to content

Commit f4fc742

Browse files
authored
PYTHON-3276 [pymongo] FLE 1.0 shared library (#947)
1 parent 78476d0 commit f4fc742

File tree

5 files changed

+99
-23
lines changed

5 files changed

+99
-23
lines changed

.evergreen/config.yml

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ functions:
450450
export LIBMONGOCRYPT_URL="${libmongocrypt_url}"
451451
export TEST_ENCRYPTION=1
452452
fi
453+
if [ -n "${test_csfle}" ]; then
454+
export TEST_CSFLE=1
455+
fi
453456
if [ -n "${test_pyopenssl}" ]; then
454457
export TEST_PYOPENSSL=1
455458
fi
@@ -1232,7 +1235,6 @@ tasks:
12321235
VERSION: "5.0"
12331236
TOPOLOGY: "sharded_cluster"
12341237
- func: "run tests"
1235-
12361238
- name: "test-6.0-standalone"
12371239
tags: ["6.0", "standalone"]
12381240
commands:
@@ -2161,6 +2163,14 @@ axes:
21612163
variables:
21622164
test_encryption: true
21632165
batchtime: 10080 # 7 days
2166+
- id: "encryption_with_csfle"
2167+
display_name: "Encryption with CSFLE"
2168+
tags: ["encryption_tag", "csfle"]
2169+
variables:
2170+
test_encryption: true
2171+
test_csfle: true
2172+
batchtime: 10080 # 7 days
2173+
21642174

21652175
# Run pyopenssl tests?
21662176
- id: pyopenssl
@@ -2229,21 +2239,6 @@ buildvariants:
22292239
- ".4.0"
22302240
- ".3.6"
22312241

2232-
- matrix_name: "tests-all-encryption"
2233-
matrix_spec:
2234-
platform:
2235-
# OSes that support versions of MongoDB>=2.6 with SSL.
2236-
- awslinux
2237-
auth-ssl: "*"
2238-
encryption: "*"
2239-
display_name: "Encryption ${platform} ${auth-ssl}"
2240-
tasks:
2241-
- ".6.0"
2242-
- ".5.0"
2243-
- ".4.4"
2244-
- ".4.2"
2245-
- ".4.0"
2246-
22472242
- matrix_name: "tests-archlinux"
22482243
matrix_spec:
22492244
platform:
@@ -2297,14 +2292,27 @@ buildvariants:
22972292
auth: "auth"
22982293
ssl: "nossl"
22992294
encryption: "*"
2300-
display_name: "Encryption ${platform} ${auth} ${ssl}"
2295+
display_name: "${encryption} ${platform} ${auth} ${ssl}"
23012296
tasks: &encryption-server-versions
2297+
- ".rapid"
23022298
- ".latest"
23032299
- ".6.0"
23042300
- ".5.0"
23052301
- ".4.4"
23062302
- ".4.2"
23072303
- ".4.0"
2304+
rules: &encryption-exclude-rules
2305+
- if:
2306+
platform: "*"
2307+
auth: "*"
2308+
ssl: "*"
2309+
encryption: [ "encryption_with_csfle" ]
2310+
then:
2311+
remove_tasks:
2312+
- ".5.0"
2313+
- ".4.4"
2314+
- ".4.2"
2315+
- ".4.0"
23082316

23092317
# Test one server version with zSeries, POWER8, and ARM.
23102318
- matrix_name: "test-different-cpu-architectures"
@@ -2385,8 +2393,21 @@ buildvariants:
23852393
# dependency tests-python-version-rhel62-test-encryption_.../test-2.6-standalone is not present in the project config
23862394
# coverage: "*"
23872395
encryption: "*"
2388-
display_name: "Encryption ${python-version} ${platform} ${auth-ssl}"
2396+
display_name: "${encryption} ${python-version} ${platform} ${auth-ssl}"
23892397
tasks: *encryption-server-versions
2398+
rules:
2399+
- if:
2400+
platform: "*"
2401+
python-version: "*"
2402+
auth-ssl: "*"
2403+
encryption: [ "encryption_with_csfle" ]
2404+
then:
2405+
remove_tasks:
2406+
- ".5.0"
2407+
- ".4.4"
2408+
- ".4.2"
2409+
- ".4.0"
2410+
23902411

23912412
- matrix_name: "tests-python-version-ubuntu18-without-c-extensions"
23922413
matrix_spec:
@@ -2481,8 +2502,20 @@ buildvariants:
24812502
python-version-windows: "*"
24822503
auth-ssl: "*"
24832504
encryption: "*"
2484-
display_name: "Encryption ${platform} ${python-version-windows} ${auth-ssl}"
2505+
display_name: "${encryption} ${platform} ${python-version-windows} ${auth-ssl}"
24852506
tasks: *encryption-server-versions
2507+
rules:
2508+
- if:
2509+
platform: "*"
2510+
python-version-windows: "*"
2511+
auth-ssl: "*"
2512+
encryption: [ "encryption_with_csfle" ]
2513+
then:
2514+
remove_tasks:
2515+
- ".5.0"
2516+
- ".4.4"
2517+
- ".4.2"
2518+
- ".4.0"
24862519

24872520
# Storage engine tests on Ubuntu 18.04 (x86_64) with Python 3.7.
24882521
- matrix_name: "tests-storage-engines"

.evergreen/run-tests.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set -o errexit # Exit the script with error if any of the commands fail
1111
# COVERAGE If non-empty, run the test suite with coverage.
1212
# TEST_ENCRYPTION If non-empty, install pymongocrypt.
1313
# LIBMONGOCRYPT_URL The URL to download libmongocrypt.
14+
# TEST_CSFLE If non-empty, install CSFLE
1415

1516
if [ -n "${SET_XTRACE_ON}" ]; then
1617
set -o xtrace
@@ -27,6 +28,7 @@ COVERAGE=${COVERAGE:-}
2728
COMPRESSORS=${COMPRESSORS:-}
2829
MONGODB_API_VERSION=${MONGODB_API_VERSION:-}
2930
TEST_ENCRYPTION=${TEST_ENCRYPTION:-}
31+
TEST_CSFLE=${TEST_CSFLE:-}
3032
LIBMONGOCRYPT_URL=${LIBMONGOCRYPT_URL:-}
3133
DATA_LAKE=${DATA_LAKE:-}
3234

@@ -153,7 +155,16 @@ if [ -z "$DATA_LAKE" ]; then
153155
else
154156
TEST_ARGS="-s test.test_data_lake"
155157
fi
156-
158+
if [ -z $TEST_CSFLE ]; then
159+
echo "CSFLE not being tested"
160+
else
161+
$PYTHON $DRIVERS_TOOLS/.evergreen/mongodl.py --component csfle \
162+
--version latest --out ../csfle/
163+
export DYLD_FALLBACK_LIBRARY_PATH=../csfle/lib/:$DYLD_FALLBACK_LIBRARY_PATH
164+
export LD_LIBRARY_PATH=../csfle/lib:$LD_LIBRARY_PATH
165+
export PATH=../csfle/bin:$PATH
166+
TEST_ARGS="-s test.test_encryption"
167+
fi
157168
# Don't download unittest-xml-reporting from pypi, which often fails.
158169
if $PYTHON -c "import xmlrunner"; then
159170
# The xunit output dir must be a Python style absolute path.

pymongo/encryption.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,14 @@ def _get_internal_client(encrypter, mongo_client):
296296

297297
io_callbacks = _EncryptionIO(metadata_client, key_vault_coll, mongocryptd_client, opts)
298298
self._auto_encrypter = AutoEncrypter(
299-
io_callbacks, MongoCryptOptions(opts._kms_providers, schema_map)
299+
io_callbacks,
300+
MongoCryptOptions(
301+
opts._kms_providers,
302+
schema_map,
303+
csfle_path=opts._csfle_path,
304+
csfle_required=opts._csfle_required,
305+
bypass_encryption=opts._bypass_auto_encryption,
306+
),
300307
)
301308
self._closed = False
302309

pymongo/encryption_options.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ def __init__(
3939
key_vault_namespace: str,
4040
key_vault_client: Optional["MongoClient"] = None,
4141
schema_map: Optional[Mapping[str, Any]] = None,
42-
bypass_auto_encryption: Optional[bool] = False,
42+
bypass_auto_encryption: bool = False,
4343
mongocryptd_uri: str = "mongodb://localhost:27020",
4444
mongocryptd_bypass_spawn: bool = False,
4545
mongocryptd_spawn_path: str = "mongocryptd",
4646
mongocryptd_spawn_args: Optional[List[str]] = None,
4747
kms_tls_options: Optional[Mapping[str, Any]] = None,
48+
csfle_path: Optional[str] = None,
49+
csfle_required: bool = False,
4850
) -> None:
4951
"""Options to configure automatic client-side field level encryption.
5052
@@ -140,6 +142,12 @@ def __init__(
140142
Or to supply a client certificate::
141143
142144
kms_tls_options={'kmip': {'tlsCertificateKeyFile': 'client.pem'}}
145+
- `csfle_path` (optional): Override the path to load the CSFLE library.
146+
- `csfle_required` (optional): If 'true', refuse to continue encryption without a CSFLE
147+
library
148+
149+
.. versionchanged:: 4.2
150+
Added `csfle_path` and `csfle_required` parameters
143151
144152
.. versionchanged:: 4.0
145153
Added the `kms_tls_options` parameter and the "kmip" KMS provider.
@@ -152,7 +160,8 @@ def __init__(
152160
"install a compatible version with: "
153161
"python -m pip install 'pymongo[encryption]'"
154162
)
155-
163+
self._csfle_path = csfle_path
164+
self._csfle_required = csfle_required
156165
self._kms_providers = kms_providers
157166
self._key_vault_namespace = key_vault_namespace
158167
self._key_vault_client = key_vault_client

test/test_encryption.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ def get_client_opts(client):
8282

8383

8484
class TestAutoEncryptionOpts(PyMongoTestCase):
85+
@unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed")
86+
@unittest.skipUnless(os.environ.get("TEST_CSFLE"), "csfle is not installed")
87+
def test_csfle(self):
88+
# Test that we can pick up csfle automatically
89+
client = MongoClient(
90+
auto_encryption_opts=AutoEncryptionOpts(
91+
KMS_PROVIDERS, "keyvault.datakeys", csfle_required=True
92+
),
93+
connect=False,
94+
)
95+
self.addCleanup(client.close)
96+
8597
@unittest.skipIf(_HAVE_PYMONGOCRYPT, "pymongocrypt is installed")
8698
def test_init_requires_pymongocrypt(self):
8799
with self.assertRaises(ConfigurationError):
@@ -1749,6 +1761,10 @@ def test_case_8(self):
17491761

17501762
# https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#bypass-spawning-mongocryptd
17511763
class TestBypassSpawningMongocryptdProse(EncryptionIntegrationTest):
1764+
@unittest.skipIf(
1765+
os.environ.get("TEST_CSFLE"),
1766+
"this prose test does not work when CSFLE is on a system dynamic library search path.",
1767+
)
17521768
def test_mongocryptd_bypass_spawn(self):
17531769
# Lower the mongocryptd timeout to reduce the test run time.
17541770
self._original_timeout = encryption._MONGOCRYPTD_TIMEOUT_MS

0 commit comments

Comments
 (0)