Skip to content

RUST-2161 Support auto encryption in unified tests #1426

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

Merged
merged 8 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 12 additions & 0 deletions src/client/csfle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,15 @@ pub(crate) fn aux_collections(
}
Ok(out)
}

impl Client {
pub(crate) async fn init_csfle(&self, opts: AutoEncryptionOptions) -> Result<()> {
let mut csfle_state = self.inner.csfle.write().await;
if csfle_state.is_some() {
return Err(Error::internal("double initialization of csfle state"));
}
*csfle_state = Some(ClientState::new(self, opts).await?);

Ok(())
}
}
3 changes: 1 addition & 2 deletions src/client/csfle/client_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ impl EncryptedClientBuilder {
/// mongocryptd as part of `Client` initialization.
pub async fn build(self) -> Result<Client> {
let client = Client::with_options(self.client_options)?;
*client.inner.csfle.write().await =
Some(super::ClientState::new(&client, self.enc_opts).await?);
client.init_csfle(self.enc_opts).await?;
Ok(client)
}
}
2 changes: 1 addition & 1 deletion src/coll/action/drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ where
}
// * from a `list_collections` call:
let found;
if enc_fields.is_none() && client_enc_fields.is_some() {
if enc_fields.is_none() && enc_opts.is_some() {
let filter = doc! { "name": self.name() };
let mut specs: Vec<_> = match session.as_deref_mut() {
Some(s) => {
Expand Down
69 changes: 62 additions & 7 deletions src/test/csfle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ pub(crate) type KmsProviderList = Vec<KmsInfo>;
static CSFLE_LOCAL_KEY: Lazy<String> = Lazy::new(|| get_env_var("CSFLE_LOCAL_KEY"));
static FLE_AWS_KEY: Lazy<String> = Lazy::new(|| get_env_var("FLE_AWS_KEY"));
static FLE_AWS_SECRET: Lazy<String> = Lazy::new(|| get_env_var("FLE_AWS_SECRET"));
static FLE_AWS_TEMP_KEY: Lazy<String> = Lazy::new(|| get_env_var("CSFLE_AWS_TEMP_ACCESS_KEY_ID"));
static FLE_AWS_TEMP_SECRET: Lazy<String> =
Lazy::new(|| get_env_var("CSFLE_AWS_TEMP_SECRET_ACCESS_KEY"));
static FLE_AWS_TEMP_SESSION_TOKEN: Lazy<String> =
Lazy::new(|| get_env_var("CSFLE_AWS_TEMP_SESSION_TOKEN"));
static FLE_AZURE_TENANTID: Lazy<String> = Lazy::new(|| get_env_var("FLE_AZURE_TENANTID"));
static FLE_AZURE_CLIENTID: Lazy<String> = Lazy::new(|| get_env_var("FLE_AZURE_CLIENTID"));
static FLE_AZURE_CLIENTSECRET: Lazy<String> = Lazy::new(|| get_env_var("FLE_AZURE_CLIENTSECRET"));
Expand All @@ -61,13 +66,16 @@ static CSFLE_TLS_CERT_DIR: Lazy<String> = Lazy::new(|| get_env_var("CSFLE_TLS_CE
static CRYPT_SHARED_LIB_PATH: Lazy<String> = Lazy::new(|| get_env_var("CRYPT_SHARED_LIB_PATH"));

fn get_env_var(name: &str) -> String {
std::env::var(name).unwrap_or_else(|_| {
panic!(
"Missing environment variable for {}. See src/test/csfle.rs for the list of required \
variables and instructions for retrieving them.",
name
)
})
match std::env::var(name) {
Ok(v) if !v.is_empty() => v,
_ => {
panic!(
"Missing environment variable for {}. See src/test/csfle.rs for the list of \
required variables and instructions for retrieving them.",
name
)
}
}
}

pub(crate) static AWS_KMS: Lazy<KmsInfo> = Lazy::new(|| {
Expand All @@ -80,6 +88,17 @@ pub(crate) static AWS_KMS: Lazy<KmsInfo> = Lazy::new(|| {
None,
)
});
static AWS_TEMP_KMS: Lazy<KmsInfo> = Lazy::new(|| {
(
KmsProvider::aws(),
doc! {
"accessKeyId": &*FLE_AWS_TEMP_KEY,
"secretAccessKey": &*FLE_AWS_TEMP_SECRET,
"sessionToken": &*FLE_AWS_TEMP_SESSION_TOKEN,
},
None,
)
});
pub(crate) static AWS_KMS_NAME1: Lazy<KmsInfo> = Lazy::new(|| {
let aws_info = AWS_KMS.clone();
(aws_info.0.with_name("name1"), aws_info.1, aws_info.2)
Expand Down Expand Up @@ -310,3 +329,39 @@ async fn fle2v2_ok(name: &str) -> bool {
}
true
}

pub(crate) fn fill_kms_placeholders(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes more sense here than in test_runner.rs; the only logic change is the conditional for temp creds for AWS.

kms_provider_map: std::collections::HashMap<mongocrypt::ctx::KmsProvider, Document>,
) -> KmsProviderList {
use mongocrypt::ctx::KmsProviderType;

let placeholder = doc! { "$$placeholder": 1 };

let mut kms_providers = Vec::new();
for (provider, mut config) in kms_provider_map {
// AWS uses temp creds if the "sessionToken" key is present in the config
let test_kms_provider = if *provider.provider_type() == KmsProviderType::Aws
&& config.contains_key("sessionToken")
{
Some(&*AWS_TEMP_KMS)
} else {
(*ALL_KMS_PROVIDERS).iter().find(|(p, ..)| p == &provider)
};

for (key, value) in config.iter_mut() {
if value.as_document() == Some(&placeholder) {
let test_kms_provider = test_kms_provider
.unwrap_or_else(|| panic!("missing config for {:?}", provider));
let placeholder_value = test_kms_provider.1.get(key).unwrap_or_else(|| {
panic!("provider config {:?} missing key {:?}", provider, key)
});
*value = placeholder_value.clone();
}
}

let tls_options = test_kms_provider.and_then(|(_, _, tls_options)| tls_options.clone());
kms_providers.push((provider, config, tls_options));
}

kms_providers
}
12 changes: 10 additions & 2 deletions src/test/csfle/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ async fn run_unified() {

#[tokio::test(flavor = "multi_thread")]
async fn run_legacy() {
// TODO RUST-528: unskip this file
let mut skipped_files = vec!["timeoutMS.json"];
let mut skipped_files = vec![
// TODO RUST-528: unskip this file
"timeoutMS.json",
// These files have been migrated to unified tests.
// TODO DRIVERS-3178 remove these once the files are gone.
"fle2v2-BypassQueryAnalysis.json",
"fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json",
"localSchema.json",
"maxWireVersion.json",
];
if cfg!(not(feature = "openssl-tls")) {
skipped_files.push("kmipKMS.json");
}
Expand Down
Loading