use crate::test_utils;
use aws_db_esdk::client as transform_client;
use aws_db_esdk::dynamodb::types::BeaconKeySource;
use aws_db_esdk::dynamodb::types::BeaconVersion;
use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::dynamodb::types::GetPrefix;
use aws_db_esdk::dynamodb::types::SearchConfig;
use aws_db_esdk::dynamodb::types::SingleKeyStore;
use aws_db_esdk::dynamodb::types::StandardBeacon;
use aws_db_esdk::dynamodb::types::VirtualField;
use aws_db_esdk::dynamodb::types::VirtualPart;
use aws_db_esdk::dynamodb::types::VirtualTransform;
use aws_db_esdk::intercept::DbEsdkInterceptor;
use aws_db_esdk::key_store::client as keystore_client;
use aws_db_esdk::key_store::types::key_store_config::KeyStoreConfig;
use aws_db_esdk::key_store::types::KmsConfiguration;
use aws_db_esdk::material_providers::client as mpl_client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::DynamoDbTablesEncryptionConfig;
use aws_sdk_dynamodb::types::AttributeValue;
use std::collections::HashMap;
const GSI_NAME: &str = "stateAndHasTestResult-index";
pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate::BoxError> {
let ddb_table_name = test_utils::SIMPLE_BEACON_TEST_DDB_TABLE_NAME;
let branch_key_wrapping_kms_key_arn = test_utils::TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN;
let branch_key_ddb_table_name = test_utils::TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME;
let length1_prefix_virtual_transform_list = vec![VirtualTransform::Prefix(
GetPrefix::builder().length(1).build()?,
)];
let has_test_result_part = VirtualPart::builder()
.loc("hasTestResult")
.trans(length1_prefix_virtual_transform_list)
.build()?;
let state_part = VirtualPart::builder().loc("state").build()?;
let virtual_part_list = vec![state_part, has_test_result_part];
let state_and_has_test_result_field = VirtualField::builder()
.name("stateAndHasTestResult")
.parts(virtual_part_list)
.build()?;
let virtual_field_list = vec![state_and_has_test_result_field];
let standard_beacon_list = vec![StandardBeacon::builder()
.name("stateAndHasTestResult")
.length(5)
.build()?];
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let key_store_config = KeyStoreConfig::builder()
.kms_client(aws_sdk_kms::Client::new(&sdk_config))
.ddb_client(aws_sdk_dynamodb::Client::new(&sdk_config))
.ddb_table_name(branch_key_ddb_table_name)
.logical_key_store_name(branch_key_ddb_table_name)
.kms_configuration(KmsConfiguration::KmsKeyArn(
branch_key_wrapping_kms_key_arn.to_string(),
))
.build()?;
let key_store = keystore_client::Client::from_conf(key_store_config)?;
let beacon_version = BeaconVersion::builder()
.standard_beacons(standard_beacon_list)
.virtual_fields(virtual_field_list)
.version(1) .key_store(key_store.clone())
.key_source(BeaconKeySource::Single(
SingleKeyStore::builder()
.key_id(branch_key_id)
.cache_ttl(6000)
.build()?,
))
.build()?;
let beacon_versions = vec![beacon_version];
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let kms_keyring = mpl
.create_aws_kms_hierarchical_keyring()
.branch_key_id(branch_key_id)
.key_store(key_store)
.ttl_seconds(6000)
.send()
.await?;
let attribute_actions_on_encrypt = HashMap::from([
("customer_id".to_string(), CryptoAction::SignOnly), ("create_time".to_string(), CryptoAction::SignOnly), ("state".to_string(), CryptoAction::EncryptAndSign), ("hasTestResult".to_string(), CryptoAction::EncryptAndSign), ]);
let table_config = DynamoDbTableEncryptionConfig::builder()
.logical_table_name(ddb_table_name)
.partition_key_name("customer_id")
.sort_key_name("create_time")
.attribute_actions_on_encrypt(attribute_actions_on_encrypt)
.keyring(kms_keyring)
.search(
SearchConfig::builder()
.write_version(1) .versions(beacon_versions)
.build()?,
)
.build()?;
let encryption_config = DynamoDbTablesEncryptionConfig::builder()
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
.build()?;
let item_with_has_test_result = HashMap::from([
(
"customer_id".to_string(),
AttributeValue::S("ABC-123".to_string()),
),
(
"create_time".to_string(),
AttributeValue::N("1681495205".to_string()),
),
("state".to_string(), AttributeValue::S("CA".to_string())),
("hasTestResult".to_string(), AttributeValue::Bool(true)),
]);
let item_with_no_has_test_result = HashMap::from([
(
"customer_id".to_string(),
AttributeValue::S("DEF-456".to_string()),
),
(
"create_time".to_string(),
AttributeValue::N("1681495205".to_string()),
),
("state".to_string(), AttributeValue::S("CA".to_string())),
("hasTestResult".to_string(), AttributeValue::Bool(false)),
]);
let trans = transform_client::Client::from_conf(encryption_config.clone())?;
let resolve_output = trans
.resolve_attributes()
.table_name(ddb_table_name)
.item(item_with_has_test_result.clone())
.version(1)
.send()
.await?;
assert_eq!(resolve_output.compound_beacons.unwrap().len(), 0);
let virtual_fields = resolve_output.virtual_fields.unwrap();
assert_eq!(virtual_fields.len(), 1);
assert_eq!(virtual_fields["stateAndHasTestResult"], "CAt");
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(encryption_config)?)
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item_with_has_test_result.clone()))
.send()
.await?;
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item_with_no_has_test_result.clone()))
.send()
.await?;
let expression_attribute_values = HashMap::from([
(
":stateAndHasTestResult".to_string(),
AttributeValue::S("CAt".to_string()),
),
]);
for _i in 0..10 {
let query_response = ddb
.query()
.table_name(ddb_table_name)
.index_name(GSI_NAME)
.key_condition_expression("stateAndHasTestResult = :stateAndHasTestResult")
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
.send()
.await?;
if query_response.items.is_none() || query_response.items.as_ref().unwrap().is_empty() {
std::thread::sleep(std::time::Duration::from_millis(20));
continue;
}
let attribute_values = query_response.items.unwrap();
assert_eq!(attribute_values.len(), 1);
let returned_item = &attribute_values[0];
assert_eq!(returned_item["state"], AttributeValue::S("CA".to_string()));
assert_eq!(returned_item["hasTestResult"], AttributeValue::Bool(true));
break;
}
println!("virtual_beacon_searchable_encryption successful.");
Ok(())
}