From 8ea4666a56c13efd1de989db4f4803d562461f32 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 23 Jan 2024 10:20:38 +0800 Subject: [PATCH 1/3] Tighten lambda-http event deserializer --- lambda-events/src/event/apigw/mod.rs | 3 ++ .../src/fixtures/example-sqs-event.json | 3 +- lambda-http/src/deserializer.rs | 37 +++++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lambda-events/src/event/apigw/mod.rs b/lambda-events/src/event/apigw/mod.rs index 36512f9c..e0774608 100644 --- a/lambda-events/src/event/apigw/mod.rs +++ b/lambda-events/src/event/apigw/mod.rs @@ -13,6 +13,7 @@ use std::collections::HashMap; /// `ApiGatewayProxyRequest` contains data coming from the API Gateway proxy #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct ApiGatewayProxyRequest where T1: DeserializeOwned, @@ -119,6 +120,7 @@ where /// `ApiGatewayV2httpRequest` contains data coming from the new HTTP API Gateway #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct ApiGatewayV2httpRequest { #[serde(default, rename = "type")] pub kind: Option, @@ -333,6 +335,7 @@ pub struct ApiGatewayRequestIdentity { /// `ApiGatewayWebsocketProxyRequest` contains data coming from the API Gateway proxy #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct ApiGatewayWebsocketProxyRequest where T1: DeserializeOwned, diff --git a/lambda-events/src/fixtures/example-sqs-event.json b/lambda-events/src/fixtures/example-sqs-event.json index 732b65c1..eea77f84 100644 --- a/lambda-events/src/fixtures/example-sqs-event.json +++ b/lambda-events/src/fixtures/example-sqs-event.json @@ -37,5 +37,4 @@ } } ] -} - +} \ No newline at end of file diff --git a/lambda-http/src/deserializer.rs b/lambda-http/src/deserializer.rs index 2584c0ad..1b2008c3 100644 --- a/lambda-http/src/deserializer.rs +++ b/lambda-http/src/deserializer.rs @@ -56,7 +56,7 @@ mod tests { fn test_deserialize_apigw_rest() { let data = include_bytes!("../../lambda-events/src/fixtures/example-apigw-request.json"); - let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialze apigw rest data"); + let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialize apigw rest data"); match req { LambdaRequest::ApiGatewayV1(req) => { assert_eq!("12345678912", req.request_context.account_id.unwrap()); @@ -69,7 +69,7 @@ mod tests { fn test_deserialize_apigw_http() { let data = include_bytes!("../../lambda-events/src/fixtures/example-apigw-v2-request-iam.json"); - let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialze apigw http data"); + let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialize apigw http data"); match req { LambdaRequest::ApiGatewayV2(req) => { assert_eq!("123456789012", req.request_context.account_id.unwrap()); @@ -84,7 +84,7 @@ mod tests { "../../lambda-events/src/fixtures/example-alb-lambda-target-request-multivalue-headers.json" ); - let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialze alb rest data"); + let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialize alb rest data"); match req { LambdaRequest::Alb(req) => { assert_eq!( @@ -101,7 +101,7 @@ mod tests { let data = include_bytes!("../../lambda-events/src/fixtures/example-apigw-websocket-request-without-method.json"); - let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialze apigw websocket data"); + let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialize apigw websocket data"); match req { LambdaRequest::WebSocket(req) => { assert_eq!("CONNECT", req.request_context.event_type.unwrap()); @@ -109,4 +109,33 @@ mod tests { other => panic!("unexpected request variant: {:?}", other), } } + + #[test] + #[cfg(feature = "pass_through")] + fn test_deserialize_bedrock_agent() { + let data = include_bytes!("../../lambda-events/src/fixtures/example-bedrock-agent-runtime-event.json"); + + let req: LambdaRequest = + serde_json::from_slice(data).expect("failed to deserialize bedrock agent request data"); + match req { + LambdaRequest::PassThrough(req) => { + assert_eq!(String::from_utf8_lossy(data), req); + } + other => panic!("unexpected request variant: {:?}", other), + } + } + + #[test] + #[cfg(feature = "pass_through")] + fn test_deserialize_sqs() { + let data = include_bytes!("../../lambda-events/src/fixtures/example-sqs-event.json"); + + let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialize sqs event data"); + match req { + LambdaRequest::PassThrough(req) => { + assert_eq!(String::from_utf8_lossy(data), req); + } + other => panic!("unexpected request variant: {:?}", other), + } + } } From aa530e9e28458ec4605717e04758d09cda538f0d Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 23 Jan 2024 11:46:20 +0800 Subject: [PATCH 2/3] Add 'deny_unknown_fields' for alb request --- lambda-events/src/event/alb/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lambda-events/src/event/alb/mod.rs b/lambda-events/src/event/alb/mod.rs index a3f96d88..6395c462 100644 --- a/lambda-events/src/event/alb/mod.rs +++ b/lambda-events/src/event/alb/mod.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; /// `AlbTargetGroupRequest` contains data originating from the ALB Lambda target group integration #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct AlbTargetGroupRequest { #[serde(with = "http_method")] pub http_method: Method, From 2799f0971b0e6ea5a048305174f1a59b8071da17 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 23 Jan 2024 12:24:16 +0800 Subject: [PATCH 3/3] Removed 'deny_unknown_fields' and make request_context mandatory for 'ApiGatewayProxyRequest' and 'ApiGatewayWebsocketProxyRequest' --- lambda-events/src/event/alb/mod.rs | 1 - lambda-events/src/event/apigw/mod.rs | 12 ++++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/lambda-events/src/event/alb/mod.rs b/lambda-events/src/event/alb/mod.rs index 6395c462..a3f96d88 100644 --- a/lambda-events/src/event/alb/mod.rs +++ b/lambda-events/src/event/alb/mod.rs @@ -9,7 +9,6 @@ use serde::{Deserialize, Serialize}; /// `AlbTargetGroupRequest` contains data originating from the ALB Lambda target group integration #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] pub struct AlbTargetGroupRequest { #[serde(with = "http_method")] pub http_method: Method, diff --git a/lambda-events/src/event/apigw/mod.rs b/lambda-events/src/event/apigw/mod.rs index e0774608..f2cb097a 100644 --- a/lambda-events/src/event/apigw/mod.rs +++ b/lambda-events/src/event/apigw/mod.rs @@ -13,10 +13,9 @@ use std::collections::HashMap; /// `ApiGatewayProxyRequest` contains data coming from the API Gateway proxy #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] pub struct ApiGatewayProxyRequest where - T1: DeserializeOwned, + T1: DeserializeOwned + Default, T1: Serialize, { /// The resource path defined in API Gateway @@ -44,7 +43,6 @@ where #[serde(deserialize_with = "deserialize_lambda_map")] #[serde(default)] pub stage_variables: HashMap, - #[serde(default)] #[serde(bound = "")] pub request_context: ApiGatewayProxyRequestContext, #[serde(default)] @@ -120,7 +118,6 @@ where /// `ApiGatewayV2httpRequest` contains data coming from the new HTTP API Gateway #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] pub struct ApiGatewayV2httpRequest { #[serde(default, rename = "type")] pub kind: Option, @@ -335,12 +332,11 @@ pub struct ApiGatewayRequestIdentity { /// `ApiGatewayWebsocketProxyRequest` contains data coming from the API Gateway proxy #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] pub struct ApiGatewayWebsocketProxyRequest where - T1: DeserializeOwned, + T1: DeserializeOwned + Default, T1: Serialize, - T2: DeserializeOwned, + T2: DeserializeOwned + Default, T2: Serialize, { /// The resource path defined in API Gateway @@ -370,7 +366,7 @@ where #[serde(deserialize_with = "deserialize_lambda_map")] #[serde(default)] pub stage_variables: HashMap, - #[serde(bound = "", default)] + #[serde(bound = "")] pub request_context: ApiGatewayWebsocketProxyRequestContext, #[serde(default)] pub body: Option,