From 8aef2a3e36ba07c34aba619e8ab36ebf6f585736 Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:25:09 -0700 Subject: [PATCH 01/10] chore: CHANGELOG and aws-lc-sys bump for Rust 1.2.3 release --- CHANGELOG.md | 7 +++++++ DynamoDbEncryption/runtimes/rust/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cdd991614..b15094ada5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Rust-1.2.3 (2026-03-10) + +### Maintenance + +- bump aws-lc-sys to 0.38 to mitigate false positive code scanners + + ## [3.9.1](https://github.com/aws/aws-database-encryption-sdk-dynamodb/compare/v3.9.0...v3.9.1) (2026-02-06) This release is available in the following languages: diff --git a/DynamoDbEncryption/runtimes/rust/Cargo.toml b/DynamoDbEncryption/runtimes/rust/Cargo.toml index 14544ff875..e55ec17540 100644 --- a/DynamoDbEncryption/runtimes/rust/Cargo.toml +++ b/DynamoDbEncryption/runtimes/rust/Cargo.toml @@ -17,7 +17,7 @@ readme = "README.md" [dependencies] aws-config = "1.8.12" aws-lc-rs = {version = "1.15.4"} -aws-lc-sys = { version = "0.37", optional = true } +aws-lc-sys = { version = "0.38", optional = true } aws-lc-fips-sys = { version = "0.13", optional = true } aws-sdk-dynamodb = "1.103.0" aws-sdk-kms = "1.98.0" From 489f480558628fe892e46071e9be9ef7feb27a00 Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:37:32 -0700 Subject: [PATCH 02/10] chore: format --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b15094ada5..9c9f5e087a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,6 @@ - bump aws-lc-sys to 0.38 to mitigate false positive code scanners - ## [3.9.1](https://github.com/aws/aws-database-encryption-sdk-dynamodb/compare/v3.9.0...v3.9.1) (2026-02-06) This release is available in the following languages: From c443eaba2d5fcd80988b735b18db41b4b951996c Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:38:42 -0700 Subject: [PATCH 03/10] chore: bump not-grep --- .github/workflows/ci_static_analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_static_analysis.yml b/.github/workflows/ci_static_analysis.yml index ede7b4b9a9..a22d8f5023 100644 --- a/.github/workflows/ci_static_analysis.yml +++ b/.github/workflows/ci_static_analysis.yml @@ -17,4 +17,4 @@ jobs: python -m pip install --upgrade pip python -m pip install setuptools==81.0.0 - name: not-grep - uses: mattsb42-meta/not-grep@1.0.0 + uses: mattsb42-meta/not-grep From e84ef03e1c88584e823a7e44d4735758382b9106 Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:17:17 -0700 Subject: [PATCH 04/10] fix(rust): use static branch key IDs in examples Replace dynamic branch key creation with pre-existing static branch key IDs, matching Java/NET test configuration. This avoids test failures caused by querying DynamoDB items encrypted with stale branch keys from previous runs. --- .../runtimes/rust/examples/main.rs | 20 ++++++++----------- .../runtimes/rust/examples/test_utils.rs | 4 ++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/DynamoDbEncryption/runtimes/rust/examples/main.rs b/DynamoDbEncryption/runtimes/rust/examples/main.rs index cd3d5b9b57..db5e7491a2 100644 --- a/DynamoDbEncryption/runtimes/rust/examples/main.rs +++ b/DynamoDbEncryption/runtimes/rust/examples/main.rs @@ -60,23 +60,19 @@ pub async fn main() -> Result<(), BoxError2> { keyring::mrk_discovery_multi_keyring::put_item_get_item().await?; clientsupplier::client_supplier_example::put_item_get_item().await?; - let key_id = create_keystore_key::keystore_create_key().await?; - let key_id2 = create_keystore_key::keystore_create_key().await?; - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - println!("Key Store Keys created. Waiting 5 seconds for consistency."); - std::thread::sleep(std::time::Duration::from_secs(5)); + let key_id = test_utils::TEST_BRANCH_KEY_ID; + let key_id2 = test_utils::TEST_ALTERNATE_BRANCH_KEY_ID; - keyring::hierarchical_keyring::put_item_get_item(&key_id, &key_id2).await?; + keyring::hierarchical_keyring::put_item_get_item(key_id, key_id2).await?; - searchableencryption::basic_searchable_encryption::put_and_query_with_beacon(&key_id).await?; - searchableencryption::beacon_styles_searchable_encryption::put_and_query_with_beacon(&key_id) + searchableencryption::basic_searchable_encryption::put_and_query_with_beacon(key_id).await?; + searchableencryption::beacon_styles_searchable_encryption::put_and_query_with_beacon(key_id) .await?; - searchableencryption::compound_beacon_searchable_encryption::put_and_query_with_beacon(&key_id) + searchableencryption::compound_beacon_searchable_encryption::put_and_query_with_beacon(key_id) .await?; - searchableencryption::virtual_beacon_searchable_encryption::put_and_query_with_beacon(&key_id) + searchableencryption::virtual_beacon_searchable_encryption::put_and_query_with_beacon(key_id) .await?; - searchableencryption::complexexample::complex_searchable_encryption::run_example(&key_id) + searchableencryption::complexexample::complex_searchable_encryption::run_example(key_id) .await?; // ScanError will have to wait until we have a reasonable error message strategy diff --git a/DynamoDbEncryption/runtimes/rust/examples/test_utils.rs b/DynamoDbEncryption/runtimes/rust/examples/test_utils.rs index 52c845c308..980fbe7f31 100644 --- a/DynamoDbEncryption/runtimes/rust/examples/test_utils.rs +++ b/DynamoDbEncryption/runtimes/rust/examples/test_utils.rs @@ -43,6 +43,10 @@ pub const TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN: &str = // Our tests require access to DDB Table with this name configured as a branch keystore pub const TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME: &str = "KeyStoreDdbTable"; + +// Pre-existing branch key IDs in the key store, matching Java/NET test configuration +pub const TEST_BRANCH_KEY_ID: &str = "3f43a9af-08c5-4317-b694-3d3e883dcaef"; +pub const TEST_ALTERNATE_BRANCH_KEY_ID: &str = "4bb57643-07c1-419e-92ad-0df0df149d7c"; pub const TEST_COMPLEX_DDB_TABLE_NAME: &str = "ComplexBeaconTestTable"; // Helper method to clean up test items From 34fe0425918e9d7cf016eb74f6d84d0204d2d52d Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:31:46 -0700 Subject: [PATCH 05/10] fix(java): use static branch key IDs in examples Replace dynamic branch key creation with pre-existing static branch key IDs. This avoids test failures caused by querying DynamoDB items encrypted with stale branch keys from previous runs, and eliminates 5-second Thread.sleep waits. --- .../cryptography/examples/TestUtils.java | 6 +++++ .../TestHierarchicalKeyringExample.java | 23 +++---------------- ...acheAcrossHierarchicalKeyringsExample.java | 17 ++------------ .../SearchableEncryptionTestUtils.java | 4 ++++ .../TestBasicSearchableEncryptionExample.java | 16 ++----------- ...aconStylesSearchableEncryptionExample.java | 16 ++----------- ...oundBeaconSearchableEncryptionExample.java | 16 ++----------- ...tualBeaconSearchableEncryptionExample.java | 16 ++----------- ...estComplexSearchableEncryptionExample.java | 16 ++----------- 9 files changed, 25 insertions(+), 105 deletions(-) diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/TestUtils.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/TestUtils.java index 37bc5f3dbd..c43b994542 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/TestUtils.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/TestUtils.java @@ -14,6 +14,12 @@ public class TestUtils { public static final String TEST_PARTITION_ID = "91c1b6a2-6fc3-4539-ad5e-938d597ed730"; + // Pre-existing branch key IDs in the key store + public static final String TEST_BRANCH_KEY_ID = + "3f43a9af-08c5-4317-b694-3d3e883dcaef"; + public static final String TEST_ALTERNATE_BRANCH_KEY_ID = + "4bb57643-07c1-419e-92ad-0df0df149d7c"; + public static final String TEST_AWS_ACCOUNT_ID = "658956600833"; public static final String TEST_AWS_REGION = "us-west-2"; // These are public KMS Keys that MUST only be used for testing, and MUST NOT be used for any production data diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestHierarchicalKeyringExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestHierarchicalKeyringExample.java index 92f0d7f629..181fd9b211 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestHierarchicalKeyringExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestHierarchicalKeyringExample.java @@ -1,33 +1,16 @@ package software.amazon.cryptography.examples.keyring; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; import software.amazon.cryptography.examples.TestUtils; public class TestHierarchicalKeyringExample { @Test - public void TestHierarchicalKeyringExample() throws InterruptedException { - // Create new branch keys for test - String keyId1 = CreateKeyStoreKeyExample.KeyStoreCreateKey( - TestUtils.TEST_KEYSTORE_NAME, - TestUtils.TEST_LOGICAL_KEYSTORE_NAME, - TestUtils.TEST_KEYSTORE_KMS_KEY_ID - ); - String keyId2 = CreateKeyStoreKeyExample.KeyStoreCreateKey( - TestUtils.TEST_KEYSTORE_NAME, - TestUtils.TEST_LOGICAL_KEYSTORE_NAME, - TestUtils.TEST_KEYSTORE_KMS_KEY_ID - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestHierarchicalKeyringExample() { HierarchicalKeyringExample.HierarchicalKeyringGetItemPutItem( TestUtils.TEST_DDB_TABLE_NAME, - keyId1, - keyId2, + TestUtils.TEST_BRANCH_KEY_ID, + TestUtils.TEST_ALTERNATE_BRANCH_KEY_ID, TestUtils.TEST_KEYSTORE_NAME, TestUtils.TEST_LOGICAL_KEYSTORE_NAME, TestUtils.TEST_KEYSTORE_KMS_KEY_ID diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestSharedCacheAcrossHierarchicalKeyringsExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestSharedCacheAcrossHierarchicalKeyringsExample.java index 452da3f36b..ae772024e8 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestSharedCacheAcrossHierarchicalKeyringsExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/keyring/TestSharedCacheAcrossHierarchicalKeyringsExample.java @@ -1,28 +1,15 @@ package software.amazon.cryptography.examples.keyring; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; import software.amazon.cryptography.examples.TestUtils; public class TestSharedCacheAcrossHierarchicalKeyringsExample { @Test - public void TestSharedCacheAcrossHierarchicalKeyringsExample() - throws InterruptedException { - // Create new branch key for test - String keyId = CreateKeyStoreKeyExample.KeyStoreCreateKey( - TestUtils.TEST_KEYSTORE_NAME, - TestUtils.TEST_LOGICAL_KEYSTORE_NAME, - TestUtils.TEST_KEYSTORE_KMS_KEY_ID - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestSharedCacheAcrossHierarchicalKeyringsExample() { SharedCacheAcrossHierarchicalKeyringsExample.SharedCacheAcrossHierarchicalKeyringsGetItemPutItem( TestUtils.TEST_DDB_TABLE_NAME, - keyId, + TestUtils.TEST_BRANCH_KEY_ID, TestUtils.TEST_KEYSTORE_NAME, TestUtils.TEST_LOGICAL_KEYSTORE_NAME, TestUtils.TEST_PARTITION_ID, diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/SearchableEncryptionTestUtils.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/SearchableEncryptionTestUtils.java index a0083a655a..3012af3a63 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/SearchableEncryptionTestUtils.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/SearchableEncryptionTestUtils.java @@ -18,4 +18,8 @@ public class SearchableEncryptionTestUtils { public static final String TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME = "KeyStoreDdbTable"; public static final String TEST_LOGICAL_KEYSTORE_NAME = "KeyStoreDdbTable"; + + // Pre-existing branch key ID in the key store + public static final String TEST_BRANCH_KEY_ID = + "3f43a9af-08c5-4317-b694-3d3e883dcaef"; } diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBasicSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBasicSearchableEncryptionExample.java index 57539f58d4..6b817602e0 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBasicSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBasicSearchableEncryptionExample.java @@ -1,26 +1,14 @@ package software.amazon.cryptography.examples.searchableencryption; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; public class TestBasicSearchableEncryptionExample { @Test - public void TestBasicExample() throws InterruptedException { - // Create new branch key for test - String keyId = CreateKeyStoreKeyExample.KeyStoreCreateKey( - SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, - SearchableEncryptionTestUtils.TEST_LOGICAL_KEYSTORE_NAME, - SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestBasicExample() { BasicSearchableEncryptionExample.PutItemQueryItemWithBeacon( SearchableEncryptionTestUtils.UNIT_INSPECTION_TEST_DDB_TABLE_NAME, - keyId, + SearchableEncryptionTestUtils.TEST_BRANCH_KEY_ID, SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME ); diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBeaconStylesSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBeaconStylesSearchableEncryptionExample.java index 82f7be3408..5f654e58c9 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBeaconStylesSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestBeaconStylesSearchableEncryptionExample.java @@ -1,26 +1,14 @@ package software.amazon.cryptography.examples.searchableencryption; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; public class TestBeaconStylesSearchableEncryptionExample { @Test - public void TestCompoundItemEncryptDecrypt() throws InterruptedException { - // Create new branch key for test - String keyId = CreateKeyStoreKeyExample.KeyStoreCreateKey( - SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, - SearchableEncryptionTestUtils.TEST_LOGICAL_KEYSTORE_NAME, - SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestCompoundItemEncryptDecrypt() { BeaconStylesSearchableEncryptionExample.PutItemQueryItemWithBeaconStyles( SearchableEncryptionTestUtils.UNIT_INSPECTION_TEST_DDB_TABLE_NAME, - keyId, + SearchableEncryptionTestUtils.TEST_BRANCH_KEY_ID, SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME ); diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestCompoundBeaconSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestCompoundBeaconSearchableEncryptionExample.java index 9661c1f8f0..5e1e4c411e 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestCompoundBeaconSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestCompoundBeaconSearchableEncryptionExample.java @@ -1,26 +1,14 @@ package software.amazon.cryptography.examples.searchableencryption; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; public class TestCompoundBeaconSearchableEncryptionExample { @Test - public void TestCompoundItemEncryptDecrypt() throws InterruptedException { - // Create new branch key for test - String keyId = CreateKeyStoreKeyExample.KeyStoreCreateKey( - SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, - SearchableEncryptionTestUtils.TEST_LOGICAL_KEYSTORE_NAME, - SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestCompoundItemEncryptDecrypt() { CompoundBeaconSearchableEncryptionExample.PutItemQueryItemWithCompoundBeacon( SearchableEncryptionTestUtils.UNIT_INSPECTION_TEST_DDB_TABLE_NAME, - keyId, + SearchableEncryptionTestUtils.TEST_BRANCH_KEY_ID, SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME ); diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestVirtualBeaconSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestVirtualBeaconSearchableEncryptionExample.java index 0ba8587802..90d5ff4a36 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestVirtualBeaconSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/TestVirtualBeaconSearchableEncryptionExample.java @@ -1,26 +1,14 @@ package software.amazon.cryptography.examples.searchableencryption; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; public class TestVirtualBeaconSearchableEncryptionExample { @Test - public void TestVirtualBeaconExample() throws InterruptedException { - // Create new branch key for test - String keyId = CreateKeyStoreKeyExample.KeyStoreCreateKey( - SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, - SearchableEncryptionTestUtils.TEST_LOGICAL_KEYSTORE_NAME, - SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestVirtualBeaconExample() { VirtualBeaconSearchableEncryptionExample.PutItemQueryItemWithVirtualBeacon( SearchableEncryptionTestUtils.SIMPLE_BEACON_TEST_DDB_TABLE_NAME, - keyId, + SearchableEncryptionTestUtils.TEST_BRANCH_KEY_ID, SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME ); diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/complexexample/TestComplexSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/complexexample/TestComplexSearchableEncryptionExample.java index 06174d0bb4..70b75d5538 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/complexexample/TestComplexSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/test/java/software/amazon/cryptography/examples/searchableencryption/complexexample/TestComplexSearchableEncryptionExample.java @@ -1,27 +1,15 @@ package software.amazon.cryptography.examples.searchableencryption.complexexample; import org.testng.annotations.Test; -import software.amazon.cryptography.examples.CreateKeyStoreKeyExample; import software.amazon.cryptography.examples.searchableencryption.SearchableEncryptionTestUtils; public class TestComplexSearchableEncryptionExample { @Test - public void TestComplexExample() throws InterruptedException { - // Create new branch key for test - String keyId = CreateKeyStoreKeyExample.KeyStoreCreateKey( - SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, - SearchableEncryptionTestUtils.TEST_LOGICAL_KEYSTORE_NAME, - SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN - ); - - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - Thread.sleep(5000); - + public void TestComplexExample() { ComplexSearchableEncryptionExample.runExample( ComplexSearchableEncryptionTestUtils.TEST_DDB_TABLE_NAME, - keyId, + SearchableEncryptionTestUtils.TEST_BRANCH_KEY_ID, SearchableEncryptionTestUtils.TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, SearchableEncryptionTestUtils.TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME ); From 4331096a60e76c6f75a22f8e610581d591c3aa67 Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:48:29 -0700 Subject: [PATCH 06/10] chore: bump not-grep --- .github/workflows/ci_static_analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_static_analysis.yml b/.github/workflows/ci_static_analysis.yml index a22d8f5023..e0204f0508 100644 --- a/.github/workflows/ci_static_analysis.yml +++ b/.github/workflows/ci_static_analysis.yml @@ -17,4 +17,4 @@ jobs: python -m pip install --upgrade pip python -m pip install setuptools==81.0.0 - name: not-grep - uses: mattsb42-meta/not-grep + uses: mattsb42-meta/not-grep@1.0.1 From 5e444da2bc7f2d1e3d0872e3680e5ae52b7f27ef Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:29:47 -0700 Subject: [PATCH 07/10] fix(rust): suffix complex example partition keys with -rust to avoid collisions --- .../complexexample/put_requests.rs | 48 +++--- .../complexexample/query_requests.rs | 150 +++++++++++------- 2 files changed, 118 insertions(+), 80 deletions(-) diff --git a/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/put_requests.rs b/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/put_requests.rs index 23eaa71139..8752538c55 100644 --- a/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/put_requests.rs +++ b/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/put_requests.rs @@ -62,7 +62,7 @@ async fn put_all_meeting_items( let meeting1_attendee_list = vec![ss("able@gmail.com"), ss("zorro@gmail.com")]; let meeting1_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting1 = HashMap::from([ - entry("partition_key", "meeting1"), + entry("partition_key", "meeting1-rust"), entry("EmployeeID", "emp_001"), entry("EmployeeEmail", "able@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -79,7 +79,7 @@ async fn put_all_meeting_items( let meeting2_attendee_list = vec![ss("barney@gmail.com"), ss("zorro@gmail.com")]; let meeting2_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting2 = HashMap::from([ - entry("partition_key", "meeting2"), + entry("partition_key", "meeting2-rust"), entry("EmployeeID", "emp_002"), entry("EmployeeEmail", "barney@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -96,7 +96,7 @@ async fn put_all_meeting_items( let meeting3_attendee_list = vec![ss("charlie@gmail.com"), ss("zorro@gmail.com")]; let meeting3_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting3 = HashMap::from([ - entry("partition_key", "meeting3"), + entry("partition_key", "meeting3-rust"), entry("EmployeeID", "emp_003"), entry("EmployeeEmail", "charlie@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -113,7 +113,7 @@ async fn put_all_meeting_items( let meeting4_attendee_list = vec![ss("david@gmail.com"), ss("zorro@gmail.com")]; let meeting4_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting4 = HashMap::from([ - entry("partition_key", "meeting4"), + entry("partition_key", "meeting4-rust"), entry("EmployeeID", "emp_004"), entry("EmployeeEmail", "david@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -130,7 +130,7 @@ async fn put_all_meeting_items( let meeting5_attendee_list = vec![ss("barney@gmail.com"), ss("zorro@gmail.com")]; let meeting5_location = HashMap::from([entry("Floor", "12"), entry("Room", "407")]); let meeting5 = HashMap::from([ - entry("partition_key", "meeting5"), + entry("partition_key", "meeting5-rust"), entry("EmployeeID", "emp_002"), entry("EmployeeEmail", "barney@gmail.com"), entry("MeetingStart", "2022-07-04T14:00"), @@ -147,7 +147,7 @@ async fn put_all_meeting_items( let meeting6_attendee_list = vec![ss("charlie@gmail.com"), ss("zorro@gmail.com")]; let meeting6_location = HashMap::from([entry("Floor", "12"), entry("Room", "407")]); let meeting6 = HashMap::from([ - entry("partition_key", "meeting6"), + entry("partition_key", "meeting6-rust"), entry("EmployeeID", "emp_003"), entry("EmployeeEmail", "charlie@gmail.com"), entry("MeetingStart", "2022-07-04T14:00"), @@ -175,7 +175,7 @@ async fn put_all_employee_items( entry("City", "Seattle"), ]); let employee1 = HashMap::from([ - entry("partition_key", "employee1"), + entry("partition_key", "employee1-rust"), entry("EmployeeID", "emp_001"), entry("EmployeeEmail", "able@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -195,7 +195,7 @@ async fn put_all_employee_items( entry("City", "Seattle"), ]); let employee2 = HashMap::from([ - entry("partition_key", "employee2"), + entry("partition_key", "employee2-rust"), entry("EmployeeID", "emp_002"), entry("EmployeeEmail", "barney@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -215,7 +215,7 @@ async fn put_all_employee_items( entry("City", "Seattle"), ]); let employee3 = HashMap::from([ - entry("partition_key", "employee3"), + entry("partition_key", "employee3-rust"), entry("EmployeeID", "emp_003"), entry("EmployeeEmail", "charlie@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -235,7 +235,7 @@ async fn put_all_employee_items( entry("City", "NYC"), ]); let employee4 = HashMap::from([ - entry("partition_key", "employee4"), + entry("partition_key", "employee4-rust"), entry("EmployeeID", "emp_004"), entry("EmployeeEmail", "david@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -256,7 +256,7 @@ async fn put_all_project_items( ddb: &mut aws_sdk_dynamodb::Client, ) -> Result<(), crate::BoxError> { let project1 = HashMap::from([ - entry("partition_key", "project1"), + entry("partition_key", "project1-rust"), entry("ProjectName", "project_001"), entry("ProjectStatus", "Pending"), entry("ProjectStart", "2022-11-01"), @@ -266,7 +266,7 @@ async fn put_all_project_items( put_item(ddb_table_name, ddb, project1).await?; let project2 = HashMap::from([ - entry("partition_key", "project2"), + entry("partition_key", "project2-rust"), entry("ProjectName", "project_002"), entry("ProjectStatus", "Active"), entry("ProjectStart", "2022-07-04"), @@ -276,7 +276,7 @@ async fn put_all_project_items( put_item(ddb_table_name, ddb, project2).await?; let project3 = HashMap::from([ - entry("partition_key", "project3"), + entry("partition_key", "project3-rust"), entry("ProjectName", "project_003"), entry("ProjectStatus", "Active"), entry("ProjectStart", "2022-08-05"), @@ -286,7 +286,7 @@ async fn put_all_project_items( put_item(ddb_table_name, ddb, project3).await?; let project4 = HashMap::from([ - entry("partition_key", "project4"), + entry("partition_key", "project4-rust"), entry("ProjectName", "project_004"), entry("ProjectStatus", "Done"), entry("ProjectStart", "2020-03-03"), @@ -309,7 +309,7 @@ async fn put_all_reservation_items( entry("Room", "403"), ]); let reservation1 = HashMap::from([ - entry("partition_key", "reservation1"), + entry("partition_key", "reservation1-rust"), entry("MeetingStart", "2022-07-04T13:00"), entry("OrganizerEmail", "able@gmail.com"), entry("Duration", "30"), @@ -332,7 +332,7 @@ async fn put_all_reservation_items( entry("Room", "407"), ]); let reservation2 = HashMap::from([ - entry("partition_key", "reservation2"), + entry("partition_key", "reservation2-rust"), entry("MeetingStart", "2022-07-04T14:00"), entry("OrganizerEmail", "barney@gmail.com"), entry("Duration", "30"), @@ -356,7 +356,7 @@ async fn put_all_ticket_items( ddb: &mut aws_sdk_dynamodb::Client, ) -> Result<(), crate::BoxError> { let ticket1 = HashMap::from([ - entry("partition_key", "ticket1"), + entry("partition_key", "ticket1-rust"), entry("TicketNumber", "ticket_001"), entry("TicketModTime", "2022-10-07T14:32:25"), entry("CreatorEmail", "zorro@gmail.com"), @@ -368,7 +368,7 @@ async fn put_all_ticket_items( put_item(ddb_table_name, ddb, ticket1).await?; let ticket2 = HashMap::from([ - entry("partition_key", "ticket2"), + entry("partition_key", "ticket2-rust"), entry("TicketNumber", "ticket_001"), entry("TicketModTime", "2022-10-07T14:32:25"), entry("CreatorEmail", "able@gmail.com"), @@ -380,7 +380,7 @@ async fn put_all_ticket_items( put_item(ddb_table_name, ddb, ticket2).await?; let ticket3 = HashMap::from([ - entry("partition_key", "ticket3"), + entry("partition_key", "ticket3-rust"), entry("TicketNumber", "ticket_002"), entry("TicketModTime", "2022-10-06T14:32:25"), entry("CreatorEmail", "zorro@gmail.com"), @@ -392,7 +392,7 @@ async fn put_all_ticket_items( put_item(ddb_table_name, ddb, ticket3).await?; let ticket4 = HashMap::from([ - entry("partition_key", "ticket4"), + entry("partition_key", "ticket4-rust"), entry("TicketNumber", "ticket_002"), entry("TicketModTime", "2022-10-08T14:32:25"), entry("CreatorEmail", "charlie@gmail.com"), @@ -411,7 +411,7 @@ async fn put_all_timecard_items( ddb: &mut aws_sdk_dynamodb::Client, ) -> Result<(), crate::BoxError> { let timecard1 = HashMap::from([ - entry("partition_key", "timecard1"), + entry("partition_key", "timecard1-rust"), entry("ProjectName", "project_002"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "able@gmail.com"), @@ -421,7 +421,7 @@ async fn put_all_timecard_items( put_item(ddb_table_name, ddb, timecard1).await?; let timecard2 = HashMap::from([ - entry("partition_key", "timecard2"), + entry("partition_key", "timecard2-rust"), entry("ProjectName", "project_002"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "barney@gmail.com"), @@ -431,7 +431,7 @@ async fn put_all_timecard_items( put_item(ddb_table_name, ddb, timecard2).await?; let timecard3 = HashMap::from([ - entry("partition_key", "timecard3"), + entry("partition_key", "timecard3-rust"), entry("ProjectName", "project_003"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "charlie@gmail.com"), @@ -441,7 +441,7 @@ async fn put_all_timecard_items( put_item(ddb_table_name, ddb, timecard3).await?; let timecard4 = HashMap::from([ - entry("partition_key", "timecard4"), + entry("partition_key", "timecard4-rust"), entry("ProjectName", "project_003"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "barney@gmail.com"), diff --git a/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/query_requests.rs b/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/query_requests.rs index f64ae0e335..b9fc88c298 100644 --- a/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/query_requests.rs +++ b/DynamoDbEncryption/runtimes/rust/examples/searchableencryption/complexexample/query_requests.rs @@ -74,6 +74,7 @@ async fn run_query1( entry(":date1", "MS-2022-07-02"), entry(":date2", "MS-2022-07-08"), entry(":zero", "0"), + entry(":rustsuffix", "-rust"), ]); let query1_response = ddb @@ -83,7 +84,7 @@ async fn run_query1( .set_expression_attribute_names(Some(query1_names)) .set_expression_attribute_values(Some(query1_values)) .key_condition_expression("PK1 = :e AND SK1 BETWEEN :date1 AND :date2") - .filter_expression("#duration > :zero") + .filter_expression("#duration > :zero AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -92,7 +93,7 @@ async fn run_query1( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("meeting1")); + assert_eq!(items[0]["partition_key"], ss("meeting1-rust")); assert_eq!(items[0]["Subject"], ss("Scan Beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -119,6 +120,7 @@ async fn run_query2( entry(":date1", "MS-2022-07-02"), entry(":date2", "MS-2022-07-08"), entry(":zero", "0"), + entry(":rustsuffix", "-rust"), ]); let query2_response = ddb @@ -128,7 +130,7 @@ async fn run_query2( .set_expression_attribute_names(Some(query2_names)) .set_expression_attribute_values(Some(query2_values)) .key_condition_expression("PK = :employee AND SK BETWEEN :date1 AND :date2") - .filter_expression("#duration > :zero") + .filter_expression("#duration > :zero AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -137,7 +139,7 @@ async fn run_query2( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("meeting1")); + assert_eq!(items[0]["partition_key"], ss("meeting1-rust")); assert_eq!(items[0]["Subject"], ss("Scan Beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -166,6 +168,7 @@ async fn run_query3( entry(":room", "403"), entry(":date1", "MS-2022-07-02"), entry(":date2", "MS-2022-07-08"), + entry(":rustsuffix", "-rust"), ]); let query3_response = ddb @@ -174,7 +177,7 @@ async fn run_query3( .index_name("GSI-0") .set_expression_attribute_values(Some(query3_values)) .key_condition_expression("PK = :buildingbeacon AND SK BETWEEN :date1 AND :date2") - .filter_expression("Building = :building AND Floor = :floor AND Room = :room") + .filter_expression("Building = :building AND Floor = :floor AND Room = :room AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -183,7 +186,7 @@ async fn run_query3( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("reservation1")); + assert_eq!(items[0]["partition_key"], ss("reservation1-rust")); assert_eq!(items[0]["Subject"], ss("Scan beacons")); assert_eq!( items[0]["Location"].as_m().unwrap()["Building"], @@ -206,6 +209,7 @@ async fn run_query4( let query4_values = HashMap::from([ entry(":email", "EE-able@gmail.com"), entry(":employee", "E-emp_001"), + entry(":rustsuffix", "-rust"), ]); let query4_response = ddb @@ -214,6 +218,7 @@ async fn run_query4( .index_name("GSI-1") .set_expression_attribute_values(Some(query4_values)) .key_condition_expression("PK1 = :email AND SK1 = :employee") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -222,7 +227,7 @@ async fn run_query4( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); assert_eq!(items[0]["Location"].as_m().unwrap()["Desk"], ss("3")); Ok(()) @@ -239,6 +244,7 @@ async fn run_query5( entry(":email", "EE-able@gmail.com"), entry(":thirtydaysago", "MS-2023-03-20"), entry(":prefix", "MS-"), + entry(":rustsuffix", "-rust"), ]); let query5_response = ddb @@ -247,6 +253,7 @@ async fn run_query5( .index_name("GSI-1") .set_expression_attribute_values(Some(query5_values)) .key_condition_expression("PK1 = :email AND SK1 BETWEEN :prefix AND :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -255,7 +262,7 @@ async fn run_query5( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("meeting1")); + assert_eq!(items[0]["partition_key"], ss("meeting1-rust")); assert_eq!(items[0]["Subject"], ss("Scan Beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -275,6 +282,7 @@ async fn run_query6( let query6_values = HashMap::from([ entry(":creatoremail", "CE-zorro@gmail.com"), entry(":thirtydaysago", "MS-2023-03-20"), + entry(":rustsuffix", "-rust"), ]); let query6_response = ddb @@ -283,6 +291,7 @@ async fn run_query6( .index_name("GSI-1") .set_expression_attribute_values(Some(query6_values)) .key_condition_expression("PK1 = :creatoremail AND SK1 < :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -292,10 +301,10 @@ async fn run_query6( // Expected to be `ticket1` and `ticket3` assert!( - ((items[0]["partition_key"] == ss("ticket1")) - && (items[1]["partition_key"] == ss("ticket3"))) - || ((items[0]["partition_key"] == ss("ticket3")) - && (items[1]["partition_key"] == ss("ticket1"))) + ((items[0]["partition_key"] == ss("ticket1-rust")) + && (items[1]["partition_key"] == ss("ticket3-rust"))) + || ((items[0]["partition_key"] == ss("ticket3-rust")) + && (items[1]["partition_key"] == ss("ticket1-rust"))) ); Ok(()) } @@ -310,6 +319,7 @@ async fn run_query7( let query7_values = HashMap::from([ entry(":organizeremail", "OE-able@gmail.com"), entry(":thirtydaysago", "MS-2023-03-20"), + entry(":rustsuffix", "-rust"), ]); let query7_response = ddb @@ -318,6 +328,7 @@ async fn run_query7( .index_name("GSI-1") .set_expression_attribute_values(Some(query7_values)) .key_condition_expression("PK1 = :organizeremail AND SK1 < :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -326,7 +337,7 @@ async fn run_query7( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("reservation1")); + assert_eq!(items[0]["partition_key"], ss("reservation1-rust")); assert_eq!(items[0]["Subject"], ss("Scan beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -347,6 +358,7 @@ async fn run_query8( entry(":email", "EE-able@gmail.com"), entry(":prefix", "TC-"), entry(":thirtydaysago", "TC-2023-03-20"), + entry(":rustsuffix", "-rust"), ]); let query8_response = ddb @@ -355,6 +367,7 @@ async fn run_query8( .index_name("GSI-1") .set_expression_attribute_values(Some(query8_values)) .key_condition_expression("PK1 = :email AND SK1 BETWEEN :prefix AND :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -363,7 +376,7 @@ async fn run_query8( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("timecard1")); + assert_eq!(items[0]["partition_key"], ss("timecard1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_002")); Ok(()) } @@ -375,7 +388,8 @@ async fn run_query9( // Query 9: Get employee info by employee ID // Key condition: PK1=employeeID SK starts with "E-" - let query9_values = HashMap::from([entry(":employee", "E-emp_001"), entry(":prefix", "E-")]); + let query9_values = HashMap::from([entry(":employee", "E-emp_001"), entry(":prefix", "E-"), entry(":rustsuffix", "-rust"), + ]); let query9_response = ddb .query() @@ -383,6 +397,7 @@ async fn run_query9( .index_name("GSI-0") .set_expression_attribute_values(Some(query9_values)) .key_condition_expression("PK = :employee AND begins_with(SK, :prefix)") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -391,7 +406,7 @@ async fn run_query9( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); Ok(()) } @@ -405,7 +420,8 @@ async fn run_query10( // Filter condition: SK starts with "E-" let query10_values = - HashMap::from([entry(":email", "EE-able@gmail.com"), entry(":prefix", "E-")]); + HashMap::from([entry(":email", "EE-able@gmail.com"), entry(":prefix", "E-"), entry(":rustsuffix", "-rust"), + ]); let query10_response = ddb .query() @@ -413,6 +429,7 @@ async fn run_query10( .index_name("GSI-1") .set_expression_attribute_values(Some(query10_values)) .key_condition_expression("PK1 = :email AND begins_with(SK1, :prefix)") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -421,7 +438,7 @@ async fn run_query10( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); Ok(()) } @@ -433,7 +450,8 @@ async fn run_query11( // Query 11: Get ticket history by ticket number // Key condition: PK=TicketNumber - let query11_values = HashMap::from([entry(":ticket", "T-ticket_001")]); + let query11_values = HashMap::from([entry(":ticket", "T-ticket_001"), entry(":rustsuffix", "-rust"), + ]); let query11_response = ddb .query() @@ -441,6 +459,7 @@ async fn run_query11( .index_name("GSI-0") .set_expression_attribute_values(Some(query11_values)) .key_condition_expression("PK = :ticket") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -450,10 +469,10 @@ async fn run_query11( // Expected to be `ticket1` and `ticket3` assert!( - ((items[0]["partition_key"] == ss("ticket1")) - && (items[1]["partition_key"] == ss("ticket2"))) - || ((items[0]["partition_key"] == ss("ticket2")) - && (items[1]["partition_key"] == ss("ticket1"))) + ((items[0]["partition_key"] == ss("ticket1-rust")) + && (items[1]["partition_key"] == ss("ticket2-rust"))) + || ((items[0]["partition_key"] == ss("ticket2-rust")) + && (items[1]["partition_key"] == ss("ticket1-rust"))) ); Ok(()) } @@ -469,6 +488,7 @@ async fn run_query12( let query12_values = HashMap::from([ entry(":email", "CE-zorro@gmail.com"), entry(":ticket", "T-ticket_001"), + entry(":rustsuffix", "-rust"), ]); let query12_response = ddb @@ -477,7 +497,7 @@ async fn run_query12( .index_name("GSI-1") .set_expression_attribute_values(Some(query12_values)) .key_condition_expression("PK1 = :email") - .filter_expression("PK = :ticket") + .filter_expression("PK = :ticket AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -486,7 +506,7 @@ async fn run_query12( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("ticket1")); + assert_eq!(items[0]["partition_key"], ss("ticket1-rust")); assert_eq!(items[0]["TicketNumber"], ss("ticket_001")); Ok(()) } @@ -501,6 +521,7 @@ async fn run_query13( let query13_values = HashMap::from([ entry(":assigneeemail", "AE-able@gmail.com"), entry(":ticket", "T-ticket_001"), + entry(":rustsuffix", "-rust"), ]); let query13_response = ddb @@ -509,7 +530,7 @@ async fn run_query13( .index_name("GSI-2") .set_expression_attribute_values(Some(query13_values)) .key_condition_expression("PK2 = :assigneeemail") - .filter_expression("PK = :ticket") + .filter_expression("PK = :ticket AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -518,7 +539,7 @@ async fn run_query13( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("ticket1")); + assert_eq!(items[0]["partition_key"], ss("ticket1-rust")); assert_eq!(items[0]["Subject"], ss("Bad bug")); Ok(()) } @@ -533,6 +554,7 @@ async fn run_query14( let query14_values = HashMap::from([ entry(":city", "C-Seattle"), entry(":location", "B-44~F-12~D-3"), + entry(":rustsuffix", "-rust"), ]); let query14_response = ddb @@ -541,6 +563,7 @@ async fn run_query14( .index_name("GSI-3") .set_expression_attribute_values(Some(query14_values)) .key_condition_expression("PK3 = :city AND begins_with(SK3, :location)") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -549,7 +572,7 @@ async fn run_query14( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); assert_eq!(items[0]["Location"].as_m().unwrap()["Desk"], ss("3")); Ok(()) @@ -562,7 +585,8 @@ async fn run_query15( // Query 15: Get employees by manager email // Key condition: PK2 = ManagerEmail - let query15_values = HashMap::from([entry(":manageremail", "ME-zorro@gmail.com")]); + let query15_values = HashMap::from([entry(":manageremail", "ME-zorro@gmail.com"), entry(":rustsuffix", "-rust"), + ]); let query15_response = ddb .query() @@ -570,6 +594,7 @@ async fn run_query15( .index_name("GSI-2") .set_expression_attribute_values(Some(query15_values)) .key_condition_expression("PK2 = :manageremail") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -580,7 +605,7 @@ async fn run_query15( let mut found_known_value_item_query15 = false; for item in &items { - if item["partition_key"] == ss("employee1") { + if item["partition_key"] == ss("employee1-rust") { found_known_value_item_query15 = true; assert_eq!(item["EmployeeID"], ss("emp_001")); assert_eq!(item["Location"].as_m().unwrap()["Desk"], ss("3")); @@ -598,7 +623,8 @@ async fn run_query16( // Query 16: Get assigned tickets by assignee email // Key condition: PK2 = AssigneeEmail - let query16_values = HashMap::from([entry(":assigneeemail", "AE-able@gmail.com")]); + let query16_values = HashMap::from([entry(":assigneeemail", "AE-able@gmail.com"), entry(":rustsuffix", "-rust"), + ]); let query16_response = ddb .query() @@ -606,6 +632,7 @@ async fn run_query16( .index_name("GSI-2") .set_expression_attribute_values(Some(query16_values)) .key_condition_expression("PK2 = :assigneeemail") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -615,10 +642,10 @@ async fn run_query16( // Expected to be `ticket1` and `ticket4` assert!( - ((items[0]["partition_key"] == ss("ticket1")) - && (items[1]["partition_key"] == ss("ticket4"))) - || ((items[0]["partition_key"] == ss("ticket4")) - && (items[1]["partition_key"] == ss("ticket1"))) + ((items[0]["partition_key"] == ss("ticket1-rust")) + && (items[1]["partition_key"] == ss("ticket4-rust"))) + || ((items[0]["partition_key"] == ss("ticket4-rust")) + && (items[1]["partition_key"] == ss("ticket1-rust"))) ); Ok(()) } @@ -637,6 +664,7 @@ async fn run_query17( let query17_values = HashMap::from([ entry(":severity", "S-3"), entry(":yesterday", "M-2022-10-07T09:30:00"), + entry(":rustsuffix", "-rust"), ]); let query17_response = ddb @@ -645,6 +673,7 @@ async fn run_query17( .index_name("GSI-3") .set_expression_attribute_values(Some(query17_values)) .key_condition_expression("PK3 = :severity AND SK3 > :yesterday") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -656,7 +685,7 @@ async fn run_query17( let mut found_known_value_item_query17 = false; for item in &items { - if item["partition_key"] == ss("ticket1") { + if item["partition_key"] == ss("ticket1-rust") { found_known_value_item_query17 = true; assert_eq!(item["TicketNumber"], ss("ticket_001")); } @@ -678,6 +707,7 @@ async fn run_query18( entry(":status", "PSts-Pending"), entry(":startdate", "PS-2022-01-01"), entry(":target", "2025-01-01"), + entry(":rustsuffix", "-rust"), ]); let query18_response = ddb @@ -686,7 +716,7 @@ async fn run_query18( .index_name("GSI-1") .set_expression_attribute_values(Some(query18_values)) .key_condition_expression("PK1 = :status AND SK1 > :startdate") - .filter_expression("ProjectTarget < :target") + .filter_expression("ProjectTarget < :target AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -695,7 +725,7 @@ async fn run_query18( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("project1")); + assert_eq!(items[0]["partition_key"], ss("project1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_001")); Ok(()) } @@ -707,7 +737,8 @@ async fn run_query19( // Query 19: Get projects by name // Key condition: PK = ProjectName, SK = ProjectName - let query19_values = HashMap::from([entry(":projectname", "P-project_001")]); + let query19_values = HashMap::from([entry(":projectname", "P-project_001"), entry(":rustsuffix", "-rust"), + ]); let query19_response = ddb .query() @@ -715,6 +746,7 @@ async fn run_query19( .index_name("GSI-0") .set_expression_attribute_values(Some(query19_values)) .key_condition_expression("PK = :projectname AND SK = :projectname") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -723,7 +755,7 @@ async fn run_query19( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("project1")); + assert_eq!(items[0]["partition_key"], ss("project1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_001")); Ok(()) } @@ -739,6 +771,7 @@ async fn run_query20( entry(":projectname", "P-project_002"), entry(":date1", "TC-2022-01-01"), entry(":date2", "TC-2023-01-01"), + entry(":rustsuffix", "-rust"), ]); let query20_response = ddb @@ -747,6 +780,7 @@ async fn run_query20( .index_name("GSI-0") .set_expression_attribute_values(Some(query20_values)) .key_condition_expression("PK = :projectname AND SK BETWEEN :date1 AND :date2") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -756,10 +790,10 @@ async fn run_query20( assert_eq!(items.len(), 2); assert!( - ((items[0]["partition_key"] == ss("timecard1")) - && (items[1]["partition_key"] == ss("timecard2"))) - || ((items[0]["partition_key"] == ss("timecard2")) - && (items[1]["partition_key"] == ss("timecard1"))) + ((items[0]["partition_key"] == ss("timecard1-rust")) + && (items[1]["partition_key"] == ss("timecard2-rust"))) + || ((items[0]["partition_key"] == ss("timecard2-rust")) + && (items[1]["partition_key"] == ss("timecard1-rust"))) ); Ok(()) } @@ -779,6 +813,7 @@ async fn run_query21( let query21_values = HashMap::from([ entry(":projectname", "P-project_002"), entry(":role", "SDE3"), + entry(":rustsuffix", "-rust"), ]); let query21_response = ddb @@ -788,7 +823,7 @@ async fn run_query21( .set_expression_attribute_values(Some(query21_values)) .set_expression_attribute_names(Some(query21_names)) .key_condition_expression("PK = :projectname") - .filter_expression("#role = :role") + .filter_expression("#role = :role AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -797,7 +832,7 @@ async fn run_query21( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("timecard1")); + assert_eq!(items[0]["partition_key"], ss("timecard1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_002")); Ok(()) } @@ -809,7 +844,8 @@ async fn run_query22( // Query 22: Get reservations by building ID // Key condition: PK = Building ID - let query22_values = HashMap::from([entry(":building", "B-SEA33")]); + let query22_values = HashMap::from([entry(":building", "B-SEA33"), entry(":rustsuffix", "-rust"), + ]); let query22_response = ddb .query() @@ -817,6 +853,7 @@ async fn run_query22( .index_name("GSI-0") .set_expression_attribute_values(Some(query22_values)) .key_condition_expression("PK = :building") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -826,10 +863,10 @@ async fn run_query22( assert_eq!(items.len(), 2); assert!( - ((items[0]["partition_key"] == ss("reservation1")) - && (items[1]["partition_key"] == ss("reservation2"))) - || ((items[0]["partition_key"] == ss("reservation2")) - && (items[1]["partition_key"] == ss("reservation1"))) + ((items[0]["partition_key"] == ss("reservation1-rust")) + && (items[1]["partition_key"] == ss("reservation2-rust"))) + || ((items[0]["partition_key"] == ss("reservation2-rust")) + && (items[1]["partition_key"] == ss("reservation1-rust"))) ); Ok(()) } @@ -851,6 +888,7 @@ async fn run_query23( entry(":date1", "MS-2022-07-01"), entry(":date2", "MS-2022-07-08"), entry(":zero", "0"), + entry(":rustsuffix", "-rust"), ]); let query23_response = ddb @@ -860,7 +898,7 @@ async fn run_query23( .set_expression_attribute_values(Some(query23_values)) .set_expression_attribute_names(Some(query23_names)) .key_condition_expression("PK = :building AND SK BETWEEN :date1 AND :date2") - .filter_expression("#duration > :zero") + .filter_expression("#duration > :zero AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -870,10 +908,10 @@ async fn run_query23( assert_eq!(items.len(), 2); assert!( - ((items[0]["partition_key"] == ss("reservation1")) - && (items[1]["partition_key"] == ss("reservation2"))) - || ((items[0]["partition_key"] == ss("reservation2")) - && (items[1]["partition_key"] == ss("reservation1"))) + ((items[0]["partition_key"] == ss("reservation1-rust")) + && (items[1]["partition_key"] == ss("reservation2-rust"))) + || ((items[0]["partition_key"] == ss("reservation2-rust")) + && (items[1]["partition_key"] == ss("reservation1-rust"))) ); Ok(()) } From 8e80fdb49c57c0b8072e46f2831120ba4d479620 Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Wed, 11 Mar 2026 09:05:14 -0700 Subject: [PATCH 08/10] fix(java): suffix complex example partition keys with -java to avoid collisions --- .../complexexample/PutRequests.java | 60 +++-- .../complexexample/QueryRequests.java | 206 +++++++++++++++--- 2 files changed, 211 insertions(+), 55 deletions(-) diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/PutRequests.java b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/PutRequests.java index 09a716358f..3b545c6f08 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/PutRequests.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/PutRequests.java @@ -58,7 +58,7 @@ public static void putAllMeetingItemsToTable( final HashMap meeting1 = new HashMap<>(); meeting1.put( "partition_key", - AttributeValue.builder().s("meeting1").build() + AttributeValue.builder().s("meeting1-java").build() ); meeting1.put("EmployeeID", AttributeValue.builder().s("emp_001").build()); meeting1.put( @@ -99,7 +99,7 @@ public static void putAllMeetingItemsToTable( final HashMap meeting2 = new HashMap<>(); meeting2.put( "partition_key", - AttributeValue.builder().s("meeting2").build() + AttributeValue.builder().s("meeting2-java").build() ); meeting2.put("EmployeeID", AttributeValue.builder().s("emp_002").build()); meeting2.put( @@ -140,7 +140,7 @@ public static void putAllMeetingItemsToTable( final HashMap meeting3 = new HashMap<>(); meeting3.put( "partition_key", - AttributeValue.builder().s("meeting3").build() + AttributeValue.builder().s("meeting3-java").build() ); meeting3.put("EmployeeID", AttributeValue.builder().s("emp_003").build()); meeting3.put( @@ -181,7 +181,7 @@ public static void putAllMeetingItemsToTable( final HashMap meeting4 = new HashMap<>(); meeting4.put( "partition_key", - AttributeValue.builder().s("meeting4").build() + AttributeValue.builder().s("meeting4-java").build() ); meeting4.put("EmployeeID", AttributeValue.builder().s("emp_004").build()); meeting4.put( @@ -222,7 +222,7 @@ public static void putAllMeetingItemsToTable( final HashMap meeting5 = new HashMap<>(); meeting5.put( "partition_key", - AttributeValue.builder().s("meeting5").build() + AttributeValue.builder().s("meeting5-java").build() ); meeting5.put("EmployeeID", AttributeValue.builder().s("emp_002").build()); meeting5.put( @@ -263,7 +263,7 @@ public static void putAllMeetingItemsToTable( final HashMap meeting6 = new HashMap<>(); meeting6.put( "partition_key", - AttributeValue.builder().s("meeting6").build() + AttributeValue.builder().s("meeting6-java").build() ); meeting6.put("EmployeeID", AttributeValue.builder().s("emp_003").build()); meeting6.put( @@ -307,7 +307,7 @@ public static void putAllEmployeeItemsToTable( final HashMap employee1 = new HashMap<>(); employee1.put( "partition_key", - AttributeValue.builder().s("employee1").build() + AttributeValue.builder().s("employee1-java").build() ); employee1.put("EmployeeID", AttributeValue.builder().s("emp_001").build()); employee1.put( @@ -344,7 +344,7 @@ public static void putAllEmployeeItemsToTable( final HashMap employee2 = new HashMap<>(); employee2.put( "partition_key", - AttributeValue.builder().s("employee2").build() + AttributeValue.builder().s("employee2-java").build() ); employee2.put("EmployeeID", AttributeValue.builder().s("emp_002").build()); employee2.put( @@ -381,7 +381,7 @@ public static void putAllEmployeeItemsToTable( final HashMap employee3 = new HashMap<>(); employee3.put( "partition_key", - AttributeValue.builder().s("employee3").build() + AttributeValue.builder().s("employee3-java").build() ); employee3.put("EmployeeID", AttributeValue.builder().s("emp_003").build()); employee3.put( @@ -415,7 +415,7 @@ public static void putAllEmployeeItemsToTable( final HashMap employee4 = new HashMap<>(); employee4.put( "partition_key", - AttributeValue.builder().s("employee4").build() + AttributeValue.builder().s("employee4-java").build() ); employee4.put("EmployeeID", AttributeValue.builder().s("emp_004").build()); employee4.put( @@ -449,7 +449,7 @@ public static void putAllProjectItemsToTable( final HashMap project1 = new HashMap<>(); project1.put( "partition_key", - AttributeValue.builder().s("project1").build() + AttributeValue.builder().s("project1-java").build() ); project1.put( "ProjectName", @@ -479,7 +479,7 @@ public static void putAllProjectItemsToTable( final HashMap project2 = new HashMap<>(); project2.put( "partition_key", - AttributeValue.builder().s("project2").build() + AttributeValue.builder().s("project2-java").build() ); project2.put( "ProjectName", @@ -506,7 +506,7 @@ public static void putAllProjectItemsToTable( final HashMap project3 = new HashMap<>(); project3.put( "partition_key", - AttributeValue.builder().s("project3").build() + AttributeValue.builder().s("project3-java").build() ); project3.put( "ProjectName", @@ -530,7 +530,7 @@ public static void putAllProjectItemsToTable( final HashMap project4 = new HashMap<>(); project4.put( "partition_key", - AttributeValue.builder().s("project4").build() + AttributeValue.builder().s("project4-java").build() ); project4.put( "ProjectName", @@ -577,7 +577,7 @@ public static void putAllReservationItemsToTable( final HashMap reservation1 = new HashMap<>(); reservation1.put( "partition_key", - AttributeValue.builder().s("reservation1").build() + AttributeValue.builder().s("reservation1-java").build() ); reservation1.put( "Location", @@ -629,7 +629,7 @@ public static void putAllReservationItemsToTable( final HashMap reservation2 = new HashMap<>(); reservation2.put( "partition_key", - AttributeValue.builder().s("reservation2").build() + AttributeValue.builder().s("reservation2-java").build() ); reservation2.put( "Location", @@ -665,7 +665,10 @@ public static void putAllTicketItemsToTable( DynamoDbClient ddb ) { final HashMap ticket1 = new HashMap<>(); - ticket1.put("partition_key", AttributeValue.builder().s("ticket1").build()); + ticket1.put( + "partition_key", + AttributeValue.builder().s("ticket1-java").build() + ); ticket1.put( "TicketNumber", AttributeValue.builder().s("ticket_001").build() @@ -694,7 +697,10 @@ public static void putAllTicketItemsToTable( ); final HashMap ticket2 = new HashMap<>(); - ticket2.put("partition_key", AttributeValue.builder().s("ticket2").build()); + ticket2.put( + "partition_key", + AttributeValue.builder().s("ticket2-java").build() + ); ticket2.put( "TicketNumber", AttributeValue.builder().s("ticket_001").build() @@ -723,7 +729,10 @@ public static void putAllTicketItemsToTable( ); final HashMap ticket3 = new HashMap<>(); - ticket3.put("partition_key", AttributeValue.builder().s("ticket3").build()); + ticket3.put( + "partition_key", + AttributeValue.builder().s("ticket3-java").build() + ); ticket3.put( "TicketNumber", AttributeValue.builder().s("ticket_002").build() @@ -752,7 +761,10 @@ public static void putAllTicketItemsToTable( ); final HashMap ticket4 = new HashMap<>(); - ticket4.put("partition_key", AttributeValue.builder().s("ticket4").build()); + ticket4.put( + "partition_key", + AttributeValue.builder().s("ticket4-java").build() + ); ticket4.put( "TicketNumber", AttributeValue.builder().s("ticket_002").build() @@ -789,7 +801,7 @@ public static void putAllTimecardItemsToTable( final HashMap timecard1 = new HashMap<>(); timecard1.put( "partition_key", - AttributeValue.builder().s("timecard1").build() + AttributeValue.builder().s("timecard1-java").build() ); timecard1.put( "ProjectName", @@ -813,7 +825,7 @@ public static void putAllTimecardItemsToTable( final HashMap timecard2 = new HashMap<>(); timecard2.put( "partition_key", - AttributeValue.builder().s("timecard2").build() + AttributeValue.builder().s("timecard2-java").build() ); timecard2.put( "ProjectName", @@ -837,7 +849,7 @@ public static void putAllTimecardItemsToTable( final HashMap timecard3 = new HashMap<>(); timecard3.put( "partition_key", - AttributeValue.builder().s("timecard3").build() + AttributeValue.builder().s("timecard3-java").build() ); timecard3.put( "ProjectName", @@ -861,7 +873,7 @@ public static void putAllTimecardItemsToTable( final HashMap timecard4 = new HashMap<>(); timecard4.put( "partition_key", - AttributeValue.builder().s("timecard4").build() + AttributeValue.builder().s("timecard4-java").build() ); timecard4.put( "ProjectName", diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/QueryRequests.java b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/QueryRequests.java index 353d7d3ddd..0a2c484e52 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/QueryRequests.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/complexexample/QueryRequests.java @@ -74,12 +74,19 @@ public static void runQuery1(String ddbTableName, DynamoDbClient ddb) { ); query1AttributeValues.put(":zero", AttributeValue.builder().s("0").build()); + query1AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + final QueryRequest query1Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-1") .keyConditionExpression("#pk1 = :e AND #sk1 BETWEEN :date1 AND :date2") - .filterExpression("#duration > :zero") + .filterExpression( + "#duration > :zero AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query1AttributeNames) .expressionAttributeValues(query1AttributeValues) .build(); @@ -93,7 +100,7 @@ public static void runQuery1(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery1 = false; for (Map item : query1Response.items()) { - if (item.get("partition_key").s().equals("meeting1")) { + if (item.get("partition_key").s().equals("meeting1-java")) { foundKnownValueItemQuery1 = true; assert item.get("Subject").s().equals("Scan Beacons"); assert item.get("Location").m().get("Floor").s().equals("12"); @@ -130,6 +137,11 @@ public static void runQuery2(String ddbTableName, DynamoDbClient ddb) { ); query2AttributeValues.put(":zero", AttributeValue.builder().s("0").build()); + query2AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query2Request = QueryRequest .builder() .tableName(ddbTableName) @@ -137,7 +149,9 @@ public static void runQuery2(String ddbTableName, DynamoDbClient ddb) { .keyConditionExpression( "#pk = :employee AND #sk BETWEEN :date1 AND :date2" ) - .filterExpression("#duration > :zero") + .filterExpression( + "#duration > :zero AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query2AttributeNames) .expressionAttributeValues(query2AttributeValues) .build(); @@ -151,7 +165,7 @@ public static void runQuery2(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery2 = false; for (Map item : query2Response.items()) { - if (item.get("partition_key").s().equals("meeting1")) { + if (item.get("partition_key").s().equals("meeting1-java")) { foundKnownValueItemQuery2 = true; assert item.get("Subject").s().equals("Scan Beacons"); assert item.get("Location").m().get("Floor").s().equals("12"); @@ -205,6 +219,11 @@ public static void runQuery3(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("MS-2022-07-08").build() ); + query3AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query3Request = QueryRequest .builder() .tableName(ddbTableName) @@ -213,7 +232,7 @@ public static void runQuery3(String ddbTableName, DynamoDbClient ddb) { "#pk = :buildingbeacon AND #sk BETWEEN :date1 AND :date2" ) .filterExpression( - "#building = :building AND #floor = :floor AND #room = :room" + "#building = :building AND #floor = :floor AND #room = :room AND contains(partition_key, :javasuffix)" ) .expressionAttributeNames(query3AttributeNames) .expressionAttributeValues(query3AttributeValues) @@ -228,7 +247,7 @@ public static void runQuery3(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery3 = false; for (Map item : query3Response.items()) { - if (item.get("partition_key").s().equals("reservation1")) { + if (item.get("partition_key").s().equals("reservation1-java")) { foundKnownValueItemQuery3 = true; assert item.get("Subject").s().equals("Scan beacons"); assert item.get("Location").m().get("Building").s().equals("SEA33"); @@ -258,11 +277,17 @@ public static void runQuery4(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("E-emp_001").build() ); + query4AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query4Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-1") .keyConditionExpression("#pk1 = :email AND #sk1 = :employee") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query4AttributeNames) .expressionAttributeValues(query4AttributeValues) .build(); @@ -276,7 +301,7 @@ public static void runQuery4(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery4 = false; for (Map item : query4Response.items()) { - if (item.get("partition_key").s().equals("employee1")) { + if (item.get("partition_key").s().equals("employee1-java")) { foundKnownValueItemQuery4 = true; assert item.get("EmployeeID").s().equals("emp_001"); assert item.get("Location").m().get("Desk").s().equals("3"); @@ -306,6 +331,11 @@ public static void runQuery5(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("MS-").build() ); + query5AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query5Request = QueryRequest .builder() .tableName(ddbTableName) @@ -313,6 +343,7 @@ public static void runQuery5(String ddbTableName, DynamoDbClient ddb) { .keyConditionExpression( "#pk1 = :email AND #sk1 BETWEEN :prefix AND :thirtydaysago" ) + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query5AttributeNames) .expressionAttributeValues(query5AttributeValues) .build(); @@ -326,7 +357,7 @@ public static void runQuery5(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery5 = false; for (Map item : query5Response.items()) { - if (item.get("partition_key").s().equals("meeting1")) { + if (item.get("partition_key").s().equals("meeting1-java")) { foundKnownValueItemQuery5 = true; assert item.get("Subject").s().equals("Scan Beacons"); assert item.get("Location").m().get("Floor").s().equals("12"); @@ -356,11 +387,17 @@ public static void runQuery6(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("MS-2023-03-20").build() ); + query6AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query6Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-1") .keyConditionExpression("#pk1 = :creatoremail AND #sk1 < :thirtydaysago") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query6AttributeNames) .expressionAttributeValues(query6AttributeValues) .build(); @@ -375,7 +412,7 @@ public static void runQuery6(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery6 = false; for (Map item : query6Response.items()) { - if (item.get("partition_key").s().equals("ticket1")) { + if (item.get("partition_key").s().equals("ticket1-java")) { foundKnownValueItemQuery6 = true; assert item.get("TicketNumber").s().equals("ticket_001"); } @@ -400,6 +437,11 @@ public static void runQuery7(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("MS-2023-03-20").build() ); + query7AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query7Request = QueryRequest .builder() .tableName(ddbTableName) @@ -407,6 +449,7 @@ public static void runQuery7(String ddbTableName, DynamoDbClient ddb) { .keyConditionExpression( "#pk1 = :organizeremail AND #sk1 < :thirtydaysago" ) + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query7AttributeNames) .expressionAttributeValues(query7AttributeValues) .build(); @@ -420,7 +463,7 @@ public static void runQuery7(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery7 = false; for (Map item : query7Response.items()) { - if (item.get("partition_key").s().equals("reservation1")) { + if (item.get("partition_key").s().equals("reservation1-java")) { foundKnownValueItemQuery7 = true; assert item.get("Subject").s().equals("Scan beacons"); assert item.get("Location").m().get("Floor").s().equals("12"); @@ -454,6 +497,11 @@ public static void runQuery8(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("TC-2023-03-20").build() ); + query8AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query8Request = QueryRequest .builder() .tableName(ddbTableName) @@ -461,6 +509,7 @@ public static void runQuery8(String ddbTableName, DynamoDbClient ddb) { .keyConditionExpression( "#pk1 = :email AND #sk1 BETWEEN :prefix AND :thirtydaysago" ) + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query8AttributeNames) .expressionAttributeValues(query8AttributeValues) .build(); @@ -474,7 +523,7 @@ public static void runQuery8(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery8 = false; for (Map item : query8Response.items()) { - if (item.get("partition_key").s().equals("timecard1")) { + if (item.get("partition_key").s().equals("timecard1-java")) { foundKnownValueItemQuery8 = true; assert item.get("ProjectName").s().equals("project_002"); } @@ -499,11 +548,17 @@ public static void runQuery9(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("E-").build() ); + query9AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query9Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-0") .keyConditionExpression("#pk = :employee AND begins_with(#sk, :prefix)") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query9AttributeNames) .expressionAttributeValues(query9AttributeValues) .build(); @@ -517,7 +572,7 @@ public static void runQuery9(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery9 = false; for (Map item : query9Response.items()) { - if (item.get("partition_key").s().equals("employee1")) { + if (item.get("partition_key").s().equals("employee1-java")) { foundKnownValueItemQuery9 = true; assert item.get("EmployeeID").s().equals("emp_001"); } @@ -543,11 +598,17 @@ public static void runQuery10(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("E-").build() ); + query10AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query10Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-1") .keyConditionExpression("#pk1 = :email AND begins_with(#sk1, :prefix)") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query10AttributeNames) .expressionAttributeValues(query10AttributeValues) .build(); @@ -561,7 +622,7 @@ public static void runQuery10(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery10 = false; for (Map item : query10Response.items()) { - if (item.get("partition_key").s().equals("employee1")) { + if (item.get("partition_key").s().equals("employee1-java")) { foundKnownValueItemQuery10 = true; assert item.get("EmployeeID").s().equals("emp_001"); } @@ -581,11 +642,17 @@ public static void runQuery11(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("T-ticket_001").build() ); + query11AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query11Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-0") .keyConditionExpression("#pk = :ticket") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query11AttributeNames) .expressionAttributeValues(query11AttributeValues) .build(); @@ -600,7 +667,7 @@ public static void runQuery11(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery11 = false; for (Map item : query11Response.items()) { - if (item.get("partition_key").s().equals("ticket1")) { + if (item.get("partition_key").s().equals("ticket1-java")) { foundKnownValueItemQuery11 = true; assert item.get("TicketNumber").s().equals("ticket_001"); } @@ -626,12 +693,19 @@ public static void runQuery12(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("T-ticket_001").build() ); + query12AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query12Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-1") .keyConditionExpression("#pk1 = :email") - .filterExpression("#pk = :ticket") + .filterExpression( + "#pk = :ticket AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query12AttributeNames) .expressionAttributeValues(query12AttributeValues) .build(); @@ -645,7 +719,7 @@ public static void runQuery12(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery12 = false; for (Map item : query12Response.items()) { - if (item.get("partition_key").s().equals("ticket1")) { + if (item.get("partition_key").s().equals("ticket1-java")) { foundKnownValueItemQuery12 = true; assert item.get("TicketNumber").s().equals("ticket_001"); } @@ -671,12 +745,19 @@ public static void runQuery13(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("T-ticket_001").build() ); + query13AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query13Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-2") .keyConditionExpression("#pk2 = :assigneeemail") - .filterExpression("#pk = :ticket") + .filterExpression( + "#pk = :ticket AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query13AttributeNames) .expressionAttributeValues(query13AttributeValues) .build(); @@ -690,7 +771,7 @@ public static void runQuery13(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery13 = false; for (Map item : query13Response.items()) { - if (item.get("partition_key").s().equals("ticket1")) { + if (item.get("partition_key").s().equals("ticket1-java")) { foundKnownValueItemQuery13 = true; assert item.get("Subject").s().equals("Bad bug"); } @@ -715,11 +796,17 @@ public static void runQuery14(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("B-44~F-12~D-3").build() ); + query14AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query14Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-3") .keyConditionExpression("#pk3 = :city AND begins_with(#sk3, :location)") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query14AttributeNames) .expressionAttributeValues(query14AttributeValues) .build(); @@ -745,7 +832,7 @@ public static void runQuery14(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery14 = false; for (Map item : query14Response.items()) { - if (item.get("partition_key").s().equals("employee1")) { + if (item.get("partition_key").s().equals("employee1-java")) { foundKnownValueItemQuery14 = true; assert item.get("EmployeeID").s().equals("emp_001"); assert item.get("Location").m().get("Desk").s().equals("3"); @@ -768,11 +855,17 @@ public static void runQuery15(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("ME-zorro@gmail.com").build() ); + query15AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query15Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-2") .keyConditionExpression("#pk2 = :manageremail") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query15AttributeNames) .expressionAttributeValues(query15AttributeValues) .build(); @@ -787,7 +880,7 @@ public static void runQuery15(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery15 = false; for (Map item : query15Response.items()) { - if (item.get("partition_key").s().equals("employee1")) { + if (item.get("partition_key").s().equals("employee1-java")) { foundKnownValueItemQuery15 = true; assert item.get("EmployeeID").s().equals("emp_001"); assert item.get("Location").m().get("Desk").s().equals("3"); @@ -808,11 +901,17 @@ public static void runQuery16(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("AE-able@gmail.com").build() ); + query16AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query16Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-2") .keyConditionExpression("#pk2 = :assigneeemail") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query16AttributeNames) .expressionAttributeValues(query16AttributeValues) .build(); @@ -827,7 +926,7 @@ public static void runQuery16(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery16 = false; for (Map item : query16Response.items()) { - if (item.get("partition_key").s().equals("ticket1")) { + if (item.get("partition_key").s().equals("ticket1-java")) { foundKnownValueItemQuery16 = true; assert item.get("TicketNumber").s().equals("ticket_001"); } @@ -856,11 +955,17 @@ public static void runQuery17(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("M-2022-10-07T09:30:00").build() ); + query17AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query17Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-3") .keyConditionExpression("#pk3 = :severity AND #sk3 > :yesterday") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query17AttributeNames) .expressionAttributeValues(query17AttributeValues) .build(); @@ -875,7 +980,7 @@ public static void runQuery17(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery17 = false; for (Map item : query17Response.items()) { - if (item.get("partition_key").s().equals("ticket1")) { + if (item.get("partition_key").s().equals("ticket1-java")) { foundKnownValueItemQuery17 = true; assert item.get("TicketNumber").s().equals("ticket_001"); } @@ -906,12 +1011,19 @@ public static void runQuery18(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("2025-01-01").build() ); + query18AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query18Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-1") .keyConditionExpression("#pk1 = :status AND #sk1 > :startdate") - .filterExpression("#target < :target") + .filterExpression( + "#target < :target AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query18AttributeNames) .expressionAttributeValues(query18AttributeValues) .build(); @@ -925,7 +1037,7 @@ public static void runQuery18(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery18 = false; for (Map item : query18Response.items()) { - if (item.get("partition_key").s().equals("project1")) { + if (item.get("partition_key").s().equals("project1-java")) { foundKnownValueItemQuery18 = true; assert item.get("ProjectName").s().equals("project_001"); } @@ -946,11 +1058,17 @@ public static void runQuery19(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("P-project_001").build() ); + query19AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query19Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-0") .keyConditionExpression("#pk = :projectname AND #sk = :projectname") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query19AttributeNames) .expressionAttributeValues(query19AttributeValues) .build(); @@ -964,7 +1082,7 @@ public static void runQuery19(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery19 = false; for (Map item : query19Response.items()) { - if (item.get("partition_key").s().equals("project1")) { + if (item.get("partition_key").s().equals("project1-java")) { foundKnownValueItemQuery19 = true; assert item.get("ProjectName").s().equals("project_001"); } @@ -993,6 +1111,11 @@ public static void runQuery20(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("TC-2023-01-01").build() ); + query20AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query20Request = QueryRequest .builder() .tableName(ddbTableName) @@ -1000,6 +1123,7 @@ public static void runQuery20(String ddbTableName, DynamoDbClient ddb) { .keyConditionExpression( "#pk = :projectname AND #sk BETWEEN :date1 AND :date2" ) + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query20AttributeNames) .expressionAttributeValues(query20AttributeValues) .build(); @@ -1014,7 +1138,7 @@ public static void runQuery20(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery20 = false; for (Map item : query20Response.items()) { - if (item.get("partition_key").s().equals("timecard1")) { + if (item.get("partition_key").s().equals("timecard1-java")) { foundKnownValueItemQuery20 = true; assert item.get("ProjectName").s().equals("project_002"); } @@ -1040,12 +1164,19 @@ public static void runQuery21(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("SDE3").build() ); + query21AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query21Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-0") .keyConditionExpression("#pk = :projectname") - .filterExpression("#role = :role") + .filterExpression( + "#role = :role AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query21AttributeNames) .expressionAttributeValues(query21AttributeValues) .build(); @@ -1059,7 +1190,7 @@ public static void runQuery21(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery21 = false; for (Map item : query21Response.items()) { - if (item.get("partition_key").s().equals("timecard1")) { + if (item.get("partition_key").s().equals("timecard1-java")) { foundKnownValueItemQuery21 = true; assert item.get("ProjectName").s().equals("project_002"); } @@ -1079,11 +1210,17 @@ public static void runQuery22(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("B-SEA33").build() ); + query22AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query22Request = QueryRequest .builder() .tableName(ddbTableName) .indexName("GSI-0") .keyConditionExpression("#pk = :building") + .filterExpression("contains(partition_key, :javasuffix)") .expressionAttributeNames(query22AttributeNames) .expressionAttributeValues(query22AttributeValues) .build(); @@ -1098,7 +1235,7 @@ public static void runQuery22(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery22 = false; for (Map item : query22Response.items()) { - if (item.get("partition_key").s().equals("reservation1")) { + if (item.get("partition_key").s().equals("reservation1-java")) { foundKnownValueItemQuery22 = true; assert item.get("Subject").s().equals("Scan beacons"); } @@ -1133,6 +1270,11 @@ public static void runQuery23(String ddbTableName, DynamoDbClient ddb) { AttributeValue.builder().s("0").build() ); + query23AttributeValues.put( + ":javasuffix", + AttributeValue.builder().s("-java").build() + ); + QueryRequest query23Request = QueryRequest .builder() .tableName(ddbTableName) @@ -1140,7 +1282,9 @@ public static void runQuery23(String ddbTableName, DynamoDbClient ddb) { .keyConditionExpression( "#pk = :building AND #sk BETWEEN :date1 AND :date2" ) - .filterExpression("#duration > :zero") + .filterExpression( + "#duration > :zero AND contains(partition_key, :javasuffix)" + ) .expressionAttributeNames(query23AttributeNames) .expressionAttributeValues(query23AttributeValues) .build(); @@ -1155,7 +1299,7 @@ public static void runQuery23(String ddbTableName, DynamoDbClient ddb) { // Known value test: Assert some properties on one of the items boolean foundKnownValueItemQuery23 = false; for (Map item : query23Response.items()) { - if (item.get("partition_key").s().equals("reservation1")) { + if (item.get("partition_key").s().equals("reservation1-java")) { foundKnownValueItemQuery23 = true; assert item.get("Subject").s().equals("Scan beacons"); } From f4c837408ecb80093f04bee903247bfa04bf7961 Mon Sep 17 00:00:00 2001 From: texastony <5892063+texastony@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:20:14 -0700 Subject: [PATCH 09/10] release: aws-db-esdk v1.2.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump version 1.2.2 → 1.2.3 - Regenerate implementation_from_dafny.rs --- DynamoDbEncryption/runtimes/rust/Cargo.toml | 2 +- .../runtimes/rust/test_examples/Cargo.toml | 4 +- releases/rust/db_esdk/Cargo.toml | 4 +- releases/rust/db_esdk/examples/main.rs | 20 +- .../rust/db_esdk/examples/migration/mod.rs | 4 + .../migration/plaintext_to_awsdbe/README.md | 51 ++++ .../plaintext_to_awsdbe/awsdbe/common.rs | 90 +++++++ .../awsdbe/migration_step_1.rs | 237 +++++++++++++++++ .../awsdbe/migration_step_2.rs | 239 +++++++++++++++++ .../awsdbe/migration_step_3.rs | 240 ++++++++++++++++++ .../plaintext_to_awsdbe/awsdbe/mod.rs | 7 + .../plaintext_to_awsdbe/migration_utils.rs | 82 ++++++ .../migration/plaintext_to_awsdbe/mod.rs | 6 + .../plaintext/migration_step_0.rs | 199 +++++++++++++++ .../plaintext_to_awsdbe/plaintext/mod.rs | 4 + .../complexexample/put_requests.rs | 48 ++-- .../complexexample/query_requests.rs | 165 +++++++----- releases/rust/db_esdk/examples/test_utils.rs | 4 + .../db_esdk/src/implementation_from_dafny.rs | 2 +- 19 files changed, 1309 insertions(+), 99 deletions(-) create mode 100644 releases/rust/db_esdk/examples/migration/mod.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/README.md create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/common.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_1.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_2.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_3.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/mod.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/migration_utils.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/mod.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/migration_step_0.rs create mode 100644 releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/mod.rs diff --git a/DynamoDbEncryption/runtimes/rust/Cargo.toml b/DynamoDbEncryption/runtimes/rust/Cargo.toml index e55ec17540..ac02b7150e 100644 --- a/DynamoDbEncryption/runtimes/rust/Cargo.toml +++ b/DynamoDbEncryption/runtimes/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-db-esdk" -version = "1.2.2" +version = "1.2.3" edition = "2021" keywords = ["cryptography", "security", "dynamodb", "encryption", "client-side"] license = "ISC AND (Apache-2.0 OR ISC)" diff --git a/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml b/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml index 9a766105c6..8801db0e33 100644 --- a/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml +++ b/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml @@ -7,9 +7,9 @@ rust-version = "1.81.0" [dependencies] aws-config = "1.5.15" +aws-db-esdk = "1.2.3" aws-lc-rs = "1.12.2" -aws-lc-sys = "0.25.0" -aws-sdk-dynamodb = "1.62.0" +aws-lc-sys = "0.38.0" aws-sdk-kms = "1.57.0" aws-smithy-runtime-api = {version = "1.7.3", features = ["client"] } aws-smithy-types = "1.2.12" diff --git a/releases/rust/db_esdk/Cargo.toml b/releases/rust/db_esdk/Cargo.toml index d471d0e750..f31084ab0c 100644 --- a/releases/rust/db_esdk/Cargo.toml +++ b/releases/rust/db_esdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-db-esdk" -version = "1.2.2" +version = "1.2.3" edition = "2021" keywords = ["cryptography", "security", "dynamodb", "encryption", "client-side"] license = "ISC AND (Apache-2.0 OR ISC)" @@ -17,7 +17,7 @@ readme = "README.md" [dependencies] aws-config = "1.8.12" aws-lc-rs = {version = "1.15.4"} -aws-lc-sys = { version = "0.37", optional = true } +aws-lc-sys = { version = "0.38", optional = true } aws-lc-fips-sys = { version = "0.13", optional = true } aws-sdk-dynamodb = "1.103.0" aws-sdk-kms = "1.98.0" diff --git a/releases/rust/db_esdk/examples/main.rs b/releases/rust/db_esdk/examples/main.rs index cd3d5b9b57..db5e7491a2 100644 --- a/releases/rust/db_esdk/examples/main.rs +++ b/releases/rust/db_esdk/examples/main.rs @@ -60,23 +60,19 @@ pub async fn main() -> Result<(), BoxError2> { keyring::mrk_discovery_multi_keyring::put_item_get_item().await?; clientsupplier::client_supplier_example::put_item_get_item().await?; - let key_id = create_keystore_key::keystore_create_key().await?; - let key_id2 = create_keystore_key::keystore_create_key().await?; - // Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood - // our test fails due to eventual consistency issues. - println!("Key Store Keys created. Waiting 5 seconds for consistency."); - std::thread::sleep(std::time::Duration::from_secs(5)); + let key_id = test_utils::TEST_BRANCH_KEY_ID; + let key_id2 = test_utils::TEST_ALTERNATE_BRANCH_KEY_ID; - keyring::hierarchical_keyring::put_item_get_item(&key_id, &key_id2).await?; + keyring::hierarchical_keyring::put_item_get_item(key_id, key_id2).await?; - searchableencryption::basic_searchable_encryption::put_and_query_with_beacon(&key_id).await?; - searchableencryption::beacon_styles_searchable_encryption::put_and_query_with_beacon(&key_id) + searchableencryption::basic_searchable_encryption::put_and_query_with_beacon(key_id).await?; + searchableencryption::beacon_styles_searchable_encryption::put_and_query_with_beacon(key_id) .await?; - searchableencryption::compound_beacon_searchable_encryption::put_and_query_with_beacon(&key_id) + searchableencryption::compound_beacon_searchable_encryption::put_and_query_with_beacon(key_id) .await?; - searchableencryption::virtual_beacon_searchable_encryption::put_and_query_with_beacon(&key_id) + searchableencryption::virtual_beacon_searchable_encryption::put_and_query_with_beacon(key_id) .await?; - searchableencryption::complexexample::complex_searchable_encryption::run_example(&key_id) + searchableencryption::complexexample::complex_searchable_encryption::run_example(key_id) .await?; // ScanError will have to wait until we have a reasonable error message strategy diff --git a/releases/rust/db_esdk/examples/migration/mod.rs b/releases/rust/db_esdk/examples/migration/mod.rs new file mode 100644 index 0000000000..7fa4b852c7 --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/mod.rs @@ -0,0 +1,4 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod plaintext_to_awsdbe; diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/README.md b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/README.md new file mode 100644 index 0000000000..31170c101e --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/README.md @@ -0,0 +1,51 @@ +# Plaintext DynamoDB Table to AWS Database Encryption SDK Encrypted Table Migration + +This projects demonstrates the steps necessary +to migrate to the AWS Database Encryption SDK for DynamoDb +from a plaintext database. + +[Step 0](plaintext/step0.go) demonstrates the starting state for your system. + +## Step 1 + +In Step 1, you update your system to do the following: + +- continue to read plaintext items +- continue to write plaintext items +- prepare to read encrypted items + +When you deploy changes in Step 1, +you should not expect any behavior change in your system, +and your dataset still consists of plaintext data. + +You must ensure that the changes in Step 1 make it to all your readers before you proceed to Step 2. + +## Step 2 + +In Step 2, you update your system to do the following: + +- continue to read plaintext items +- start writing encrypted items +- continue to read encrypted items + +When you deploy changes in Step 2, +you are introducing encrypted items to your system, +and must make sure that all your readers are updated with the changes from Step 1. + +Before you move onto the next step, you will need to encrypt all plaintext items in your dataset. +Once you have completed this step, +while new items are being encrypted using the new format and will be authenticated on read, +your system will still accept reading plaintext, unauthenticated items. +In order to complete migration to a system where you always authenticate your items, +you should prioritize moving on to Step 3. + +## Step 3 + +Once all old items are encrypted, +update your system to do the following: + +- continue to write encrypted items +- continue to read encrypted items +- do not accept reading plaintext items + +Once you have deployed these changes to your system, you have completed migration. diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/common.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/common.rs new file mode 100644 index 0000000000..471213e188 --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/common.rs @@ -0,0 +1,90 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig; +use aws_db_esdk::dynamodb::types::PlaintextOverride; +use aws_db_esdk::material_providers::client; +use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig; +use aws_db_esdk::types::dynamo_db_tables_encryption_config::DynamoDbTablesEncryptionConfig; +use aws_db_esdk::CryptoAction; +use std::collections::HashMap; + +pub async fn create_table_configs( + kms_key_id: &str, + ddb_table_name: &str, + plaintext_override: PlaintextOverride, +) -> Result> { + // Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + // For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + // We will use the `CreateMrkMultiKeyring` method to create this keyring, + // as it will correctly handle both single region and Multi-Region KMS Keys. + let provider_config = MaterialProvidersConfig::builder().build()?; + let mat_prov = client::Client::from_conf(provider_config)?; + let kms_keyring = mat_prov + .create_aws_kms_mrk_multi_keyring() + .generator(kms_key_id) + .send() + .await?; + + // Configure which attributes are encrypted and/or signed when writing new items. + // For each attribute that may exist on the items we plan to write to our DynamoDbTable, + // we must explicitly configure how they should be treated during item encryption: + // - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + // - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + // - DO_NOTHING: The attribute is not encrypted and not included in the signature + let partition_key_name = "partition_key"; + let sort_key_name = "sort_key"; + let attribute_actions_on_encrypt = HashMap::from([ + (partition_key_name.to_string(), CryptoAction::SignOnly), + (sort_key_name.to_string(), CryptoAction::SignOnly), + ("attribute1".to_string(), CryptoAction::EncryptAndSign), + ("attribute2".to_string(), CryptoAction::SignOnly), + ("attribute3".to_string(), CryptoAction::DoNothing), + ]); + + // Configure which attributes we expect to be excluded in the signature + // when reading items. There are two options for configuring this: + // + // - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + // When defining your DynamoDb schema and deciding on attribute names, + // choose a distinguishing prefix (such as ":") for all attributes that + // you do not want to include in the signature. + // This has two main benefits: + // - It is easier to reason about the security and authenticity of data within your item + // when all unauthenticated data is easily distinguishable by their attribute name. + // - If you need to add new unauthenticated attributes in the future, + // you can easily make the corresponding update to your `attributeActionsOnEncrypt` + // and immediately start writing to that new attribute, without + // any other configuration update needed. + // Once you configure this field, it is not safe to update it. + // + // - Configure `allowedUnsignedAttributes`: You may also explicitly list + // a set of attributes that should be considered unauthenticated when encountered + // on read. Be careful if you use this configuration. Do not remove an attribute + // name from this configuration, even if you are no longer writing with that attribute, + // as old items may still include this attribute, and our configuration needs to know + // to continue to exclude this attribute from the signature scope. + // If you add new attribute names to this field, you must first deploy the update to this + // field to all readers in your host fleet before deploying the update to start writing + // with that new attribute. + // + // For this example, we will explicitly list the attributes that are not signed. + let unsigned_attributes = vec!["attribute3".to_string()]; + + // Create the DynamoDb Encryption configuration for the table we will be writing to. + let table_config = DynamoDbTableEncryptionConfig::builder() + .logical_table_name(ddb_table_name) + .partition_key_name(partition_key_name) + .sort_key_name(sort_key_name) + .attribute_actions_on_encrypt(attribute_actions_on_encrypt) + .keyring(kms_keyring) + .allowed_unsigned_attributes(unsigned_attributes) + .plaintext_override(plaintext_override) + .build()?; + + let table_configs = DynamoDbTablesEncryptionConfig::builder() + .table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)])) + .build()?; + + Ok(table_configs) +} diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_1.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_1.rs new file mode 100644 index 0000000000..aa7f668768 --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_1.rs @@ -0,0 +1,237 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::migration::plaintext_to_awsdbe::awsdbe::common::create_table_configs; +use crate::migration::plaintext_to_awsdbe::migration_utils::{ + verify_returned_item, DO_NOTHING_VALUE, ENCRYPTED_AND_SIGNED_VALUE, SIGN_ONLY_VALUE, +}; +use aws_db_esdk::dynamodb::types::PlaintextOverride; +use aws_db_esdk::intercept::DbEsdkInterceptor; +use aws_sdk_dynamodb::types::AttributeValue; +use std::collections::HashMap; + +/* +Migration Step 1: This is the first step in the migration process from +plaintext to encrypted DynamoDB using the AWS Database Encryption SDK. + +In this example, we configure a DynamoDB Encryption client to do the following: +1. Write items only in plaintext +2. Read items in plaintext or, if the item is encrypted, decrypt with our encryption configuration + +While this step configures your client to be ready to start reading encrypted items, +we do not yet expect to be reading any encrypted items, +as our client still writes plaintext items. +Before you move on to step 2, ensure that these changes have successfully been deployed +to all of your readers. + +Running this example requires access to the DDB Table whose name +is provided in the function parameter. +This table must be configured with the following +primary key configuration: + - Partition key is named "partition_key" with type (S) + - Sort key is named "sort_key" with type (N) +*/ +pub async fn migration_step_1_example( + kms_key_id: &str, + ddb_table_name: &str, + partition_key_value: &str, + sort_key_write_value: &str, + sort_key_read_value: &str, +) -> Result> { + // 1. Create table configurations + // In this step of migration we will use PlaintextOverride::ForcePlaintextWriteAllowPlaintextRead + // which means: + // - Write: Items are forced to be written as plaintext. + // Items may not be written as encrypted items. + // - Read: Items are allowed to be read as plaintext. + // Items are allowed to be read as encrypted items. + let table_configs = create_table_configs( + kms_key_id, + ddb_table_name, + PlaintextOverride::ForcePlaintextWriteAllowPlaintextRead, + ) + .await?; + + // 2. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs + let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; + let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config) + .interceptor(DbEsdkInterceptor::new(table_configs)?) + .build(); + let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config); + + // 3. Put an item into our table using the above client. + // This item will be stored in plaintext due to our PlaintextOverride configuration. + let partition_key_name = "partition_key"; + let sort_key_name = "sort_key"; + let encrypted_and_signed_value = ENCRYPTED_AND_SIGNED_VALUE; + let sign_only_value = SIGN_ONLY_VALUE; + let do_nothing_value = DO_NOTHING_VALUE; + let item = HashMap::from([ + ( + partition_key_name.to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + sort_key_name.to_string(), + AttributeValue::N(sort_key_write_value.to_string()), + ), + ( + "attribute1".to_string(), + AttributeValue::S(encrypted_and_signed_value.to_string()), + ), + ( + "attribute2".to_string(), + AttributeValue::S(sign_only_value.to_string()), + ), + ( + "attribute3".to_string(), + AttributeValue::S(do_nothing_value.to_string()), + ), + ]); + + ddb.put_item() + .table_name(ddb_table_name) + .set_item(Some(item)) + .send() + .await?; + + // 4. Get an item back from the table using the same client. + // If this is an item written in plaintext (i.e. any item written + // during Step 0 or 1), then the item will still be in plaintext. + // If this is an item that was encrypted client-side (i.e. any item written + // during Step 2 or after), then the item will be decrypted client-side + // and surfaced as a plaintext item. + let key = HashMap::from([ + ( + partition_key_name.to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + sort_key_name.to_string(), + AttributeValue::N(sort_key_read_value.to_string()), + ), + ]); + + let response = ddb + .get_item() + .table_name(ddb_table_name) + .set_key(Some(key)) + // In this example we configure a strongly consistent read + // because we perform a read immediately after a write (for demonstrative purposes). + // By default, reads are only eventually consistent. + .consistent_read(true) + .send() + .await?; + + // 5. Verify we get the expected item back + if let Some(item) = response.item { + let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?; + if success { + println!("MigrationStep1 completed successfully"); + } + Ok(success) + } else { + Err("No item found".into()) + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_migration_step_1() -> Result<(), Box> { + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_2::migration_step_2_example; + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_3::migration_step_3_example; + use crate::migration::plaintext_to_awsdbe::plaintext::migration_step_0::migration_step_0_example; + use crate::test_utils; + use uuid::Uuid; + + let kms_key_id = test_utils::TEST_KMS_KEY_ID; + let table_name = test_utils::TEST_DDB_TABLE_NAME; + let partition_key = Uuid::new_v4().to_string(); + let sort_keys = ["0", "1", "2", "3"]; + + // Successfully executes step 1 + let success = migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[1], + ) + .await?; + assert!(success, "MigrationStep1 should complete successfully"); + + // Given: Step 0 has succeeded + let success = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[0]).await?; + assert!(success, "MigrationStep0 should complete successfully"); + + // When: Execute Step 1 with sortReadValue=0, Then: Success (i.e. can read plaintext values from Step 0) + let success = migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[0], + ) + .await?; + assert!( + success, + "MigrationStep1 should be able to read items written by Step 0" + ); + + // Given: Step 2 has succeeded + let success = migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[2], + ) + .await?; + assert!(success, "MigrationStep2 should complete successfully"); + + // When: Execute Step 1 with sortReadValue=2, Then: Success (i.e. can read encrypted values from Step 2) + let success = migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[2], + ) + .await?; + assert!( + success, + "MigrationStep1 should be able to read items written by Step 2" + ); + + // Given: Step 3 has succeeded + let success = migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[3], + ) + .await?; + assert!(success, "MigrationStep3 should complete successfully"); + + // When: Execute Step 1 with sortReadValue=3, Then: Success (i.e. can read encrypted values from Step 3) + let success = migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[3], + ) + .await?; + assert!( + success, + "MigrationStep1 should be able to read items written by Step 3" + ); + + // Cleanup + for sort_key in &sort_keys { + test_utils::cleanup_items(table_name, &partition_key, sort_key).await?; + } + + Ok(()) +} diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_2.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_2.rs new file mode 100644 index 0000000000..7766474bce --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_2.rs @@ -0,0 +1,239 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::migration::plaintext_to_awsdbe::awsdbe::common::create_table_configs; +use crate::migration::plaintext_to_awsdbe::migration_utils::{ + verify_returned_item, DO_NOTHING_VALUE, ENCRYPTED_AND_SIGNED_VALUE, SIGN_ONLY_VALUE, +}; +use aws_db_esdk::dynamodb::types::PlaintextOverride; +use aws_db_esdk::intercept::DbEsdkInterceptor; +use aws_sdk_dynamodb::types::AttributeValue; +use std::collections::HashMap; + +/* +Migration Step 2: This is the second step in the migration process from +plaintext to encrypted DynamoDB using the AWS Database Encryption SDK. + +In this example, we configure a DynamoDB Encryption client to do the following: +1. Write items with encryption (no longer writing plaintext) +2. Read both plaintext items and encrypted items + +Once you deploy this change to your system, you will have a dataset +containing both encrypted and plaintext items. +Because the changes in Step 1 have been deployed to all readers, +we can be sure that our entire system is ready to read this new data. + +Before you move onto the next step, you will need to encrypt all plaintext items in your dataset. +How you will want to do this depends on your system. + +Running this example requires access to the DDB Table whose name +is provided in the function parameter. +This table must be configured with the following +primary key configuration: + - Partition key is named "partition_key" with type (S) + - Sort key is named "sort_key" with type (N) +*/ +pub async fn migration_step_2_example( + kms_key_id: &str, + ddb_table_name: &str, + partition_key_value: &str, + sort_key_write_value: &str, + sort_key_read_value: &str, +) -> Result> { + // 1. Create table configurations + // In this step of migration we will use PlaintextOverride::ForbidPlaintextWriteAllowPlaintextRead + // which means: + // - Write: Items are forbidden to be written as plaintext. + // Items will be written as encrypted items. + // - Read: Items are allowed to be read as plaintext. + // Items are allowed to be read as encrypted items. + let table_configs = create_table_configs( + kms_key_id, + ddb_table_name, + PlaintextOverride::ForbidPlaintextWriteAllowPlaintextRead, + ) + .await?; + + // 2. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs + let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; + let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config) + .interceptor(DbEsdkInterceptor::new(table_configs)?) + .build(); + let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config); + + // 3. Put an item into our table using the above client. + // This item will be encrypted due to our PlaintextOverride configuration. + let partition_key_name = "partition_key"; + let sort_key_name = "sort_key"; + let encrypted_and_signed_value = ENCRYPTED_AND_SIGNED_VALUE; + let sign_only_value = SIGN_ONLY_VALUE; + let do_nothing_value = DO_NOTHING_VALUE; + let item = HashMap::from([ + ( + partition_key_name.to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + sort_key_name.to_string(), + AttributeValue::N(sort_key_write_value.to_string()), + ), + ( + "attribute1".to_string(), + AttributeValue::S(encrypted_and_signed_value.to_string()), + ), + ( + "attribute2".to_string(), + AttributeValue::S(sign_only_value.to_string()), + ), + ( + "attribute3".to_string(), + AttributeValue::S(do_nothing_value.to_string()), + ), + ]); + + ddb.put_item() + .table_name(ddb_table_name) + .set_item(Some(item)) + .send() + .await?; + + // 4. Get an item back from the table using the same client. + // If this is an item written in plaintext (i.e. any item written + // during Step 0 or 1), then the item will still be in plaintext. + // If this is an item that was encrypted client-side (i.e. any item written + // during Step 2 or after), then the item will be decrypted client-side + // and surfaced as a plaintext item. + let key = HashMap::from([ + ( + partition_key_name.to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + sort_key_name.to_string(), + AttributeValue::N(sort_key_read_value.to_string()), + ), + ]); + + let response = ddb + .get_item() + .table_name(ddb_table_name) + .set_key(Some(key)) + // In this example we configure a strongly consistent read + // because we perform a read immediately after a write (for demonstrative purposes). + // By default, reads are only eventually consistent. + .consistent_read(true) + .send() + .await?; + + // 5. Verify we get the expected item back + if let Some(item) = response.item { + let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?; + if success { + println!("MigrationStep2 completed successfully"); + } + Ok(success) + } else { + Err("No item found".into()) + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_migration_step_2() -> Result<(), Box> { + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_1::migration_step_1_example; + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_3::migration_step_3_example; + use crate::migration::plaintext_to_awsdbe::plaintext::migration_step_0::migration_step_0_example; + use crate::test_utils; + use uuid::Uuid; + + let kms_key_id = test_utils::TEST_KMS_KEY_ID; + let table_name = test_utils::TEST_DDB_TABLE_NAME; + let partition_key = Uuid::new_v4().to_string(); + let sort_keys = ["0", "1", "2", "3"]; + + // Successfully executes step 2 + let success = migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[2], + ) + .await?; + assert!(success, "MigrationStep2 should complete successfully"); + + // Given: Step 0 has succeeded + let success = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[0]).await?; + assert!(success, "MigrationStep0 should complete successfully"); + + // When: Execute Step 2 with sortReadValue=0, Then: Success (i.e. can read plaintext values from Step 0) + let success = migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[0], + ) + .await?; + assert!( + success, + "MigrationStep2 should be able to read items written by Step 0" + ); + + // Given: Step 1 has succeeded + let success = migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[1], + ) + .await?; + assert!(success, "MigrationStep1 should complete successfully"); + + // When: Execute Step 2 with sortReadValue=1, Then: Success (i.e. can read plaintext values from Step 1) + let success = migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[1], + ) + .await?; + assert!( + success, + "MigrationStep2 should be able to read items written by Step 1" + ); + + // Given: Step 3 has succeeded + let success = migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[3], + ) + .await?; + assert!(success, "MigrationStep3 should complete successfully"); + + // When: Execute Step 2 with sortReadValue=3, Then: Success (i.e. can read encrypted values from Step 3) + let success = migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[3], + ) + .await?; + assert!( + success, + "MigrationStep2 should be able to read items written by Step 3" + ); + + // Cleanup + for sort_key in &sort_keys { + test_utils::cleanup_items(table_name, &partition_key, sort_key).await?; + } + + Ok(()) +} diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_3.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_3.rs new file mode 100644 index 0000000000..9ab74d91ce --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/migration_step_3.rs @@ -0,0 +1,240 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::migration::plaintext_to_awsdbe::awsdbe::common::create_table_configs; +use crate::migration::plaintext_to_awsdbe::migration_utils::{ + verify_returned_item, DO_NOTHING_VALUE, ENCRYPTED_AND_SIGNED_VALUE, SIGN_ONLY_VALUE, +}; +use aws_db_esdk::dynamodb::types::PlaintextOverride; +use aws_db_esdk::intercept::DbEsdkInterceptor; +use aws_sdk_dynamodb::types::AttributeValue; +use std::collections::HashMap; + +/* +Migration Step 3: This is the final step in the migration process from +plaintext to encrypted DynamoDB using the AWS Database Encryption SDK. + +In this example, we configure a DynamoDB Encryption client to do the following: +1. Write items with encryption (no longer writing plaintext) +2. Read only encrypted items (no longer reading plaintext) + +Once you complete Step 3, all items being read by your system are encrypted. + +Before you move onto this step, you will need to encrypt all plaintext items in your dataset. +How you will want to do this depends on your system. + +Running this example requires access to the DDB Table whose name +is provided in the function parameter. +This table must be configured with the following +primary key configuration: + - Partition key is named "partition_key" with type (S) + - Sort key is named "sort_key" with type (N) +*/ +pub async fn migration_step_3_example( + kms_key_id: &str, + ddb_table_name: &str, + partition_key_value: &str, + sort_key_write_value: &str, + sort_key_read_value: &str, +) -> Result> { + // 1. Create table configurations + // In this step of migration we will use PlaintextOverride::ForbidPlaintextWriteForbidPlaintextRead + // which means: + // - Write: Items are forbidden to be written as plaintext. + // Items will be written as encrypted items. + // - Read: Items are forbidden to be read as plaintext. + // Items will be read as encrypted items. + // Note: If you do not specify a PlaintextOverride, it defaults to + // ForbidPlaintextWriteForbidPlaintextRead, which is the desired + // behavior for a client interacting with a fully encrypted database. + let table_configs = create_table_configs( + kms_key_id, + ddb_table_name, + PlaintextOverride::ForbidPlaintextWriteForbidPlaintextRead, + ) + .await?; + + // 2. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs + let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; + let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config) + .interceptor(DbEsdkInterceptor::new(table_configs)?) + .build(); + let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config); + + // 3. Put an item into our table using the above client. + // This item will be encrypted due to our PlaintextOverride configuration. + let partition_key_name = "partition_key"; + let sort_key_name = "sort_key"; + let encrypted_and_signed_value = ENCRYPTED_AND_SIGNED_VALUE; + let sign_only_value = SIGN_ONLY_VALUE; + let do_nothing_value = DO_NOTHING_VALUE; + let item = HashMap::from([ + ( + partition_key_name.to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + sort_key_name.to_string(), + AttributeValue::N(sort_key_write_value.to_string()), + ), + ( + "attribute1".to_string(), + AttributeValue::S(encrypted_and_signed_value.to_string()), + ), + ( + "attribute2".to_string(), + AttributeValue::S(sign_only_value.to_string()), + ), + ( + "attribute3".to_string(), + AttributeValue::S(do_nothing_value.to_string()), + ), + ]); + + ddb.put_item() + .table_name(ddb_table_name) + .set_item(Some(item)) + .send() + .await?; + + // 4. Get an item back from the table using the same client. + // If this is an item written in plaintext (i.e. any item written + // during Step 0 or 1), then the read will fail, as we have + // configured our client to forbid reading plaintext items. + // If this is an item that was encrypted client-side (i.e. any item written + // during Step 2 or after), then the item will be decrypted client-side + // and surfaced as a plaintext item. + let key = HashMap::from([ + ( + partition_key_name.to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + sort_key_name.to_string(), + AttributeValue::N(sort_key_read_value.to_string()), + ), + ]); + + let response = ddb + .get_item() + .table_name(ddb_table_name) + .set_key(Some(key)) + // In this example we configure a strongly consistent read + // because we perform a read immediately after a write (for demonstrative purposes). + // By default, reads are only eventually consistent. + .consistent_read(true) + .send() + .await?; + + // Verify we get the expected item back + if let Some(item) = response.item { + let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?; + if success { + println!("MigrationStep3 completed successfully"); + } + Ok(success) + } else { + Err("No item found".into()) + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_migration_step_3() -> Result<(), Box> { + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_1::migration_step_1_example; + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_2::migration_step_2_example; + use crate::migration::plaintext_to_awsdbe::plaintext::migration_step_0::migration_step_0_example; + use crate::test_utils; + use uuid::Uuid; + + let kms_key_id = test_utils::TEST_KMS_KEY_ID; + let table_name = test_utils::TEST_DDB_TABLE_NAME; + let partition_key = Uuid::new_v4().to_string(); + let sort_keys = ["0", "1", "2", "3"]; + + // Successfully executes step 3 + let success = migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[3], + ) + .await?; + assert!(success, "MigrationStep3 should complete successfully"); + + // Given: Step 0 has succeeded + let success = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[0]).await?; + assert!(success, "MigrationStep0 should complete successfully"); + + // When: Execute Step 3 with sortReadValue=0, Then: should error out when reading plaintext items from Step 0 + let result = migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[0], + ) + .await; + assert!( + result.is_err(), + "MigrationStep3 should fail when reading plaintext items" + ); + + // Given: Step 1 has succeeded + let success = migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[1], + ) + .await?; + assert!(success, "MigrationStep1 should complete successfully"); + + // When: Execute Step 3 with sortReadValue=1, Then: should error out when reading plaintext items from Step 1 + let result = migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[1], + ) + .await; + assert!( + result.is_err(), + "MigrationStep3 should fail when reading plaintext items" + ); + + // Given: Step 2 has succeeded + let success = migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[2], + ) + .await?; + assert!(success, "MigrationStep2 should complete successfully"); + + // When: Execute Step 3 with sortReadValue=2, Then: Success (i.e. can read encrypted values from Step 2) + let success = migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[2], + ) + .await?; + assert!( + success, + "MigrationStep3 should be able to read items written by Step 2" + ); + + // Cleanup + for sort_key in &sort_keys { + test_utils::cleanup_items(table_name, &partition_key, sort_key).await?; + } + + Ok(()) +} diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/mod.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/mod.rs new file mode 100644 index 0000000000..6a3380ee20 --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/awsdbe/mod.rs @@ -0,0 +1,7 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod common; +pub mod migration_step_1; +pub mod migration_step_2; +pub mod migration_step_3; diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/migration_utils.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/migration_utils.rs new file mode 100644 index 0000000000..3f7e40ae55 --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/migration_utils.rs @@ -0,0 +1,82 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use aws_sdk_dynamodb::types::AttributeValue; +use std::collections::HashMap; + +/* +Utility module for the PlaintextToAWSDBE migration examples. +This module contains shared functionality used by all migration steps. +*/ + +// Common attribute values used across all migration steps +pub const ENCRYPTED_AND_SIGNED_VALUE: &str = "this will be encrypted and signed"; +pub const SIGN_ONLY_VALUE: &str = "this will never be encrypted, but it will be signed"; +pub const DO_NOTHING_VALUE: &str = "this will never be encrypted nor signed"; + +// Verify that a returned item matches the expected values +pub fn verify_returned_item( + item: &HashMap, + partition_key_value: &str, + sort_key_value: &str, +) -> Result> { + if let Some(AttributeValue::S(pk)) = item.get("partition_key") { + if pk != partition_key_value { + return Err(format!( + "partition_key mismatch: expected {}, got {}", + partition_key_value, pk + ) + .into()); + } + } else { + return Err("partition_key not found or not a string".into()); + } + + if let Some(AttributeValue::N(sk)) = item.get("sort_key") { + if sk != sort_key_value { + return Err( + format!("sort_key mismatch: expected {}, got {}", sort_key_value, sk).into(), + ); + } + } else { + return Err("sort_key not found or not a number".into()); + } + + if let Some(AttributeValue::S(attr1)) = item.get("attribute1") { + if attr1 != ENCRYPTED_AND_SIGNED_VALUE { + return Err(format!( + "attribute1 mismatch: expected {}, got {}", + ENCRYPTED_AND_SIGNED_VALUE, attr1 + ) + .into()); + } + } else { + return Err("attribute1 not found or not a string".into()); + } + + if let Some(AttributeValue::S(attr2)) = item.get("attribute2") { + if attr2 != SIGN_ONLY_VALUE { + return Err(format!( + "attribute2 mismatch: expected {}, got {}", + SIGN_ONLY_VALUE, attr2 + ) + .into()); + } + } else { + return Err("attribute2 not found or not a string".into()); + } + + if let Some(AttributeValue::S(attr3)) = item.get("attribute3") { + if attr3 != DO_NOTHING_VALUE { + return Err(format!( + "attribute3 mismatch: expected {}, got {}", + DO_NOTHING_VALUE, attr3 + ) + .into()); + } + } else { + return Err("attribute3 not found or not a string".into()); + } + + Ok(true) +} diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/mod.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/mod.rs new file mode 100644 index 0000000000..8714f145ad --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/mod.rs @@ -0,0 +1,6 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod awsdbe; +pub mod migration_utils; +pub mod plaintext; diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/migration_step_0.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/migration_step_0.rs new file mode 100644 index 0000000000..5b75054ebf --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/migration_step_0.rs @@ -0,0 +1,199 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::migration::plaintext_to_awsdbe::migration_utils::{ + verify_returned_item, DO_NOTHING_VALUE, ENCRYPTED_AND_SIGNED_VALUE, SIGN_ONLY_VALUE, +}; +use aws_sdk_dynamodb::types::AttributeValue; +use std::collections::HashMap; + +/* +Migration Step 0: This is the pre-migration step for the +plaintext-to-encrypted database migration, and is the starting +state for our migration from a plaintext database to a +client-side encrypted database encrypted using the +AWS Database Encryption SDK for DynamoDb. + +In this example, we configure a DynamoDbClient to +write a plaintext record to a table and read that record. +This emulates the starting state of a plaintext-to-encrypted +database migration; i.e. a plaintext database you can +read and write to with the DynamoDbClient. + +Running this example requires access to the DDB Table whose name +is provided in the function parameter. +This table must be configured with the following +primary key configuration: + - Partition key is named "partition_key" with type (S) + - Sort key is named "sort_key" with type (N) +*/ +pub async fn migration_step_0_example( + ddb_table_name: &str, + partition_key_value: &str, + sort_key_write_value: &str, + sort_key_read_value: &str, +) -> Result> { + // 1. Create a standard DynamoDB client + let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; + let ddb = aws_sdk_dynamodb::Client::new(&sdk_config); + + // 2. Put an example item into DynamoDB table + // This item will be stored in plaintext. + let encrypted_and_signed_value = ENCRYPTED_AND_SIGNED_VALUE; + let sign_only_value = SIGN_ONLY_VALUE; + let do_nothing_value = DO_NOTHING_VALUE; + let item = HashMap::from([ + ( + "partition_key".to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + "sort_key".to_string(), + AttributeValue::N(sort_key_write_value.to_string()), + ), + ( + "attribute1".to_string(), + AttributeValue::S(encrypted_and_signed_value.to_string()), + ), + ( + "attribute2".to_string(), + AttributeValue::S(sign_only_value.to_string()), + ), + ( + "attribute3".to_string(), + AttributeValue::S(do_nothing_value.to_string()), + ), + ]); + + ddb.put_item() + .table_name(ddb_table_name) + .set_item(Some(item)) + .send() + .await?; + + // 3. Get an item back from the table as it was written. + // If this is an item written in plaintext (i.e. any item written + // during Step 0 or 1), then the item will still be in plaintext + // and will be able to be processed. + // If this is an item that was encrypted client-side (i.e. any item written + // during Step 2 or after), then the item will still be encrypted client-side + // and will be unable to be processed in your code. To decrypt and process + // client-side encrypted items, you will need to configure encrypted reads on + // your dynamodb client (this is configured from Step 1 onwards). + let key = HashMap::from([ + ( + "partition_key".to_string(), + AttributeValue::S(partition_key_value.to_string()), + ), + ( + "sort_key".to_string(), + AttributeValue::N(sort_key_read_value.to_string()), + ), + ]); + + let response = ddb + .get_item() + .table_name(ddb_table_name) + .set_key(Some(key)) + .send() + .await?; + + // 4. Verify we get the expected item back + if let Some(item) = response.item { + let success = verify_returned_item(&item, partition_key_value, sort_key_read_value)?; + if success { + println!("MigrationStep0 completed successfully"); + } + Ok(success) + } else { + Err("No item found".into()) + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_migration_step_0() -> Result<(), Box> { + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_1::migration_step_1_example; + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_2::migration_step_2_example; + use crate::migration::plaintext_to_awsdbe::awsdbe::migration_step_3::migration_step_3_example; + use crate::test_utils; + use uuid::Uuid; + + let kms_key_id = test_utils::TEST_KMS_KEY_ID; + let table_name = test_utils::TEST_DDB_TABLE_NAME; + let partition_key = Uuid::new_v4().to_string(); + let sort_keys = ["0", "1", "2", "3"]; + + // Successfully executes step 0 + let success = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[0]).await?; + assert!(success, "MigrationStep0 should complete successfully"); + + // Given: Step 1 has succeeded + migration_step_1_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[1], + sort_keys[1], + ) + .await?; + + // When: Execute Step 0 with sortReadValue=1, Then: Success (i.e. can read plaintext values) + let success = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[1]).await?; + assert!( + success, + "MigrationStep0 should be able to read items written by Step 1" + ); + + // Given: Step 2 has succeeded + migration_step_2_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[2], + sort_keys[2], + ) + .await?; + + // When: Execute Step 0 with sortReadValue=2, Then: should error out when reading encrypted items. + let result = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[2]).await; + assert!( + result.is_err(), + "MigrationStep0 should fail when reading encrypted items" + ); + assert!(result + .unwrap_err() + .to_string() + .contains("attribute1 not found or not a string")); + + // Given: Step 3 has succeeded + migration_step_3_example( + kms_key_id, + table_name, + &partition_key, + sort_keys[3], + sort_keys[3], + ) + .await?; + + // When: Execute Step 0 with sortReadValue=3, Then: should error out + let result = + migration_step_0_example(table_name, &partition_key, sort_keys[0], sort_keys[3]).await; + assert!( + result.is_err(), + "MigrationStep0 should fail when reading encrypted items" + ); + assert!(result + .unwrap_err() + .to_string() + .contains("attribute1 not found or not a string")); + + // Cleanup + for sort_key in &sort_keys { + test_utils::cleanup_items(table_name, &partition_key, sort_key).await?; + } + + Ok(()) +} diff --git a/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/mod.rs b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/mod.rs new file mode 100644 index 0000000000..c1d709e7ba --- /dev/null +++ b/releases/rust/db_esdk/examples/migration/plaintext_to_awsdbe/plaintext/mod.rs @@ -0,0 +1,4 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod migration_step_0; diff --git a/releases/rust/db_esdk/examples/searchableencryption/complexexample/put_requests.rs b/releases/rust/db_esdk/examples/searchableencryption/complexexample/put_requests.rs index 23eaa71139..8752538c55 100644 --- a/releases/rust/db_esdk/examples/searchableencryption/complexexample/put_requests.rs +++ b/releases/rust/db_esdk/examples/searchableencryption/complexexample/put_requests.rs @@ -62,7 +62,7 @@ async fn put_all_meeting_items( let meeting1_attendee_list = vec![ss("able@gmail.com"), ss("zorro@gmail.com")]; let meeting1_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting1 = HashMap::from([ - entry("partition_key", "meeting1"), + entry("partition_key", "meeting1-rust"), entry("EmployeeID", "emp_001"), entry("EmployeeEmail", "able@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -79,7 +79,7 @@ async fn put_all_meeting_items( let meeting2_attendee_list = vec![ss("barney@gmail.com"), ss("zorro@gmail.com")]; let meeting2_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting2 = HashMap::from([ - entry("partition_key", "meeting2"), + entry("partition_key", "meeting2-rust"), entry("EmployeeID", "emp_002"), entry("EmployeeEmail", "barney@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -96,7 +96,7 @@ async fn put_all_meeting_items( let meeting3_attendee_list = vec![ss("charlie@gmail.com"), ss("zorro@gmail.com")]; let meeting3_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting3 = HashMap::from([ - entry("partition_key", "meeting3"), + entry("partition_key", "meeting3-rust"), entry("EmployeeID", "emp_003"), entry("EmployeeEmail", "charlie@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -113,7 +113,7 @@ async fn put_all_meeting_items( let meeting4_attendee_list = vec![ss("david@gmail.com"), ss("zorro@gmail.com")]; let meeting4_location = HashMap::from([entry("Floor", "12"), entry("Room", "403")]); let meeting4 = HashMap::from([ - entry("partition_key", "meeting4"), + entry("partition_key", "meeting4-rust"), entry("EmployeeID", "emp_004"), entry("EmployeeEmail", "david@gmail.com"), entry("MeetingStart", "2022-07-04T13:00"), @@ -130,7 +130,7 @@ async fn put_all_meeting_items( let meeting5_attendee_list = vec![ss("barney@gmail.com"), ss("zorro@gmail.com")]; let meeting5_location = HashMap::from([entry("Floor", "12"), entry("Room", "407")]); let meeting5 = HashMap::from([ - entry("partition_key", "meeting5"), + entry("partition_key", "meeting5-rust"), entry("EmployeeID", "emp_002"), entry("EmployeeEmail", "barney@gmail.com"), entry("MeetingStart", "2022-07-04T14:00"), @@ -147,7 +147,7 @@ async fn put_all_meeting_items( let meeting6_attendee_list = vec![ss("charlie@gmail.com"), ss("zorro@gmail.com")]; let meeting6_location = HashMap::from([entry("Floor", "12"), entry("Room", "407")]); let meeting6 = HashMap::from([ - entry("partition_key", "meeting6"), + entry("partition_key", "meeting6-rust"), entry("EmployeeID", "emp_003"), entry("EmployeeEmail", "charlie@gmail.com"), entry("MeetingStart", "2022-07-04T14:00"), @@ -175,7 +175,7 @@ async fn put_all_employee_items( entry("City", "Seattle"), ]); let employee1 = HashMap::from([ - entry("partition_key", "employee1"), + entry("partition_key", "employee1-rust"), entry("EmployeeID", "emp_001"), entry("EmployeeEmail", "able@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -195,7 +195,7 @@ async fn put_all_employee_items( entry("City", "Seattle"), ]); let employee2 = HashMap::from([ - entry("partition_key", "employee2"), + entry("partition_key", "employee2-rust"), entry("EmployeeID", "emp_002"), entry("EmployeeEmail", "barney@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -215,7 +215,7 @@ async fn put_all_employee_items( entry("City", "Seattle"), ]); let employee3 = HashMap::from([ - entry("partition_key", "employee3"), + entry("partition_key", "employee3-rust"), entry("EmployeeID", "emp_003"), entry("EmployeeEmail", "charlie@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -235,7 +235,7 @@ async fn put_all_employee_items( entry("City", "NYC"), ]); let employee4 = HashMap::from([ - entry("partition_key", "employee4"), + entry("partition_key", "employee4-rust"), entry("EmployeeID", "emp_004"), entry("EmployeeEmail", "david@gmail.com"), entry("ManagerEmail", "zorro@gmail.com"), @@ -256,7 +256,7 @@ async fn put_all_project_items( ddb: &mut aws_sdk_dynamodb::Client, ) -> Result<(), crate::BoxError> { let project1 = HashMap::from([ - entry("partition_key", "project1"), + entry("partition_key", "project1-rust"), entry("ProjectName", "project_001"), entry("ProjectStatus", "Pending"), entry("ProjectStart", "2022-11-01"), @@ -266,7 +266,7 @@ async fn put_all_project_items( put_item(ddb_table_name, ddb, project1).await?; let project2 = HashMap::from([ - entry("partition_key", "project2"), + entry("partition_key", "project2-rust"), entry("ProjectName", "project_002"), entry("ProjectStatus", "Active"), entry("ProjectStart", "2022-07-04"), @@ -276,7 +276,7 @@ async fn put_all_project_items( put_item(ddb_table_name, ddb, project2).await?; let project3 = HashMap::from([ - entry("partition_key", "project3"), + entry("partition_key", "project3-rust"), entry("ProjectName", "project_003"), entry("ProjectStatus", "Active"), entry("ProjectStart", "2022-08-05"), @@ -286,7 +286,7 @@ async fn put_all_project_items( put_item(ddb_table_name, ddb, project3).await?; let project4 = HashMap::from([ - entry("partition_key", "project4"), + entry("partition_key", "project4-rust"), entry("ProjectName", "project_004"), entry("ProjectStatus", "Done"), entry("ProjectStart", "2020-03-03"), @@ -309,7 +309,7 @@ async fn put_all_reservation_items( entry("Room", "403"), ]); let reservation1 = HashMap::from([ - entry("partition_key", "reservation1"), + entry("partition_key", "reservation1-rust"), entry("MeetingStart", "2022-07-04T13:00"), entry("OrganizerEmail", "able@gmail.com"), entry("Duration", "30"), @@ -332,7 +332,7 @@ async fn put_all_reservation_items( entry("Room", "407"), ]); let reservation2 = HashMap::from([ - entry("partition_key", "reservation2"), + entry("partition_key", "reservation2-rust"), entry("MeetingStart", "2022-07-04T14:00"), entry("OrganizerEmail", "barney@gmail.com"), entry("Duration", "30"), @@ -356,7 +356,7 @@ async fn put_all_ticket_items( ddb: &mut aws_sdk_dynamodb::Client, ) -> Result<(), crate::BoxError> { let ticket1 = HashMap::from([ - entry("partition_key", "ticket1"), + entry("partition_key", "ticket1-rust"), entry("TicketNumber", "ticket_001"), entry("TicketModTime", "2022-10-07T14:32:25"), entry("CreatorEmail", "zorro@gmail.com"), @@ -368,7 +368,7 @@ async fn put_all_ticket_items( put_item(ddb_table_name, ddb, ticket1).await?; let ticket2 = HashMap::from([ - entry("partition_key", "ticket2"), + entry("partition_key", "ticket2-rust"), entry("TicketNumber", "ticket_001"), entry("TicketModTime", "2022-10-07T14:32:25"), entry("CreatorEmail", "able@gmail.com"), @@ -380,7 +380,7 @@ async fn put_all_ticket_items( put_item(ddb_table_name, ddb, ticket2).await?; let ticket3 = HashMap::from([ - entry("partition_key", "ticket3"), + entry("partition_key", "ticket3-rust"), entry("TicketNumber", "ticket_002"), entry("TicketModTime", "2022-10-06T14:32:25"), entry("CreatorEmail", "zorro@gmail.com"), @@ -392,7 +392,7 @@ async fn put_all_ticket_items( put_item(ddb_table_name, ddb, ticket3).await?; let ticket4 = HashMap::from([ - entry("partition_key", "ticket4"), + entry("partition_key", "ticket4-rust"), entry("TicketNumber", "ticket_002"), entry("TicketModTime", "2022-10-08T14:32:25"), entry("CreatorEmail", "charlie@gmail.com"), @@ -411,7 +411,7 @@ async fn put_all_timecard_items( ddb: &mut aws_sdk_dynamodb::Client, ) -> Result<(), crate::BoxError> { let timecard1 = HashMap::from([ - entry("partition_key", "timecard1"), + entry("partition_key", "timecard1-rust"), entry("ProjectName", "project_002"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "able@gmail.com"), @@ -421,7 +421,7 @@ async fn put_all_timecard_items( put_item(ddb_table_name, ddb, timecard1).await?; let timecard2 = HashMap::from([ - entry("partition_key", "timecard2"), + entry("partition_key", "timecard2-rust"), entry("ProjectName", "project_002"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "barney@gmail.com"), @@ -431,7 +431,7 @@ async fn put_all_timecard_items( put_item(ddb_table_name, ddb, timecard2).await?; let timecard3 = HashMap::from([ - entry("partition_key", "timecard3"), + entry("partition_key", "timecard3-rust"), entry("ProjectName", "project_003"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "charlie@gmail.com"), @@ -441,7 +441,7 @@ async fn put_all_timecard_items( put_item(ddb_table_name, ddb, timecard3).await?; let timecard4 = HashMap::from([ - entry("partition_key", "timecard4"), + entry("partition_key", "timecard4-rust"), entry("ProjectName", "project_003"), entry("TimeCardStart", "2022-09-12"), entry("EmployeeEmail", "barney@gmail.com"), diff --git a/releases/rust/db_esdk/examples/searchableencryption/complexexample/query_requests.rs b/releases/rust/db_esdk/examples/searchableencryption/complexexample/query_requests.rs index f64ae0e335..03b5cf2da8 100644 --- a/releases/rust/db_esdk/examples/searchableencryption/complexexample/query_requests.rs +++ b/releases/rust/db_esdk/examples/searchableencryption/complexexample/query_requests.rs @@ -74,6 +74,7 @@ async fn run_query1( entry(":date1", "MS-2022-07-02"), entry(":date2", "MS-2022-07-08"), entry(":zero", "0"), + entry(":rustsuffix", "-rust"), ]); let query1_response = ddb @@ -83,7 +84,7 @@ async fn run_query1( .set_expression_attribute_names(Some(query1_names)) .set_expression_attribute_values(Some(query1_values)) .key_condition_expression("PK1 = :e AND SK1 BETWEEN :date1 AND :date2") - .filter_expression("#duration > :zero") + .filter_expression("#duration > :zero AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -92,7 +93,7 @@ async fn run_query1( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("meeting1")); + assert_eq!(items[0]["partition_key"], ss("meeting1-rust")); assert_eq!(items[0]["Subject"], ss("Scan Beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -119,6 +120,7 @@ async fn run_query2( entry(":date1", "MS-2022-07-02"), entry(":date2", "MS-2022-07-08"), entry(":zero", "0"), + entry(":rustsuffix", "-rust"), ]); let query2_response = ddb @@ -128,7 +130,7 @@ async fn run_query2( .set_expression_attribute_names(Some(query2_names)) .set_expression_attribute_values(Some(query2_values)) .key_condition_expression("PK = :employee AND SK BETWEEN :date1 AND :date2") - .filter_expression("#duration > :zero") + .filter_expression("#duration > :zero AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -137,7 +139,7 @@ async fn run_query2( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("meeting1")); + assert_eq!(items[0]["partition_key"], ss("meeting1-rust")); assert_eq!(items[0]["Subject"], ss("Scan Beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -166,6 +168,7 @@ async fn run_query3( entry(":room", "403"), entry(":date1", "MS-2022-07-02"), entry(":date2", "MS-2022-07-08"), + entry(":rustsuffix", "-rust"), ]); let query3_response = ddb @@ -174,7 +177,7 @@ async fn run_query3( .index_name("GSI-0") .set_expression_attribute_values(Some(query3_values)) .key_condition_expression("PK = :buildingbeacon AND SK BETWEEN :date1 AND :date2") - .filter_expression("Building = :building AND Floor = :floor AND Room = :room") + .filter_expression("Building = :building AND Floor = :floor AND Room = :room AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -183,7 +186,7 @@ async fn run_query3( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("reservation1")); + assert_eq!(items[0]["partition_key"], ss("reservation1-rust")); assert_eq!(items[0]["Subject"], ss("Scan beacons")); assert_eq!( items[0]["Location"].as_m().unwrap()["Building"], @@ -206,6 +209,7 @@ async fn run_query4( let query4_values = HashMap::from([ entry(":email", "EE-able@gmail.com"), entry(":employee", "E-emp_001"), + entry(":rustsuffix", "-rust"), ]); let query4_response = ddb @@ -214,6 +218,7 @@ async fn run_query4( .index_name("GSI-1") .set_expression_attribute_values(Some(query4_values)) .key_condition_expression("PK1 = :email AND SK1 = :employee") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -222,7 +227,7 @@ async fn run_query4( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); assert_eq!(items[0]["Location"].as_m().unwrap()["Desk"], ss("3")); Ok(()) @@ -239,6 +244,7 @@ async fn run_query5( entry(":email", "EE-able@gmail.com"), entry(":thirtydaysago", "MS-2023-03-20"), entry(":prefix", "MS-"), + entry(":rustsuffix", "-rust"), ]); let query5_response = ddb @@ -247,6 +253,7 @@ async fn run_query5( .index_name("GSI-1") .set_expression_attribute_values(Some(query5_values)) .key_condition_expression("PK1 = :email AND SK1 BETWEEN :prefix AND :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -255,7 +262,7 @@ async fn run_query5( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("meeting1")); + assert_eq!(items[0]["partition_key"], ss("meeting1-rust")); assert_eq!(items[0]["Subject"], ss("Scan Beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -275,6 +282,7 @@ async fn run_query6( let query6_values = HashMap::from([ entry(":creatoremail", "CE-zorro@gmail.com"), entry(":thirtydaysago", "MS-2023-03-20"), + entry(":rustsuffix", "-rust"), ]); let query6_response = ddb @@ -283,6 +291,7 @@ async fn run_query6( .index_name("GSI-1") .set_expression_attribute_values(Some(query6_values)) .key_condition_expression("PK1 = :creatoremail AND SK1 < :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -292,10 +301,10 @@ async fn run_query6( // Expected to be `ticket1` and `ticket3` assert!( - ((items[0]["partition_key"] == ss("ticket1")) - && (items[1]["partition_key"] == ss("ticket3"))) - || ((items[0]["partition_key"] == ss("ticket3")) - && (items[1]["partition_key"] == ss("ticket1"))) + ((items[0]["partition_key"] == ss("ticket1-rust")) + && (items[1]["partition_key"] == ss("ticket3-rust"))) + || ((items[0]["partition_key"] == ss("ticket3-rust")) + && (items[1]["partition_key"] == ss("ticket1-rust"))) ); Ok(()) } @@ -310,6 +319,7 @@ async fn run_query7( let query7_values = HashMap::from([ entry(":organizeremail", "OE-able@gmail.com"), entry(":thirtydaysago", "MS-2023-03-20"), + entry(":rustsuffix", "-rust"), ]); let query7_response = ddb @@ -318,6 +328,7 @@ async fn run_query7( .index_name("GSI-1") .set_expression_attribute_values(Some(query7_values)) .key_condition_expression("PK1 = :organizeremail AND SK1 < :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -326,7 +337,7 @@ async fn run_query7( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("reservation1")); + assert_eq!(items[0]["partition_key"], ss("reservation1-rust")); assert_eq!(items[0]["Subject"], ss("Scan beacons")); assert_eq!(items[0]["Location"].as_m().unwrap()["Floor"], ss("12")); assert!(items[0]["Attendees"] @@ -347,6 +358,7 @@ async fn run_query8( entry(":email", "EE-able@gmail.com"), entry(":prefix", "TC-"), entry(":thirtydaysago", "TC-2023-03-20"), + entry(":rustsuffix", "-rust"), ]); let query8_response = ddb @@ -355,6 +367,7 @@ async fn run_query8( .index_name("GSI-1") .set_expression_attribute_values(Some(query8_values)) .key_condition_expression("PK1 = :email AND SK1 BETWEEN :prefix AND :thirtydaysago") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -363,7 +376,7 @@ async fn run_query8( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("timecard1")); + assert_eq!(items[0]["partition_key"], ss("timecard1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_002")); Ok(()) } @@ -375,7 +388,11 @@ async fn run_query9( // Query 9: Get employee info by employee ID // Key condition: PK1=employeeID SK starts with "E-" - let query9_values = HashMap::from([entry(":employee", "E-emp_001"), entry(":prefix", "E-")]); + let query9_values = HashMap::from([ + entry(":employee", "E-emp_001"), + entry(":prefix", "E-"), + entry(":rustsuffix", "-rust"), + ]); let query9_response = ddb .query() @@ -383,6 +400,7 @@ async fn run_query9( .index_name("GSI-0") .set_expression_attribute_values(Some(query9_values)) .key_condition_expression("PK = :employee AND begins_with(SK, :prefix)") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -391,7 +409,7 @@ async fn run_query9( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); Ok(()) } @@ -404,8 +422,11 @@ async fn run_query10( // Key condition: PK1=email // Filter condition: SK starts with "E-" - let query10_values = - HashMap::from([entry(":email", "EE-able@gmail.com"), entry(":prefix", "E-")]); + let query10_values = HashMap::from([ + entry(":email", "EE-able@gmail.com"), + entry(":prefix", "E-"), + entry(":rustsuffix", "-rust"), + ]); let query10_response = ddb .query() @@ -413,6 +434,7 @@ async fn run_query10( .index_name("GSI-1") .set_expression_attribute_values(Some(query10_values)) .key_condition_expression("PK1 = :email AND begins_with(SK1, :prefix)") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -421,7 +443,7 @@ async fn run_query10( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); Ok(()) } @@ -433,7 +455,10 @@ async fn run_query11( // Query 11: Get ticket history by ticket number // Key condition: PK=TicketNumber - let query11_values = HashMap::from([entry(":ticket", "T-ticket_001")]); + let query11_values = HashMap::from([ + entry(":ticket", "T-ticket_001"), + entry(":rustsuffix", "-rust"), + ]); let query11_response = ddb .query() @@ -441,6 +466,7 @@ async fn run_query11( .index_name("GSI-0") .set_expression_attribute_values(Some(query11_values)) .key_condition_expression("PK = :ticket") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -450,10 +476,10 @@ async fn run_query11( // Expected to be `ticket1` and `ticket3` assert!( - ((items[0]["partition_key"] == ss("ticket1")) - && (items[1]["partition_key"] == ss("ticket2"))) - || ((items[0]["partition_key"] == ss("ticket2")) - && (items[1]["partition_key"] == ss("ticket1"))) + ((items[0]["partition_key"] == ss("ticket1-rust")) + && (items[1]["partition_key"] == ss("ticket2-rust"))) + || ((items[0]["partition_key"] == ss("ticket2-rust")) + && (items[1]["partition_key"] == ss("ticket1-rust"))) ); Ok(()) } @@ -469,6 +495,7 @@ async fn run_query12( let query12_values = HashMap::from([ entry(":email", "CE-zorro@gmail.com"), entry(":ticket", "T-ticket_001"), + entry(":rustsuffix", "-rust"), ]); let query12_response = ddb @@ -477,7 +504,7 @@ async fn run_query12( .index_name("GSI-1") .set_expression_attribute_values(Some(query12_values)) .key_condition_expression("PK1 = :email") - .filter_expression("PK = :ticket") + .filter_expression("PK = :ticket AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -486,7 +513,7 @@ async fn run_query12( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("ticket1")); + assert_eq!(items[0]["partition_key"], ss("ticket1-rust")); assert_eq!(items[0]["TicketNumber"], ss("ticket_001")); Ok(()) } @@ -501,6 +528,7 @@ async fn run_query13( let query13_values = HashMap::from([ entry(":assigneeemail", "AE-able@gmail.com"), entry(":ticket", "T-ticket_001"), + entry(":rustsuffix", "-rust"), ]); let query13_response = ddb @@ -509,7 +537,7 @@ async fn run_query13( .index_name("GSI-2") .set_expression_attribute_values(Some(query13_values)) .key_condition_expression("PK2 = :assigneeemail") - .filter_expression("PK = :ticket") + .filter_expression("PK = :ticket AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -518,7 +546,7 @@ async fn run_query13( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("ticket1")); + assert_eq!(items[0]["partition_key"], ss("ticket1-rust")); assert_eq!(items[0]["Subject"], ss("Bad bug")); Ok(()) } @@ -533,6 +561,7 @@ async fn run_query14( let query14_values = HashMap::from([ entry(":city", "C-Seattle"), entry(":location", "B-44~F-12~D-3"), + entry(":rustsuffix", "-rust"), ]); let query14_response = ddb @@ -541,6 +570,7 @@ async fn run_query14( .index_name("GSI-3") .set_expression_attribute_values(Some(query14_values)) .key_condition_expression("PK3 = :city AND begins_with(SK3, :location)") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -549,7 +579,7 @@ async fn run_query14( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("employee1")); + assert_eq!(items[0]["partition_key"], ss("employee1-rust")); assert_eq!(items[0]["EmployeeID"], ss("emp_001")); assert_eq!(items[0]["Location"].as_m().unwrap()["Desk"], ss("3")); Ok(()) @@ -562,7 +592,10 @@ async fn run_query15( // Query 15: Get employees by manager email // Key condition: PK2 = ManagerEmail - let query15_values = HashMap::from([entry(":manageremail", "ME-zorro@gmail.com")]); + let query15_values = HashMap::from([ + entry(":manageremail", "ME-zorro@gmail.com"), + entry(":rustsuffix", "-rust"), + ]); let query15_response = ddb .query() @@ -570,6 +603,7 @@ async fn run_query15( .index_name("GSI-2") .set_expression_attribute_values(Some(query15_values)) .key_condition_expression("PK2 = :manageremail") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -580,7 +614,7 @@ async fn run_query15( let mut found_known_value_item_query15 = false; for item in &items { - if item["partition_key"] == ss("employee1") { + if item["partition_key"] == ss("employee1-rust") { found_known_value_item_query15 = true; assert_eq!(item["EmployeeID"], ss("emp_001")); assert_eq!(item["Location"].as_m().unwrap()["Desk"], ss("3")); @@ -598,7 +632,10 @@ async fn run_query16( // Query 16: Get assigned tickets by assignee email // Key condition: PK2 = AssigneeEmail - let query16_values = HashMap::from([entry(":assigneeemail", "AE-able@gmail.com")]); + let query16_values = HashMap::from([ + entry(":assigneeemail", "AE-able@gmail.com"), + entry(":rustsuffix", "-rust"), + ]); let query16_response = ddb .query() @@ -606,6 +643,7 @@ async fn run_query16( .index_name("GSI-2") .set_expression_attribute_values(Some(query16_values)) .key_condition_expression("PK2 = :assigneeemail") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -615,10 +653,10 @@ async fn run_query16( // Expected to be `ticket1` and `ticket4` assert!( - ((items[0]["partition_key"] == ss("ticket1")) - && (items[1]["partition_key"] == ss("ticket4"))) - || ((items[0]["partition_key"] == ss("ticket4")) - && (items[1]["partition_key"] == ss("ticket1"))) + ((items[0]["partition_key"] == ss("ticket1-rust")) + && (items[1]["partition_key"] == ss("ticket4-rust"))) + || ((items[0]["partition_key"] == ss("ticket4-rust")) + && (items[1]["partition_key"] == ss("ticket1-rust"))) ); Ok(()) } @@ -637,6 +675,7 @@ async fn run_query17( let query17_values = HashMap::from([ entry(":severity", "S-3"), entry(":yesterday", "M-2022-10-07T09:30:00"), + entry(":rustsuffix", "-rust"), ]); let query17_response = ddb @@ -645,6 +684,7 @@ async fn run_query17( .index_name("GSI-3") .set_expression_attribute_values(Some(query17_values)) .key_condition_expression("PK3 = :severity AND SK3 > :yesterday") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -656,7 +696,7 @@ async fn run_query17( let mut found_known_value_item_query17 = false; for item in &items { - if item["partition_key"] == ss("ticket1") { + if item["partition_key"] == ss("ticket1-rust") { found_known_value_item_query17 = true; assert_eq!(item["TicketNumber"], ss("ticket_001")); } @@ -678,6 +718,7 @@ async fn run_query18( entry(":status", "PSts-Pending"), entry(":startdate", "PS-2022-01-01"), entry(":target", "2025-01-01"), + entry(":rustsuffix", "-rust"), ]); let query18_response = ddb @@ -686,7 +727,7 @@ async fn run_query18( .index_name("GSI-1") .set_expression_attribute_values(Some(query18_values)) .key_condition_expression("PK1 = :status AND SK1 > :startdate") - .filter_expression("ProjectTarget < :target") + .filter_expression("ProjectTarget < :target AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -695,7 +736,7 @@ async fn run_query18( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("project1")); + assert_eq!(items[0]["partition_key"], ss("project1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_001")); Ok(()) } @@ -707,7 +748,10 @@ async fn run_query19( // Query 19: Get projects by name // Key condition: PK = ProjectName, SK = ProjectName - let query19_values = HashMap::from([entry(":projectname", "P-project_001")]); + let query19_values = HashMap::from([ + entry(":projectname", "P-project_001"), + entry(":rustsuffix", "-rust"), + ]); let query19_response = ddb .query() @@ -715,6 +759,7 @@ async fn run_query19( .index_name("GSI-0") .set_expression_attribute_values(Some(query19_values)) .key_condition_expression("PK = :projectname AND SK = :projectname") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -723,7 +768,7 @@ async fn run_query19( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("project1")); + assert_eq!(items[0]["partition_key"], ss("project1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_001")); Ok(()) } @@ -739,6 +784,7 @@ async fn run_query20( entry(":projectname", "P-project_002"), entry(":date1", "TC-2022-01-01"), entry(":date2", "TC-2023-01-01"), + entry(":rustsuffix", "-rust"), ]); let query20_response = ddb @@ -747,6 +793,7 @@ async fn run_query20( .index_name("GSI-0") .set_expression_attribute_values(Some(query20_values)) .key_condition_expression("PK = :projectname AND SK BETWEEN :date1 AND :date2") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -756,10 +803,10 @@ async fn run_query20( assert_eq!(items.len(), 2); assert!( - ((items[0]["partition_key"] == ss("timecard1")) - && (items[1]["partition_key"] == ss("timecard2"))) - || ((items[0]["partition_key"] == ss("timecard2")) - && (items[1]["partition_key"] == ss("timecard1"))) + ((items[0]["partition_key"] == ss("timecard1-rust")) + && (items[1]["partition_key"] == ss("timecard2-rust"))) + || ((items[0]["partition_key"] == ss("timecard2-rust")) + && (items[1]["partition_key"] == ss("timecard1-rust"))) ); Ok(()) } @@ -779,6 +826,7 @@ async fn run_query21( let query21_values = HashMap::from([ entry(":projectname", "P-project_002"), entry(":role", "SDE3"), + entry(":rustsuffix", "-rust"), ]); let query21_response = ddb @@ -788,7 +836,7 @@ async fn run_query21( .set_expression_attribute_values(Some(query21_values)) .set_expression_attribute_names(Some(query21_names)) .key_condition_expression("PK = :projectname") - .filter_expression("#role = :role") + .filter_expression("#role = :role AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -797,7 +845,7 @@ async fn run_query21( assert_eq!(items.len(), 1); // Known value test: Assert some properties the item - assert_eq!(items[0]["partition_key"], ss("timecard1")); + assert_eq!(items[0]["partition_key"], ss("timecard1-rust")); assert_eq!(items[0]["ProjectName"], ss("project_002")); Ok(()) } @@ -809,7 +857,8 @@ async fn run_query22( // Query 22: Get reservations by building ID // Key condition: PK = Building ID - let query22_values = HashMap::from([entry(":building", "B-SEA33")]); + let query22_values = + HashMap::from([entry(":building", "B-SEA33"), entry(":rustsuffix", "-rust")]); let query22_response = ddb .query() @@ -817,6 +866,7 @@ async fn run_query22( .index_name("GSI-0") .set_expression_attribute_values(Some(query22_values)) .key_condition_expression("PK = :building") + .filter_expression("contains(partition_key, :rustsuffix)") .send() .await?; @@ -826,10 +876,10 @@ async fn run_query22( assert_eq!(items.len(), 2); assert!( - ((items[0]["partition_key"] == ss("reservation1")) - && (items[1]["partition_key"] == ss("reservation2"))) - || ((items[0]["partition_key"] == ss("reservation2")) - && (items[1]["partition_key"] == ss("reservation1"))) + ((items[0]["partition_key"] == ss("reservation1-rust")) + && (items[1]["partition_key"] == ss("reservation2-rust"))) + || ((items[0]["partition_key"] == ss("reservation2-rust")) + && (items[1]["partition_key"] == ss("reservation1-rust"))) ); Ok(()) } @@ -851,6 +901,7 @@ async fn run_query23( entry(":date1", "MS-2022-07-01"), entry(":date2", "MS-2022-07-08"), entry(":zero", "0"), + entry(":rustsuffix", "-rust"), ]); let query23_response = ddb @@ -860,7 +911,7 @@ async fn run_query23( .set_expression_attribute_values(Some(query23_values)) .set_expression_attribute_names(Some(query23_names)) .key_condition_expression("PK = :building AND SK BETWEEN :date1 AND :date2") - .filter_expression("#duration > :zero") + .filter_expression("#duration > :zero AND contains(partition_key, :rustsuffix)") .send() .await?; @@ -870,10 +921,10 @@ async fn run_query23( assert_eq!(items.len(), 2); assert!( - ((items[0]["partition_key"] == ss("reservation1")) - && (items[1]["partition_key"] == ss("reservation2"))) - || ((items[0]["partition_key"] == ss("reservation2")) - && (items[1]["partition_key"] == ss("reservation1"))) + ((items[0]["partition_key"] == ss("reservation1-rust")) + && (items[1]["partition_key"] == ss("reservation2-rust"))) + || ((items[0]["partition_key"] == ss("reservation2-rust")) + && (items[1]["partition_key"] == ss("reservation1-rust"))) ); Ok(()) } diff --git a/releases/rust/db_esdk/examples/test_utils.rs b/releases/rust/db_esdk/examples/test_utils.rs index 52c845c308..980fbe7f31 100644 --- a/releases/rust/db_esdk/examples/test_utils.rs +++ b/releases/rust/db_esdk/examples/test_utils.rs @@ -43,6 +43,10 @@ pub const TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN: &str = // Our tests require access to DDB Table with this name configured as a branch keystore pub const TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME: &str = "KeyStoreDdbTable"; + +// Pre-existing branch key IDs in the key store, matching Java/NET test configuration +pub const TEST_BRANCH_KEY_ID: &str = "3f43a9af-08c5-4317-b694-3d3e883dcaef"; +pub const TEST_ALTERNATE_BRANCH_KEY_ID: &str = "4bb57643-07c1-419e-92ad-0df0df149d7c"; pub const TEST_COMPLEX_DDB_TABLE_NAME: &str = "ComplexBeaconTestTable"; // Helper method to clean up test items diff --git a/releases/rust/db_esdk/src/implementation_from_dafny.rs b/releases/rust/db_esdk/src/implementation_from_dafny.rs index 2d813a9b32..769f62997c 100644 --- a/releases/rust/db_esdk/src/implementation_from_dafny.rs +++ b/releases/rust/db_esdk/src/implementation_from_dafny.rs @@ -55510,7 +55510,7 @@ pub mod software { } /// ../submodules/MaterialProviders/ComAmazonawsKms/src/Index.dfy(31,3) pub fn DafnyUserAgentSuffix(runtime: &Sequence) -> Sequence { - let mut version: Sequence = string_utf16_of("1.11.0"); + let mut version: Sequence = string_utf16_of("1.11.2"); string_utf16_of("AwsCryptographicMPL/").concat(runtime).concat(&string_utf16_of("/")).concat(&version) } /// ../submodules/MaterialProviders/ComAmazonawsKms/Model/ComAmazonawsKmsTypes.dfy(2006,3) From 23ca70572aba17a68263ae836112b40634dc3d6e Mon Sep 17 00:00:00 2001 From: Tony Knapp <5892063+texastony@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:39:03 -0700 Subject: [PATCH 10/10] Update DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Corella <39066999+josecorella@users.noreply.github.com> --- DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml b/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml index 8801db0e33..a7c6648bc6 100644 --- a/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml +++ b/DynamoDbEncryption/runtimes/rust/test_examples/Cargo.toml @@ -7,7 +7,7 @@ rust-version = "1.81.0" [dependencies] aws-config = "1.5.15" -aws-db-esdk = "1.2.3" +aws-sdk-dynamodb = "1.62.0" aws-lc-rs = "1.12.2" aws-lc-sys = "0.38.0" aws-sdk-kms = "1.57.0"