From 894864aabe8087cca6f206502601b8d215adcb47 Mon Sep 17 00:00:00 2001 From: Andy Jewell Date: Wed, 12 Feb 2025 17:40:40 -0500 Subject: [PATCH 1/7] chore(rust): enable wrapped client test vectors --- TestVectors/Makefile | 6 +- ...tographyDynamoDbEncryptionTypesWrapped.dfy | 1 + .../runtimes/rust/src/create_client.rs | 6 +- TestVectors/runtimes/rust/src/intercept.rs | 182 ++++++++++++++++++ TestVectors/runtimes/rust/src/lib.rs | 1 + 5 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 TestVectors/runtimes/rust/src/intercept.rs diff --git a/TestVectors/Makefile b/TestVectors/Makefile index 3a4cea433..467c1947e 100644 --- a/TestVectors/Makefile +++ b/TestVectors/Makefile @@ -63,6 +63,8 @@ PROJECT_INDEX := \ submodules/MaterialProviders/AwsCryptographicMaterialProviders/dafny/AwsCryptographyKeyStore/src/Index.dfy \ submodules/MaterialProviders/TestVectorsAwsCryptographicMaterialProviders/dafny/KeyVectors/src/Index.dfy \ DynamoDbEncryption/dafny/StructuredEncryption/src/Index.dfy \ + DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Index.dfy \ + DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/Index.dfy \ DynamoDbEncryption/dafny/DynamoDbEncryption/src/Index.dfy \ STD_LIBRARY=submodules/MaterialProviders/StandardLibrary @@ -77,8 +79,10 @@ SERVICE_DEPS_DDBEncryption := \ submodules/MaterialProviders/ComAmazonawsDynamodb \ submodules/MaterialProviders/AwsCryptographicMaterialProviders/dafny/AwsCryptographicMaterialProviders \ submodules/MaterialProviders/AwsCryptographicMaterialProviders/dafny/AwsCryptographyKeyStore \ - DynamoDbEncryption/dafny/StructuredEncryption \ + DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms \ DynamoDbEncryption/dafny/DynamoDbEncryption \ + DynamoDbEncryption/dafny/DynamoDbItemEncryptor \ + DynamoDbEncryption/dafny/StructuredEncryption \ submodules/MaterialProviders/TestVectorsAwsCryptographicMaterialProviders/dafny/TestVectorsAwsCryptographicMaterialProviders \ transpile_implementation_rust: _remove_wrapped_client_rust diff --git a/TestVectors/dafny/DDBEncryption/Model/AwsCryptographyDynamoDbEncryptionTypesWrapped.dfy b/TestVectors/dafny/DDBEncryption/Model/AwsCryptographyDynamoDbEncryptionTypesWrapped.dfy index cb0d63baa..ceddef25f 100644 --- a/TestVectors/dafny/DDBEncryption/Model/AwsCryptographyDynamoDbEncryptionTypesWrapped.dfy +++ b/TestVectors/dafny/DDBEncryption/Model/AwsCryptographyDynamoDbEncryptionTypesWrapped.dfy @@ -4,6 +4,7 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" // BEGIN MANUAL EDIT include "../../../../DynamoDbEncryption/dafny/DynamoDbEncryption/src/Index.dfy" +include "../../../../DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/Index.dfy" include "../../../../submodules/MaterialProviders/TestVectorsAwsCryptographicMaterialProviders/dafny/KeyVectors/src/Index.dfy" // END MANUAL EDIT abstract module WrappedAbstractAwsCryptographyDynamoDbEncryptionService { diff --git a/TestVectors/runtimes/rust/src/create_client.rs b/TestVectors/runtimes/rust/src/create_client.rs index 951659264..175d7bbbc 100644 --- a/TestVectors/runtimes/rust/src/create_client.rs +++ b/TestVectors/runtimes/rust/src/create_client.rs @@ -7,7 +7,7 @@ use crate::implementation_from_dafny::software::amazon::cryptography::services:: use crate::implementation_from_dafny::software::amazon::cryptography::dbencryptionsdk::dynamodb::internaldafny::types::Error; use crate::implementation_from_dafny::_Wrappers_Compile; use std::sync::LazyLock; -// use crate::intercept::DbEsdkInterceptor; +use crate::intercept::DbEsdkInterceptor; static DAFNY_TOKIO_RUNTIME: LazyLock = LazyLock::new(|| { tokio::runtime::Builder::new_multi_thread() @@ -24,6 +24,8 @@ impl _CreateInterceptedDDBClient_Compile::_default { pub fn CreateInterceptedDDBClient(config : &Rc) -> Rc<_Wrappers_Compile::Result, Rc>> { + + let table_configs = crate::conversions::dynamo_db_tables_encryption_config::plain_from_dafny(config); let shared_config = DAFNY_TOKIO_RUNTIME.block_on(aws_config::load_defaults( aws_config::BehaviorVersion::v2024_03_28())); @@ -33,7 +35,7 @@ impl _CreateInterceptedDDBClient_Compile::_default { .build(); let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&shared_config) -// .interceptor(DbEsdkInterceptor::new(table_configs)) + .interceptor(DbEsdkInterceptor::new(table_configs).unwrap()) .build(); let inner = aws_sdk_dynamodb::Client::from_conf(dynamo_config); diff --git a/TestVectors/runtimes/rust/src/intercept.rs b/TestVectors/runtimes/rust/src/intercept.rs new file mode 100644 index 000000000..ce59fe7a6 --- /dev/null +++ b/TestVectors/runtimes/rust/src/intercept.rs @@ -0,0 +1,182 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![deny(warnings, unconditional_panic)] +#![deny(nonstandard_style)] +#![deny(clippy::all)] +#![allow(unused)] +#![allow(clippy::result_large_err)] + +use aws_sdk_dynamodb::{ + config::{ + interceptors::{BeforeSerializationInterceptorContextMut, FinalizerInterceptorContextMut}, + ConfigBag, Intercept, RuntimeComponents, + }, + error::BoxError, +}; +use aws_smithy_runtime_api::client::interceptors::context::Input; +use aws_smithy_types::config_bag::{Storable, StoreReplace}; + +macro_rules! modify_request { + ($cfg:ident,$request:ident,$self:ident,$transform:ident) => {{ + // store the original request + $cfg.interceptor_state() + .store_put(OriginalRequest(Input::erase($request.clone()))); + + // transform the request + let result = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + $self + .client + .$transform() + .sdk_input($request.clone()) + .send() + .await + }) + }); + match result { + Ok(x) => *$request = x.transformed_input.unwrap(), + Err(x) => { + let s = format!("{:?}", x); + return Err(s.into()); + } + }; + }}; +} + +macro_rules! modify_response { + ($cfg:ident,$type:ty,$response:ident,$self:ident,$transform:ident) => {{ + // retrieve the original request + let original = $cfg + .load::() + .expect("we put this in ourselves"); + let original = original + .0 + .downcast_ref::<$type>() + .expect("we know this type corresponds to the output type"); + + // transform the response + let result = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + $self + .client + .$transform() + .original_input(original.clone()) + .sdk_output($response.clone()) + .send() + .await + }) + }); + match result { + Ok(x) => *$response = x.transformed_output.unwrap(), + Err(x) => { + let s = format!("{:?}", x); + return Err(s.into()); + } + }; + }}; +} + +type TClient = crate::deps::aws_cryptography_dbEncryptionSdk_dynamoDb_transforms::client::Client; + +#[derive(Debug)] +pub struct DbEsdkInterceptor { + client: TClient, +} + +impl DbEsdkInterceptor { + pub fn new( + config: crate::deps::aws_cryptography_dbEncryptionSdk_dynamoDb_transforms::types::DynamoDbTablesEncryptionConfig, + ) -> Result { + let client = TClient::from_conf(config)?; + Ok(DbEsdkInterceptor { client }) + } +} + +#[derive(Debug)] +struct OriginalRequest(Input); + +impl Storable for OriginalRequest { + type Storer = StoreReplace; +} + +impl Intercept for DbEsdkInterceptor { + fn name(&self) -> &'static str { + "DbEsdkInterceptor" + } + + fn modify_before_serialization( + &self, + // https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/interceptors/context/struct.BeforeSerializationInterceptorContextMut.html + context: &mut BeforeSerializationInterceptorContextMut, + _rc: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + if let Some(batch_execute_statement_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, batch_execute_statement_request, self, batch_execute_statement_input_transform); + } else if let Some(batch_get_item_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, batch_get_item_request, self, batch_get_item_input_transform); + } else if let Some(batch_write_item_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, batch_write_item_request, self, batch_write_item_input_transform); + } else if let Some(delete_item_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, delete_item_request, self, delete_item_input_transform); + } else if let Some(execute_statement_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, execute_statement_request, self, execute_statement_input_transform); + } else if let Some(execute_transaction_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, execute_transaction_request, self, execute_transaction_input_transform); + } else if let Some(get_item_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, get_item_request, self, get_item_input_transform); + } else if let Some(put_item_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, put_item_request, self, put_item_input_transform); + } else if let Some(query_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, query_request, self, query_input_transform); + } else if let Some(scan_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, scan_request, self, scan_input_transform); + } else if let Some(transact_get_items_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, transact_get_items_request, self, transact_get_items_input_transform); + } else if let Some(transact_write_items_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, transact_write_items_request, self, transact_write_items_input_transform); + } else if let Some(update_item_request) = context.input_mut().downcast_mut::() { + modify_request!(cfg, update_item_request, self, update_item_input_transform); + } + Ok(()) + } + + fn modify_before_attempt_completion( + &self, + context: &mut FinalizerInterceptorContextMut, + _rc: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + if let Some(Ok(output)) = context.output_or_error_mut() { + if let Some(batch_execute_statement_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::batch_execute_statement::BatchExecuteStatementInput, batch_execute_statement_response, self, batch_execute_statement_output_transform); + } else if let Some(batch_get_item_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::batch_get_item::BatchGetItemInput, batch_get_item_response, self, batch_get_item_output_transform); + } else if let Some(batch_write_item_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::batch_write_item::BatchWriteItemInput, batch_write_item_response, self, batch_write_item_output_transform); + } else if let Some(delete_item_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::delete_item::DeleteItemInput, delete_item_response, self, delete_item_output_transform); + } else if let Some(execute_statement_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::execute_statement::ExecuteStatementInput, execute_statement_response, self, execute_statement_output_transform); + } else if let Some(execute_transaction_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::execute_transaction::ExecuteTransactionInput, execute_transaction_response, self, execute_transaction_output_transform); + } else if let Some(get_item_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::get_item::GetItemInput, get_item_response, self, get_item_output_transform); + } else if let Some(put_item_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::put_item::PutItemInput, put_item_response, self, put_item_output_transform); + } else if let Some(query_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::query::QueryInput, query_response, self, query_output_transform); + } else if let Some(scan_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::scan::ScanInput, scan_response, self, scan_output_transform); + } else if let Some(transact_get_items_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::transact_get_items::TransactGetItemsInput, transact_get_items_response, self, transact_get_items_output_transform); + } else if let Some(transact_write_items_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::transact_write_items::TransactWriteItemsInput, transact_write_items_response, self, transact_write_items_output_transform); + } else if let Some(update_item_response) = output.downcast_mut::() { + modify_response!(cfg, aws_sdk_dynamodb::operation::update_item::UpdateItemInput, update_item_response, self, update_item_output_transform); + } + } + Ok(()) + } +} diff --git a/TestVectors/runtimes/rust/src/lib.rs b/TestVectors/runtimes/rust/src/lib.rs index eb2db89f9..ea26b691a 100644 --- a/TestVectors/runtimes/rust/src/lib.rs +++ b/TestVectors/runtimes/rust/src/lib.rs @@ -13,6 +13,7 @@ pub mod error; pub mod operation; pub mod types; pub mod validation; +pub mod intercept; #[cfg(feature = "wrapped-client")] pub mod wrapped; From 5830b89707cc9ddce1a8f9b3e78be7b945bb61e3 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Thu, 13 Feb 2025 12:07:49 -0800 Subject: [PATCH 2/7] Use the correct copy of the DynamoDbTablesEncryptionConfig shape --- TestVectors/runtimes/rust/src/create_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestVectors/runtimes/rust/src/create_client.rs b/TestVectors/runtimes/rust/src/create_client.rs index 175d7bbbc..b8c885eb5 100644 --- a/TestVectors/runtimes/rust/src/create_client.rs +++ b/TestVectors/runtimes/rust/src/create_client.rs @@ -25,7 +25,7 @@ impl _CreateInterceptedDDBClient_Compile::_default { -> Rc<_Wrappers_Compile::Result, Rc>> { - let table_configs = crate::conversions::dynamo_db_tables_encryption_config::plain_from_dafny(config); + let table_configs = crate::deps::aws_cryptography_dbEncryptionSdk_dynamoDb_transforms::conversions::dynamo_db_tables_encryption_config::_dynamo_db_tables_encryption_config::plain_from_dafny(config); let shared_config = DAFNY_TOKIO_RUNTIME.block_on(aws_config::load_defaults( aws_config::BehaviorVersion::v2024_03_28())); From 20ed3dbc67638d83a3ecd9b24e62b710c3ea3949 Mon Sep 17 00:00:00 2001 From: Andy Jewell Date: Thu, 13 Feb 2025 15:28:51 -0500 Subject: [PATCH 3/7] m --- TestVectors/runtimes/rust/SkipLocal.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 TestVectors/runtimes/rust/SkipLocal.txt diff --git a/TestVectors/runtimes/rust/SkipLocal.txt b/TestVectors/runtimes/rust/SkipLocal.txt deleted file mode 100644 index 2e8dda198..000000000 --- a/TestVectors/runtimes/rust/SkipLocal.txt +++ /dev/null @@ -1 +0,0 @@ -Rust can't deal with wrapped DDB Client yet. From dfda5ab0bb87c97edfe9d0a57879d6827bc39688 Mon Sep 17 00:00:00 2001 From: Andy Jewell Date: Thu, 13 Feb 2025 16:55:23 -0500 Subject: [PATCH 4/7] m --- .github/workflows/library_rust_tests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/library_rust_tests.yml b/.github/workflows/library_rust_tests.yml index fdc8237cf..dff52bf36 100644 --- a/.github/workflows/library_rust_tests.yml +++ b/.github/workflows/library_rust_tests.yml @@ -34,6 +34,12 @@ jobs: env: RUST_MIN_STACK: 838860800 steps: + - name: Setup DynamoDB Local + uses: rrainn/dynamodb-action@v4.0.0 + with: + port: 8000 + cors: "*" + - name: Support longpaths on Git checkout run: | git config --global core.longpaths true From 82d700da010f302637642db8b43c0b1dae5b000d Mon Sep 17 00:00:00 2001 From: Andy Jewell Date: Thu, 13 Feb 2025 17:24:40 -0500 Subject: [PATCH 5/7] m --- .github/workflows/library_rust_tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/library_rust_tests.yml b/.github/workflows/library_rust_tests.yml index dff52bf36..9f0068896 100644 --- a/.github/workflows/library_rust_tests.yml +++ b/.github/workflows/library_rust_tests.yml @@ -34,7 +34,12 @@ jobs: env: RUST_MIN_STACK: 838860800 steps: + - name: Setup Docker + if: matrix.os == 'macos-13' && matrix.library == 'TestVectors' + uses: actions/setup-docker-on-macos@v1-alpha + - name: Setup DynamoDB Local + if: matrix.library == 'TestVectors' uses: rrainn/dynamodb-action@v4.0.0 with: port: 8000 From c287133578eb36bce8d44dd283935321a6db0065 Mon Sep 17 00:00:00 2001 From: Andy Jewell Date: Thu, 13 Feb 2025 17:26:41 -0500 Subject: [PATCH 6/7] m --- .github/workflows/library_rust_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/library_rust_tests.yml b/.github/workflows/library_rust_tests.yml index 9f0068896..9e7b3280e 100644 --- a/.github/workflows/library_rust_tests.yml +++ b/.github/workflows/library_rust_tests.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Setup Docker if: matrix.os == 'macos-13' && matrix.library == 'TestVectors' - uses: actions/setup-docker-on-macos@v1-alpha + uses: marketplace/actions/setup-docker-on-macos@v1-alpha - name: Setup DynamoDB Local if: matrix.library == 'TestVectors' From a43949d70726b91d3736909035831e68e5edb529 Mon Sep 17 00:00:00 2001 From: Andy Jewell Date: Thu, 13 Feb 2025 17:29:29 -0500 Subject: [PATCH 7/7] m --- .github/workflows/library_rust_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/library_rust_tests.yml b/.github/workflows/library_rust_tests.yml index 9e7b3280e..72160471c 100644 --- a/.github/workflows/library_rust_tests.yml +++ b/.github/workflows/library_rust_tests.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Setup Docker if: matrix.os == 'macos-13' && matrix.library == 'TestVectors' - uses: marketplace/actions/setup-docker-on-macos@v1-alpha + uses: douglascamata/setup-docker-macos-action@v1-alpha - name: Setup DynamoDB Local if: matrix.library == 'TestVectors'