From a416a2d68f14c0711d42b38e81b0091d160dfd6f Mon Sep 17 00:00:00 2001 From: Dzhuneyt <1754428+Dzhuneyt@users.noreply.github.com> Date: Thu, 17 Feb 2022 23:39:35 +0200 Subject: [PATCH] fix(lambda): Validate Lambda "functionName" parameter (#17970) Closes #13264 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-lambda/lib/function.ts | 11 ++++- .../@aws-cdk/aws-lambda/test/function.test.ts | 40 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index d79371ec5f208..979923c093be0 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -6,7 +6,7 @@ import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; -import { Annotations, ArnFormat, CfnResource, Duration, Fn, Lazy, Names, Stack } from '@aws-cdk/core'; +import { Annotations, ArnFormat, CfnResource, Duration, Fn, Lazy, Names, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Architecture } from './architecture'; import { Code, CodeConfig } from './code'; @@ -627,6 +627,15 @@ export class Function extends FunctionBase { physicalName: props.functionName, }); + if (props.functionName && !Token.isUnresolved(props.functionName)) { + if (props.functionName.length > 64) { + throw new Error(`Function name can not be longer than 64 characters but has ${props.functionName.length} characters.`); + } + if (!/^[a-zA-Z0-9-_]+$/.test(props.functionName)) { + throw new Error(`Function name ${props.functionName} can contain only letters, numbers, hyphens, or underscores with no spaces.`); + } + } + const managedPolicies = new Array(); // the arn is in the form of - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index 3565af167cc23..9e71b4c0608d0 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -12,6 +12,7 @@ import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; +import { Intrinsic, Token } from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as _ from 'lodash'; import * as lambda from '../lib'; @@ -2404,6 +2405,45 @@ describe('function', () => { }); expect(fn.architecture?.name).toEqual('arm64'); }); + + test('Error when function name is longer than 64 chars', () => { + const stack = new cdk.Stack(); + expect(() => new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + functionName: 'a'.repeat(65), + })).toThrow(/Function name can not be longer than 64 characters/); + }); + + test('Error when function name contains invalid characters', () => { + const stack = new cdk.Stack(); + [' ', '\n', '\r', '[', ']', '<', '>', '$'].forEach(invalidChar => { + expect(() => { + new lambda.Function(stack, `foo${invalidChar}`, { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + functionName: `foo${invalidChar}`, + }); + }).toThrow(/can contain only letters, numbers, hyphens, or underscores with no spaces./); + }); + }); + + test('No error when function name is Tokenized and Unresolved', () => { + const stack = new cdk.Stack(); + expect(() => { + const realFunctionName = 'a'.repeat(141); + const tokenizedFunctionName = Token.asString(new Intrinsic(realFunctionName)); + + new lambda.Function(stack, 'foo', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_14_X, + functionName: tokenizedFunctionName, + }); + }).not.toThrow(); + }); }); function newTestLambda(scope: constructs.Construct) {