Skip to content

Commit d99b2ae

Browse files
authored
RUST-1387 Run csfle legacy spec tests (#781)
1 parent cb32700 commit d99b2ae

29 files changed

+723
-154
lines changed

.evergreen/config.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -511,12 +511,19 @@ functions:
511511
export CSFLE_SHARED_LIB_PATH=$(.evergreen/find-crypt_shared.sh "$PROJECT_DIRECTORY/crypt_shared/lib/")
512512
export DISABLE_CRYPT_SHARED=${DISABLE_CRYPT_SHARED}
513513
export TLS_FEATURE=${TLS_FEATURE}
514+
export PYTHON=${PYTHON}
515+
${PYTHON} -m pip install boto3
516+
514517
# Exported without xtrace to avoid leaking credentials
515518
set +o xtrace
516-
export KMS_PROVIDERS=$(cat << "EOF"
517-
${kms_providers}
518-
EOF
519-
)
519+
export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
520+
export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
521+
export AZURE_TENANT_ID=${AZURE_TENANT_ID}
522+
export AZURE_CLIENT_ID=${AZURE_CLIENT_ID}
523+
export AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET}
524+
export GCP_EMAIL=${GCP_EMAIL}
525+
export GCP_PRIVATE_KEY=${GCP_PRIVATE_KEY}
526+
export CSFLE_LOCAL_KEY=${CSFLE_LOCAL_KEY}
520527
set -o xtrace
521528
522529
.evergreen/run-csfle-tests.sh

.evergreen/run-csfle-tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ if [ "$OS" = "Windows_NT" ]; then
2020
export SSL_CERT_DIR=$(cygpath /etc/ssl/certs --windows)
2121
fi
2222

23+
export AWS_DEFAULT_REGION=us-east-1
24+
. ${DRIVERS_TOOLS}/.evergreen/csfle/set-temp-creds.sh
25+
2326
echo "cargo test options: --features ${FEATURE_FLAGS} ${OPTIONS}"
2427

2528
CARGO_RESULT=0

src/client/csfle.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,13 @@ impl ClientState {
9797
}
9898

9999
fn make_crypt(opts: &AutoEncryptionOptions) -> Result<Crypt> {
100-
let mut builder = Crypt::builder().kms_providers(&opts.kms_providers.credentials()?)?;
100+
let mut builder = Crypt::builder().kms_providers(&opts.kms_providers.credentials_doc()?)?;
101101
if let Some(m) = &opts.schema_map {
102102
builder = builder.schema_map(&bson::to_document(m)?)?;
103103
}
104+
if let Some(m) = &opts.encrypted_fields_map {
105+
builder = builder.encrypted_field_config_map(&bson::to_document(m)?)?;
106+
}
104107
#[cfg(not(test))]
105108
let disable_crypt_shared = false;
106109
#[cfg(test)]

src/client/csfle/client_builder.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::{bson::Document, error::Result, options::ClientOptions, Client, Namespace};
1+
use crate::{bson::Document, error::Result, options::ClientOptions, Client};
22

3-
use super::options::{AutoEncryptionOptions, KmsProviders};
3+
use super::options::AutoEncryptionOptions;
44

55
/// A builder for constructing a `Client` with auto-encryption enabled.
66
///
@@ -31,14 +31,10 @@ pub struct EncryptedClientBuilder {
3131
}
3232

3333
impl EncryptedClientBuilder {
34-
pub(crate) fn new(
35-
client_options: ClientOptions,
36-
key_vault_namespace: Namespace,
37-
kms_providers: KmsProviders,
38-
) -> Self {
34+
pub(crate) fn new(client_options: ClientOptions, enc_opts: AutoEncryptionOptions) -> Self {
3935
EncryptedClientBuilder {
4036
client_options,
41-
enc_opts: AutoEncryptionOptions::new(key_vault_namespace, kms_providers),
37+
enc_opts,
4238
}
4339
}
4440

@@ -101,8 +97,8 @@ impl EncryptedClientBuilder {
10197
self
10298
}
10399

104-
/// Constructs a new `Client` using automatic encryption. May perform DNS lookups as part of
105-
/// `Client` initialization.
100+
/// Constructs a new `Client` using automatic encryption. May perform DNS lookups and/or spawn
101+
/// mongocryptd as part of `Client` initialization.
106102
pub async fn build(self) -> Result<Client> {
107103
let client = Client::with_options(self.client_options)?;
108104
*client.inner.csfle.write().await =

src/client/csfle/client_encryption.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl ClientEncryption {
5959
) -> Result<Self> {
6060
let kms_providers = KmsProviders::new(kms_providers)?;
6161
let crypt = Crypt::builder()
62-
.kms_providers(&kms_providers.credentials()?)?
62+
.kms_providers(&kms_providers.credentials_doc()?)?
6363
.build()?;
6464
let exec = CryptExecutor::new_explicit(
6565
key_vault_client.weak(),

src/client/csfle/options.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::HashMap;
22

33
use bson::Array;
44
use mongocrypt::ctx::KmsProvider;
5+
use serde::Deserialize;
56

67
use crate::{
78
bson::{Bson, Document},
@@ -19,13 +20,15 @@ use crate::{
1920
/// https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#libmongocrypt-auto-encryption-allow-list
2021
/// )). To bypass automatic encryption for all operations, set bypassAutoEncryption=true in
2122
/// AutoEncryptionOpts.
22-
#[derive(Debug, Clone)]
23-
#[non_exhaustive]
23+
#[derive(Debug, Clone, Deserialize)]
24+
#[serde(rename_all = "camelCase", deny_unknown_fields)]
2425
pub(crate) struct AutoEncryptionOptions {
2526
/// Used for data key queries. Will default to an internal client if not set.
27+
#[serde(skip)]
2628
pub(crate) key_vault_client: Option<crate::Client>,
2729
/// A collection that contains all data keys used for encryption and decryption (aka the key
2830
/// vault collection).
31+
#[serde(default = "default_key_vault_namespace")]
2932
pub(crate) key_vault_namespace: Namespace,
3033
/// Options individual to each KMS provider.
3134
pub(crate) kms_providers: KmsProviders,
@@ -54,9 +57,17 @@ pub(crate) struct AutoEncryptionOptions {
5457
pub(crate) bypass_query_analysis: Option<bool>,
5558
/// Disable loading crypt_shared.
5659
#[cfg(test)]
60+
#[serde(skip)]
5761
pub(crate) disable_crypt_shared: Option<bool>,
5862
}
5963

64+
fn default_key_vault_namespace() -> Namespace {
65+
Namespace {
66+
db: "keyvault".to_string(),
67+
coll: "datakeys".to_string(),
68+
}
69+
}
70+
6071
impl AutoEncryptionOptions {
6172
pub(crate) fn new(key_vault_namespace: Namespace, kms_providers: KmsProviders) -> Self {
6273
Self {
@@ -74,9 +85,11 @@ impl AutoEncryptionOptions {
7485
}
7586
}
7687

77-
#[derive(Debug, Clone)]
88+
#[derive(Deserialize, Debug, Clone)]
7889
pub(crate) struct KmsProviders {
90+
#[serde(flatten)]
7991
credentials: HashMap<KmsProvider, Document>,
92+
#[serde(skip)]
8093
tls_options: Option<KmsProvidersTlsOptions>,
8194
}
8295

@@ -105,13 +118,36 @@ impl KmsProviders {
105118
})
106119
}
107120

108-
pub(crate) fn credentials(&self) -> Result<Document> {
121+
pub(crate) fn credentials_doc(&self) -> Result<Document> {
109122
Ok(bson::to_document(&self.credentials)?)
110123
}
111124

112125
pub(crate) fn tls_options(&self) -> &Option<KmsProvidersTlsOptions> {
113126
&self.tls_options
114127
}
128+
129+
#[cfg(test)]
130+
pub(crate) fn credentials(&self) -> &HashMap<KmsProvider, Document> {
131+
&self.credentials
132+
}
133+
134+
#[cfg(test)]
135+
pub(crate) fn set(&mut self, provider: KmsProvider, creds: Document, tls: Option<TlsOptions>) {
136+
self.credentials.insert(provider.clone(), creds);
137+
if let Some(tls) = tls {
138+
self.tls_options
139+
.get_or_insert_with(KmsProvidersTlsOptions::new)
140+
.insert(provider, tls);
141+
}
142+
}
143+
144+
#[cfg(test)]
145+
pub(crate) fn clear(&mut self, provider: &KmsProvider) {
146+
self.credentials.remove(provider);
147+
if let Some(tls_opts) = &mut self.tls_options {
148+
tls_opts.remove(provider);
149+
}
150+
}
115151
}
116152

117153
impl AutoEncryptionOptions {

src/client/csfle/state_machine.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ use tokio::{
1515

1616
use crate::{
1717
client::{options::ServerAddress, WeakClient},
18+
coll::options::FindOptions,
1819
error::{Error, Result},
1920
operation::{RawOutput, RunCommand},
21+
options::ReadConcern,
2022
runtime::{AsyncStream, Process, TlsConfig},
2123
Client,
2224
Namespace,
@@ -152,7 +154,14 @@ impl CryptExecutor {
152154
let kv_coll = kv_client
153155
.database(&kv_ns.db)
154156
.collection::<RawDocumentBuf>(&kv_ns.coll);
155-
let mut cursor = kv_coll.find(filter, None).await?;
157+
let mut cursor = kv_coll
158+
.find(
159+
filter,
160+
FindOptions::builder()
161+
.read_concern(ReadConcern::MAJORITY)
162+
.build(),
163+
)
164+
.await?;
156165
while cursor.advance().await? {
157166
ctx.mongo_feed(cursor.current())?;
158167
}

src/client/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,10 @@ impl Client {
180180
) -> Result<EncryptedClientBuilder> {
181181
Ok(EncryptedClientBuilder::new(
182182
client_options,
183-
key_vault_namespace,
184-
csfle::options::KmsProviders::new(kms_providers)?,
183+
csfle::options::AutoEncryptionOptions::new(
184+
key_vault_namespace,
185+
csfle::options::KmsProviders::new(kms_providers)?,
186+
),
185187
))
186188
}
187189

@@ -562,6 +564,11 @@ impl Client {
562564
})
563565
.ok()
564566
}
567+
568+
#[cfg(test)]
569+
pub(crate) fn options(&self) -> &ClientOptions {
570+
&self.inner.options
571+
}
565572
}
566573

567574
#[cfg(feature = "csfle")]

src/coll/options.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,8 +1068,10 @@ pub struct DropCollectionOptions {
10681068
pub write_concern: Option<WriteConcern>,
10691069

10701070
/// Map of encrypted fields for the collection.
1071+
// Serialization is skipped because the server doesn't accept this option; it's needed for
1072+
// preprocessing. Deserialization needs to remain because it's used in test files.
10711073
#[cfg(feature = "csfle")]
1072-
#[serde(skip)]
1074+
#[serde(skip_serializing)]
10731075
pub encrypted_fields: Option<Document>,
10741076
}
10751077

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ impl Error {
286286
}
287287
ErrorKind::Transaction { message } => Some(message.clone()),
288288
ErrorKind::IncompatibleServer { message } => Some(message.clone()),
289+
ErrorKind::InvalidArgument { message } => Some(message.clone()),
290+
#[cfg(feature = "csfle")]
291+
ErrorKind::Csfle(err) => err.message.clone(),
289292
_ => None,
290293
}
291294
}

0 commit comments

Comments
 (0)