Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lambda): Validate Lambda "functionName" parameter #17970

Merged
merged 8 commits into from
Feb 17, 2022
19 changes: 18 additions & 1 deletion packages/@aws-cdk/aws-lambda/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
import * as logs from '@aws-cdk/aws-logs';
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';
Expand Down Expand Up @@ -690,6 +690,15 @@ export class Function extends FunctionBase {
}
this._architecture = props.architecture ?? (props.architectures && props.architectures[0]);

if (props.functionName && !Token.isUnresolved(props.functionName)) {
if (props.functionName.length > 140) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this says that the length cannot be greater than 64 characters. Where are you gettintg the 140 from?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps the 140 comes from here? @Dzhuneyt do you think you can help investigate the correct length here? #18795

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed that the number is 64 here. Going to update this PR accordingly.

throw new Error('Function name can not be longer than 140 characters.');
}
if (!this.validateFunctionName(props.functionName)) {
throw new Error('Function name can contain only letters, numbers, hyphens, or underscores with no spaces.');
}
}

const resource: CfnFunction = new CfnFunction(this, 'Resource', {
functionName: this.physicalName,
description: props.description,
Expand Down Expand Up @@ -1084,6 +1093,14 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett
throw new Error('AWS_CODEGURU_PROFILER_GROUP_ARN and AWS_CODEGURU_PROFILER_ENABLED must not be set when profiling options enabled');
}
}

/**
* Validate if the string contains only letters, numbers, hyphens, underscore but no spaces
*/
private validateFunctionName(functionName: string) {
const regexp = /^[a-zA-Z0-9-_]+$/;
return functionName.search(regexp) !== -1;
}
}

/**
Expand Down
40 changes: 40 additions & 0 deletions packages/@aws-cdk/aws-lambda/test/function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as signer from '@aws-cdk/aws-signer';
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';
Expand Down Expand Up @@ -2278,6 +2279,45 @@ describe('function', () => {
});
expect(fn.architecture?.name).toEqual('arm64');
});

test('Error when function name is longer than 140 chars', () => {
const stack = new cdk.Stack();
expect(() => new lambda.Function(stack, 'MyFunction', {
code: lambda.Code.fromInline('foo'),
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'index.handler',
functionName: 'a'.repeat(141),
})).toThrow(/Function name can not be longer than 140 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_10_X,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this runtime has an end-of-life set for 2/14/22. lets use Node 12 or 14.

functionName: `foo${invalidChar}`,
});
}).toThrow(/Function name 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_10_X,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

functionName: tokenizedFunctionName,
});
}).not.toThrow();
});
});

function newTestLambda(scope: constructs.Construct) {
Expand Down