Skip to content

Commit ea9a81b

Browse files
committed
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.
1 parent d6f01fe commit ea9a81b

3 files changed

Lines changed: 29 additions & 10 deletions

File tree

apps/sim/lib/api/contracts/tools/aws/lambda-create-function.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ const CreateFunctionSchema = z
2121
runtime: z.string().optional(),
2222
handler: z.string().optional(),
2323
packageType: z.enum(['Zip', 'Image']).optional(),
24-
s3Bucket: z.string().optional(),
25-
s3Key: z.string().optional(),
26-
s3ObjectVersion: z.string().optional(),
27-
imageUri: z.string().optional(),
28-
sourceKmsKeyArn: z.string().optional(),
24+
s3Bucket: z.string().min(1, 's3Bucket cannot be empty').optional(),
25+
s3Key: z.string().min(1, 's3Key cannot be empty').optional(),
26+
s3ObjectVersion: z.string().min(1, 's3ObjectVersion cannot be empty').optional(),
27+
imageUri: z.string().min(1, 'imageUri cannot be empty').optional(),
28+
sourceKmsKeyArn: z.string().min(1, 'sourceKmsKeyArn cannot be empty').optional(),
2929
description: z.string().max(256, 'description cannot exceed 256 characters').optional(),
3030
functionTimeout: z.number().int().min(1).max(900).optional(),
3131
memorySize: z.number().int().min(128).max(32768).optional(),

apps/sim/lib/api/contracts/tools/aws/lambda-update-function-code.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ const UpdateFunctionCodeSchema = z
1717
.string()
1818
.min(1, 'functionName is required')
1919
.max(256, 'functionName cannot exceed 256 characters'),
20-
s3Bucket: z.string().optional(),
21-
s3Key: z.string().optional(),
22-
s3ObjectVersion: z.string().optional(),
23-
imageUri: z.string().optional(),
24-
sourceKmsKeyArn: z.string().optional(),
20+
s3Bucket: z.string().min(1, 's3Bucket cannot be empty').optional(),
21+
s3Key: z.string().min(1, 's3Key cannot be empty').optional(),
22+
s3ObjectVersion: z.string().min(1, 's3ObjectVersion cannot be empty').optional(),
23+
imageUri: z.string().min(1, 'imageUri cannot be empty').optional(),
24+
sourceKmsKeyArn: z.string().min(1, 'sourceKmsKeyArn cannot be empty').optional(),
2525
architectures: z
2626
.array(z.enum(['x86_64', 'arm64']))
2727
.length(1, 'architectures takes exactly one value')

apps/sim/lib/internal/lambda/execute-tool.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,25 @@ describe('executeLambdaTool', () => {
528528
expect(JSON.stringify(await response.json())).toContain('not both')
529529
})
530530

531+
it('rejects an empty code-source field rather than treating it as absent', async () => {
532+
const response = await executeLambdaTool(
533+
createRequest({
534+
toolId: 'lambda_create_function',
535+
input: {
536+
...CONNECTION,
537+
functionName: 'alpha',
538+
role: 'arn:aws:iam::1:role/exec',
539+
imageUri: 'ecr/alpha:1',
540+
packageType: 'Image',
541+
s3Bucket: '',
542+
},
543+
})
544+
)
545+
546+
expect(response.status).toBe(400)
547+
expect(mockOperations.executeLambdaCreateFunction).not.toHaveBeenCalled()
548+
})
549+
531550
it('rejects a partial S3 pair alongside an image URI', async () => {
532551
const response = await executeLambdaTool(
533552
createRequest({

0 commit comments

Comments
 (0)