feat: enable VPC Lattice support - #829
Conversation
| "apigw_http", | ||
| "apigw_rest", | ||
| "alb", | ||
| "vpc_lattice", |
There was a problem hiding this comment.
[BUG] Adding another HTTP event variant alongside pass_through changes event classification, and nothing in this PR verifies that non-HTTP events still behave as before.
pass_through is the fallback variant of lambda_http's event enum, and it is the adapter's only mechanism for non-HTTP triggers. In src/lib.rs:
if matches!(request_context, RequestContext::PassThrough) && parts.method == Method::POST {
path = self.pass_through_path.as_str();
}Every SQS, SNS, S3, DynamoDB, EventBridge, and Bedrock Agent payload reaches the app only because it deserializes into PassThrough (documented in docs/guide/src/features/non-http-events.md, exercised by examples/sqs-expressjs and examples/bedrock-agent-fastapi). Enabling one more variant necessarily shrinks the set of payloads that reach that fallback. VPC Lattice payloads are shaped as loosely typed method / raw_path / headers / query_string_parameters / body / is_base64_encoded fields, so if those fields deserialize with defaults, an unrelated event JSON can match the Lattice variant instead of falling through. The failure is silent: the event would be forwarded as a GET to / with an empty body rather than POSTed to AWS_LWA_PASS_THROUGH_PATH, so a pass-through handler would simply stop receiving messages.
Two things are worth adding before merge:
- A regression test asserting a non-HTTP payload still routes to the pass-through path. The current harness cannot express this —
tests/integ_tests/common/mod.rsonly builds ALB events:
pub enum LambdaEventType {
#[default]
ALB,
// TODO: Add other event types
}- A test covering the new path itself: a VPC Lattice event producing the expected request path, query string, and
x-amzn-request-contextheader. There is currently no coverage that the newly enabled variant works end to end throughfetch_response, which derives the path fromraw_http_path()and serializes the context into a header.
This matters more than usual here because the PR description notes cargo check --locked could not complete in the author's environment, so neither compilation nor the existing test suite has been run against the change.
|
Added focused regression coverage in
Verification passed: |
There was a problem hiding this comment.
Code Review Results
Reviewed: 34d3a29..fe18556
Files: 3
Comments: 1
Comments on lines outside the diff:
[Cargo.toml:31] [GENERAL] Adding vpc_lattice inserts another variant into lambda_http's event enum, which is matched untagged (variants are tried in declaration order, with pass_through as the fallback). The new tests cover the two ends of that ordering — a Bedrock Agent payload still resolving to RequestContext::PassThrough, and a VPC Lattice V2 payload resolving to RequestContext::VpcLattice — but nothing covers the variants in between.
That gap matters because no existing test deserializes a real event payload at all. LambdaEventBuilder::build() in tests/integ_tests/common/mod.rs returns LambdaRequest::Alb(...) directly, and the unit tests in src/lib.rs construct LambdaRequest::Alb / LambdaRequest::ApiGatewayV2 directly as well. Both bypass serde entirely, so if a VPC Lattice V2 payload shape overlaps an ALB or API Gateway payload shape (both carry path/headers/queryStringParameters/body/requestContext), the misclassification would produce a wrong x-amzn-request-context header and a wrong forwarded path with the entire suite still green. The e2e tests that would catch it are #[ignore]d and require a deployed stack.
Since the new tests already establish the pattern, the check is cheap to add:
#[test]
fn test_http_events_still_classify_after_enabling_vpc_lattice() {
let alb = lambda_http::request::from_str(&alb_event_json()).expect("Failed to deserialize ALB event");
assert!(matches!(alb.request_context(), RequestContext::Alb(_)));
let apigw = lambda_http::request::from_str(&apigw_v2_event_json()).expect("Failed to deserialize APIGW event");
assert!(matches!(apigw.request_context(), RequestContext::ApiGatewayV2(_)));
}This is also worth confirming before merge because the PR description notes that cargo check --locked could not complete in this environment, so neither the new tests nor the feature combination have actually been compiled or run.
Note: Cargo.lock was reviewed only for consistency with the manifest change (version and checksum bumps for aws_lambda_events, lambda_http, lambda_runtime, lambda_runtime_api_client); as a generated lock file it is otherwise skipped.
|
Added commit
|
| "apigw_http", | ||
| "apigw_rest", | ||
| "alb", | ||
| "vpc_lattice", |
There was a problem hiding this comment.
[GENERAL] Enabling vpc_lattice makes VPC Lattice a supported trigger, but no user-facing documentation in this repo reflects that, and the supported payload format is left implicit.
Concretely stale/incomplete after this change:
README.md— the features list still reads "Supports Amazon API Gateway Rest API and Http API endpoints, Lambda Function URLs, and Application Load Balancer".docs/guide/src/features/request-context.md— describesx-amzn-request-contextpurely as "API Gateway request context"; with this change the header can now carry a VPC Lattice context (serviceNetworkArn,serviceArn,targetGroupArn,identity), which is exactly the metadata an app behind Lattice would read for authorization.
The payload-format point matters behaviorally, not just editorially: the PR description and the test fixture ("version": "2.0") target the VPC Lattice V2 event structure. A Lattice target group configured with the other payload format would not match that variant and would instead fall back to the pass-through path in src/lib.rs:
if matches!(request_context, RequestContext::PassThrough) && parts.method == Method::POST {
path = self.pass_through_path.as_str();
}That means a misconfigured target group silently POSTs the raw event to AWS_LWA_PASS_THROUGH_PATH (default /events) instead of the app's real route — a failure mode that is very hard to diagnose without a documented requirement. Please state which payload format(s) are supported and note the target-group configuration requirement.
| .expect("Failed to create adapter"); | ||
| let mut request = lambda_http::request::from_str(&event).expect("Failed to deserialize event"); | ||
|
|
||
| assert!(matches!(request.request_context(), RequestContext::PassThrough)); |
There was a problem hiding this comment.
[GENERAL] The regression guard for the classification change covers a single non-HTTP payload shape, which leaves most of the documented pass-through surface unguarded.
This PR inserts a new variant into lambda_http's untagged event enum, where pass_through is the fallback and variants are tried in declaration order. test_non_http_event_routes_to_configured_pass_through_path proves a Bedrock Agent payload still resolves to RequestContext::PassThrough, but docs/guide/src/features/non-http-events.md claims support for "SQS, SNS, S3, DynamoDB, Kinesis, Kafka, EventBridge, and Bedrock Agents". A records-style payload ({"Records": [...]}) has a completely different shape from the Bedrock payload, so it exercises a different matching path and is the more representative case for the adapter's non-HTTP triggers — and the repo already ships a fixture at examples/sqs-expressjs/events/sqs.json to model it after.
Similarly, test_http_event_request_context_classification asserts ALB and API Gateway V2 but omits API Gateway REST (V1), which is one of the adapter's headline supported triggers and is equally subject to variant-ordering changes.
Suggested additions, following the pattern already established in the new test:
let sqs_event = json!({
"Records": [{
"messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
"receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a",
"body": "Test message.",
"eventSource": "aws:sqs",
"awsRegion": "us-east-1"
}]
})
.to_string();
let sqs_request = lambda_http::request::from_str(&sqs_event).expect("Failed to deserialize SQS event");
assert!(matches!(sqs_request.request_context(), RequestContext::PassThrough));Without these, a future variant reordering or event-struct loosening in lambda_http could silently reroute non-HTTP triggers away from AWS_LWA_PASS_THROUGH_PATH and the suite would still pass.
Cargo.lock was reviewed as a lock file only (version/checksum bumps for aws_lambda_events, lambda_http, lambda_runtime, lambda_runtime_api_client); no findings. I did not evaluate whether the vpc_lattice feature or the pinned versions resolve correctly, since the crate sources are not available in this workspace and the PR notes cargo check --locked could not complete — worth confirming in CI before merge, given the 244 lines of new test code have not been compiled.
Enable VPC Lattice event support in the adapter by enabling
lambda_http's existingvpc_latticefeature and updating the direct dependency from 1.1.1 to 1.2.0. The existing API Gateway, ALB, pass-through, tracing, and Tokio concurrency features are preserved.Cargo.lockis refreshed for the required Lambda crates.This exposes the VPC Lattice V2 event support already implemented by
lambda_http.Validation:
cargo fmt --all -- --checkcargo metadata --locked --offline --format-version 1 --no-depsgit diff --checkcargo check --lockedcould not reach compilation because this environment could not resolvestatic.crates.iowhile downloading the newly lockedlambda_runtimesource.Closes #789