feat(lambda): add AWS Lambda integration with 50 operations - #7216
Conversation
Adds an AWS Lambda block covering every major resource family: invocation, function CRUD, versions and aliases, resource-based permissions, event source mappings, reserved and provisioned concurrency, function URLs, asynchronous invocation configs, layers, tags, account settings, recursion detection, and runtime management. Tools run in-process through the shared internal tool-operation boundary using @aws-sdk/client-lambda. Request and response shapes are contract-bound, with shared response projections for the FunctionConfiguration, alias, event source mapping, function URL, provisioned concurrency, and layer types. Deployment packages are sourced from Amazon S3 or a container image URI; inline .zip upload is not supported.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Greptile SummaryThe PR adds an in-process AWS Lambda integration with workflow-block configuration, validated operation contracts, SDK command mapping, generated registry/catalog metadata, documentation, and broad test coverage.
Confidence Score: 5/5The PR appears safe to merge because the previously reported Lambda update, VPC, and timeout failures are resolved at the current head. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/blocks/blocks/lambda.ts | Defines the Lambda workflow block and now distinguishes explicit empty-array clearing from blank fields while using functionTimeout. |
| apps/sim/lib/internal/lambda/operations.ts | Maps validated operation inputs to AWS SDK commands, including complete VPC normalization and the renamed function timeout. |
| apps/sim/lib/internal/lambda/execute-tool.ts | Enforces contract parsing before dispatching Lambda operations through the internal execution boundary. |
| apps/sim/lib/api/contracts/tools/aws/lambda-update-function-configuration.ts | Validates update configuration bounds and requires VPC subnet and security-group lists to be supplied together. |
| apps/sim/tools/lambda/update_function_configuration.ts | Declares user-facing update parameters and forwards explicit empty collections and functionTimeout to the validated operation. |
| apps/sim/tools/lambda/supplied.ts | Preserves intentionally supplied empty arrays while omitting nullish values. |
| apps/sim/blocks/blocks/lambda.test.ts | Covers explicit collection clearing, blank-field preservation, and block parameter transformation. |
| apps/sim/lib/internal/lambda/operations.test.ts | Exercises SDK command mappings, including complete VPC detach objects. |
| apps/sim/lib/internal/lambda/execute-tool.test.ts | Verifies contract rejection of one-sided VPC updates before operation dispatch. |
Sequence Diagram
sequenceDiagram
participant W as Workflow Block
participant T as Tool Boundary
participant C as Lambda Contract
participant O as Lambda Operation
participant A as AWS Lambda
W->>T: Operation and transformed parameters
T->>C: Validate request contract
alt Invalid input
C-->>T: Structured validation error
T-->>W: Failed tool result
else Valid input
C->>O: Validated operation input
O->>A: AWS SDK command
A-->>O: Lambda response
O-->>T: Contract-shaped output
T-->>W: Successful tool result
end
Reviews (5): Last reviewed commit: "fix(lambda): never send a half-configure..." | Re-trigger Greptile
There was a problem hiding this comment.
Review completed against the latest diff
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
An empty list field coerced to undefined, so the AWS update command omitted the field and the previous value survived — there was no way to remove a function's layers, detach it from a VPC, or drop event source filters, response types, and source access configurations. A blank field still means "leave unchanged", since treating it as "clear" would wipe the setting on every update that left it empty. Clearing is now an explicit empty-array literal, documented in each field's description and placeholder. Also stops toSourceAccessConfigurations from folding an empty list back into an omitted field.
…dline The `timeout` param name is reserved: the shared tool executor reads `params.timeout` as its own operation deadline in milliseconds. A Lambda function timeout of 30 seconds therefore aborted the call after 30ms, so Create Function and Update Function Configuration failed whenever a timeout was set. Renamed to `functionTimeout`. Also tightens the boundary against documented AWS constraints and drops avoidable provider round-trips: - optional params supplied as null or an empty string are omitted rather than forwarded, so an empty qualifier no longer reaches AWS as `Qualifier: ''` - documented limits on functionName, qualifier, clientContext, statementId, action, and alias routing weights - source access configuration types are a closed enum, excluding VIRTUAL_HOST on update where AWS rejects it - cross-field checks: exactly one code source matched to packageType, runtime and handler required for a .zip package, an event source or Kafka bootstrap servers required, AT_TIMESTAMP paired with its timestamp, and masterRegion only alongside functionVersion ALL - architectures takes exactly one value, so it is no longer clearable - the block declares AuthMode.ApiKey, correcting a catalog entry that advertised the integration as needing no authentication Removes the unreachable non-ok branch from every transformResponse: the shared executor throws on any non-ok response before transformResponse runs. Raises the internal tool-operation registry test budget, whose cost scales with the number of registered tools.
Clearing only one of the two VPC lists produced `VpcConfig: { SubnetIds: [] }`
with no security groups, because an empty array is truthy and the wrapper
included each list independently. That is not a detach — it is an invalid
partial attachment.
A Lambda VPC attachment is a unit, so the contract now requires the two lists
to be supplied together on Create Function and Update Function Configuration,
naming the missing side. The wrapper defaults the other list to empty as well,
so it cannot emit a one-sided config even if called directly.
|
Confirmed and fixed in ec9d37e — this was a real follow-on from the previous round, not a stale read. The counterexample was exact: an empty array is truthy, so A Lambda VPC attachment is a unit, so the fix is at both levels:
Covered by four tests: a one-sided update is rejected at the boundary, a both-empty detach is accepted, and the mapper emits both keys in each direction. |
* fix(lambda): close the remaining contract validation gaps Follow-up to #7216, from review on the release PR. Every bound added here is one the AWS Lambda API reference documents; findings that asked for undocumented limits were left alone. Code source selection had two holes. `hasS3` required both S3 fields, so a partial pair alongside `imageUri` read as "image only" and the stray S3 field still went to AWS; and an `imageUri` with no `packageType` was accepted even though the package type then defaults to Zip. Both now fail at the boundary, naming the field to change, and the zip-only `s3ObjectVersion` and `sourceKmsKeyArn` count as S3 fields for the exclusivity check. The VPC guard only checked that both lists were supplied, so supplying both with one empty passed and produced a partial update. Both must now be empty (detach) or both populated (attach). Documented bounds added: - alias names: 1-128 and the documented pattern, which excludes all-digit names - descriptions: 256 characters - layer names: 140 characters and the name-or-ARN pattern - optional `functionName` on the event source mapping operations: 1-256 - `RemovePermission` statement IDs: 1-100 and its own pattern, which allows a dot where `AddPermission` does not Also rejects values that are structurally meaningless rather than merely out of range: empty tag keys, empty Kafka bootstrap servers, more than one weighted routing entry, and an event source mapping that supplies both an event source ARN and self-managed Kafka bootstrap servers. * fix(lambda): match twelve digits in the layer ARN pattern The account-ID segment was written as `\d{12}` inside a template literal, so the emitted regex carried a literal `d{12}` and rejected every real layer ARN. The existing test only covered an over-long name, which is why it passed. Escapes the backslash and adds the coverage that would have caught it: a real layer ARN and a bare layer name are both accepted, and an ARN whose account segment is not twelve digits is rejected. * fix(lambda): reject empty code-source fields instead of ignoring them The mutual-exclusivity check used truthiness, so `imageUri` alongside `s3Bucket: ''` read as image-only while the create operation still forwarded the defined empty field to AWS. An empty string is meaningless for every code-source field, so each is now `.min(1)` at the contract rather than special-cased in the refinement. * fix(lambda): reject empty optional strings across the Lambda contracts An empty `eventSourceArn` alongside bootstrap servers slipped past the mutual-exclusivity check for the same reason the code-source fields did: the guard tests truthiness, so a defined-but-empty value reads as absent while the operation still forwards it. Rather than patch each field as it surfaces, every optional string field now rejects an empty value. The tool layer already drops `''` before it reaches a contract, so an empty value can only arrive from a malformed direct call, and forwarding it to AWS is never right. `description` is exempt: AWS documents it as "Minimum length of 0", so an empty value legitimately clears it. Both behaviours are covered by tests. * fix(lambda): stop rejecting values AWS documents as valid A comprehensive validation pass against the API reference found the previous commit's blanket "no empty optional strings" rule was wrong. Several Lambda parameters document an empty string as meaningful, and their patterns say so: KMSKeyArn, SourceKMSKeyArn, and DeadLetterConfig.TargetArn all carry `(arn:...)|()`, whose trailing alternative matches the empty string, and the on-success/on-failure destinations document `Minimum length of 0` with a pattern beginning `$|`. For each, empty is how the setting is cleared. The rule is now opt-in rather than opt-out: only the five fields feeding a truthiness-based cross-field check reject an empty value. That removes 47 constraints and leaves the ones that were actually reported. Also from the same pass: - Supplying an image URI no longer demands an explicit `packageType`. That subBlock is advanced with no default, so requiring it produced a 400 naming a control the user cannot see; the operation derives Image from the code source instead, and only an explicit Zip alongside an image is rejected. - `fileSystemConfigs` was the one projection without a null guard, so an omitted field vanished from the block output rather than reading null. - An absent function URL now maps to null instead of an empty string a workflow could build a request against. - GetFunction reports `tagsError`, so a partial tag-read failure is distinguishable from a function with no tags, and marks `configuration` nullable to match what the operation returns. - Event source mappings report `selfManagedKafkaBootstrapServers`, which could be set but never read back. - TagResource rejects an empty tag map instead of reporting "0 tags applied". * test(lambda): prove every projection matches its contract schema Reading code confirmed the projections and schemas agree, but nothing ran them against each other. This runs all eight shared mappers against their schemas in both directions: every declared key is emitted and non-undefined, no undeclared key is emitted, and the result parses — for an empty AWS response, which is the common case, and for a fully-populated one. Verified the suite fails when either defect class is reintroduced: a mapper that stops emitting a declared key, and a projection that leaks `undefined` where the schema declares a value.
Summary
@aws-sdk/client-lambda; every request and response is contract-bound, with shared response projections for the FunctionConfiguration, alias, event source mapping, function URL, provisioned concurrency, and layer types.zipupload is not supported, and the docs page says soType of Change
Testing
bun run type-checkclean; all 38check:auditspass, includingcheck:api-validation:strict,docs:check,integration-catalog:check,check:tool-request-boundary, andcheck:bare-iconsChecklist