Skip to content

Commit 9185042

Browse files
authored
fix(codedeploy): add name validation for Application, Deployment Group and Deployment Configuration (#19473)
- Naming rules from: https://docs.aws.amazon.com/codedeploy/latest/userguide/limits.html ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](../CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](../CONTRIBUTING.md/#adding-new-unconventional-dependencies) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 77a5fa1 commit 9185042

14 files changed

+184
-8
lines changed

Diff for: packages/@aws-cdk/aws-codedeploy/lib/ecs/application.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ArnFormat, IResource, Resource } from '@aws-cdk/core';
22
import { Construct } from 'constructs';
33
import { CfnApplication } from '../codedeploy.generated';
4-
import { arnForApplication } from '../utils';
4+
import { arnForApplication, validateName } from '../utils';
55

66
/**
77
* Represents a reference to a CodeDeploy Application deploying to Amazon ECS.
@@ -77,4 +77,8 @@ export class EcsApplication extends Resource implements IEcsApplication {
7777
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
7878
});
7979
}
80+
81+
protected validate(): string[] {
82+
return validateName('Application', this.physicalName);
83+
}
8084
}

Diff for: packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ArnFormat, IResource, Resource } from '@aws-cdk/core';
22
import { Construct } from 'constructs';
33
import { CfnApplication } from '../codedeploy.generated';
4-
import { arnForApplication } from '../utils';
4+
import { arnForApplication, validateName } from '../utils';
55

66
/**
77
* Represents a reference to a CodeDeploy Application deploying to AWS Lambda.
@@ -77,4 +77,8 @@ export class LambdaApplication extends Resource implements ILambdaApplication {
7777
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
7878
});
7979
}
80+
81+
protected validate(): string[] {
82+
return validateName('Application', this.physicalName);
83+
}
8084
}

Diff for: packages/@aws-cdk/aws-codedeploy/lib/lambda/custom-deployment-config.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Duration, Names, Resource } from '@aws-cdk/core';
22
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources';
33
import { Construct } from 'constructs';
4-
import { arnForDeploymentConfig } from '../utils';
4+
import { arnForDeploymentConfig, validateName } from '../utils';
55
import { ILambdaDeploymentConfig } from './deployment-config';
66

77
/**
@@ -143,6 +143,10 @@ export class CustomLambdaDeploymentConfig extends Resource implements ILambdaDep
143143
});
144144
}
145145

146+
protected validate(): string[] {
147+
return validateName('Deployment config', this.deploymentConfigName);
148+
}
149+
146150
// Validate the inputs. The percentage/interval limits come from CodeDeploy
147151
private validateParameters(props: CustomLambdaDeploymentConfigProps): void {
148152
if ( !(1 <= props.percentage && props.percentage <= 99) ) {

Diff for: packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as cdk from '@aws-cdk/core';
55
import { Construct } from 'constructs';
66
import { CfnDeploymentGroup } from '../codedeploy.generated';
77
import { AutoRollbackConfig } from '../rollback-config';
8-
import { arnForDeploymentGroup, renderAlarmConfiguration, renderAutoRollbackConfiguration } from '../utils';
8+
import { arnForDeploymentGroup, renderAlarmConfiguration, renderAutoRollbackConfiguration, validateName } from '../utils';
99
import { ILambdaApplication, LambdaApplication } from './application';
1010
import { ILambdaDeploymentConfig, LambdaDeploymentConfig } from './deployment-config';
1111

@@ -254,6 +254,10 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy
254254
actions: ['codedeploy:PutLifecycleEventHookExecutionStatus'],
255255
});
256256
}
257+
258+
protected validate(): string[] {
259+
return validateName('Deployment group', this.physicalName);
260+
}
257261
}
258262

259263
/**

Diff for: packages/@aws-cdk/aws-codedeploy/lib/server/application.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ArnFormat, IResource, Resource } from '@aws-cdk/core';
22
import { Construct } from 'constructs';
33
import { CfnApplication } from '../codedeploy.generated';
4-
import { arnForApplication } from '../utils';
4+
import { arnForApplication, validateName } from '../utils';
55

66
/**
77
* Represents a reference to a CodeDeploy Application deploying to EC2/on-premise instances.
@@ -78,4 +78,8 @@ export class ServerApplication extends Resource implements IServerApplication {
7878
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
7979
});
8080
}
81+
82+
protected validate(): string[] {
83+
return validateName('Application', this.physicalName);
84+
}
8185
}

Diff for: packages/@aws-cdk/aws-codedeploy/lib/server/deployment-config.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as cdk from '@aws-cdk/core';
22
import { Construct } from 'constructs';
33
import { CfnDeploymentConfig } from '../codedeploy.generated';
4-
import { arnForDeploymentConfig } from '../utils';
4+
import { arnForDeploymentConfig, validateName } from '../utils';
55

66
/**
77
* The Deployment Configuration of an EC2/on-premise Deployment Group.
@@ -119,6 +119,10 @@ export class ServerDeploymentConfig extends cdk.Resource implements IServerDeplo
119119
this.deploymentConfigName = resource.ref;
120120
this.deploymentConfigArn = arnForDeploymentConfig(this.deploymentConfigName);
121121
}
122+
123+
protected validate(): string[] {
124+
return validateName('Deployment config', this.physicalName);
125+
}
122126
}
123127

124128
function deploymentConfig(name: string): IServerDeploymentConfig {

Diff for: packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ArnFormat } from '@aws-cdk/core';
88
import { Construct } from 'constructs';
99
import { CfnDeploymentGroup } from '../codedeploy.generated';
1010
import { AutoRollbackConfig } from '../rollback-config';
11-
import { arnForDeploymentGroup, renderAlarmConfiguration, renderAutoRollbackConfiguration } from '../utils';
11+
import { arnForDeploymentGroup, renderAlarmConfiguration, renderAutoRollbackConfiguration, validateName } from '../utils';
1212
import { IServerApplication, ServerApplication } from './application';
1313
import { IServerDeploymentConfig, ServerDeploymentConfig } from './deployment-config';
1414
import { LoadBalancer, LoadBalancerGeneration } from './load-balancer';
@@ -341,6 +341,10 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase {
341341
return this._autoScalingGroups.slice();
342342
}
343343

344+
protected validate(): string[] {
345+
return validateName('Deployment group', this.physicalName);
346+
}
347+
344348
private addCodeDeployAgentInstallUserData(asg: autoscaling.IAutoScalingGroup): void {
345349
if (!this.installAgent) {
346350
return;

Diff for: packages/@aws-cdk/aws-codedeploy/lib/utils.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
2-
import { Aws } from '@aws-cdk/core';
2+
import { Aws, Token } from '@aws-cdk/core';
33
import { CfnDeploymentGroup } from './codedeploy.generated';
44
import { AutoRollbackConfig } from './rollback-config';
55

@@ -65,3 +65,18 @@ CfnDeploymentGroup.AutoRollbackConfigurationProperty | undefined {
6565
}
6666
: undefined;
6767
}
68+
69+
export function validateName(type: 'Application' | 'Deployment group' | 'Deployment config', name: string): string[] {
70+
const ret = [];
71+
72+
if (!Token.isUnresolved(name) && name !== undefined) {
73+
if (name.length > 100) {
74+
ret.push(`${type} name: "${name}" can be a max of 100 characters.`);
75+
}
76+
if (!/^[a-z0-9._+=,@-]+$/i.test(name)) {
77+
ret.push(`${type} name: "${name}" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).`);
78+
}
79+
}
80+
81+
return ret;
82+
}

Diff for: packages/@aws-cdk/aws-codedeploy/test/ecs/application.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,24 @@ describe('CodeDeploy ECS Application', () => {
2323
ComputePlatform: 'ECS',
2424
});
2525
});
26+
27+
test('fail with more than 100 characters in name', () => {
28+
const app = new cdk.App();
29+
const stack = new cdk.Stack(app);
30+
new codedeploy.EcsApplication(stack, 'MyApp', {
31+
applicationName: 'a'.repeat(101),
32+
});
33+
34+
expect(() => app.synth()).toThrow(`Application name: "${'a'.repeat(101)}" can be a max of 100 characters.`);
35+
});
36+
37+
test('fail with unallowed characters in name', () => {
38+
const app = new cdk.App();
39+
const stack = new cdk.Stack(app);
40+
new codedeploy.EcsApplication(stack, 'MyApp', {
41+
applicationName: 'my name',
42+
});
43+
44+
expect(() => app.synth()).toThrow('Application name: "my name" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).');
45+
});
2646
});

Diff for: packages/@aws-cdk/aws-codedeploy/test/lambda/application.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,24 @@ describe('CodeDeploy Lambda Application', () => {
2121
ComputePlatform: 'Lambda',
2222
});
2323
});
24+
25+
test('fail with more than 100 characters in name', () => {
26+
const app = new cdk.App();
27+
const stack = new cdk.Stack(app);
28+
new codedeploy.LambdaApplication(stack, 'MyApp', {
29+
applicationName: 'a'.repeat(101),
30+
});
31+
32+
expect(() => app.synth()).toThrow(`Application name: "${'a'.repeat(101)}" can be a max of 100 characters.`);
33+
});
34+
35+
test('fail with unallowed characters in name', () => {
36+
const app = new cdk.App();
37+
const stack = new cdk.Stack(app);
38+
new codedeploy.LambdaApplication(stack, 'MyApp', {
39+
applicationName: 'my name',
40+
});
41+
42+
expect(() => app.synth()).toThrow('Application name: "my name" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).');
43+
});
2444
});

Diff for: packages/@aws-cdk/aws-codedeploy/test/lambda/custom-deployment-config.test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,32 @@ test('custom resource created with specific name', () => {
9797
});
9898
});
9999

100+
test('fail with more than 100 characters in name', () => {
101+
const app = new cdk.App();
102+
const stackWithApp = new cdk.Stack(app);
103+
new codedeploy.CustomLambdaDeploymentConfig(stackWithApp, 'CustomConfig', {
104+
type: codedeploy.CustomLambdaDeploymentConfigType.CANARY,
105+
interval: cdk.Duration.minutes(1),
106+
percentage: 5,
107+
deploymentConfigName: 'a'.repeat(101),
108+
});
109+
110+
expect(() => app.synth()).toThrow(`Deployment config name: "${'a'.repeat(101)}" can be a max of 100 characters.`);
111+
});
112+
113+
test('fail with unallowed characters in name', () => {
114+
const app = new cdk.App();
115+
const stackWithApp = new cdk.Stack(app);
116+
new codedeploy.CustomLambdaDeploymentConfig(stackWithApp, 'CustomConfig', {
117+
type: codedeploy.CustomLambdaDeploymentConfigType.CANARY,
118+
interval: cdk.Duration.minutes(1),
119+
percentage: 5,
120+
deploymentConfigName: 'my name',
121+
});
122+
123+
expect(() => app.synth()).toThrow('Deployment config name: "my name" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).');
124+
});
125+
100126
test('can create linear custom config', () => {
101127
// WHEN
102128
const config = new codedeploy.CustomLambdaDeploymentConfig(stack, 'CustomConfig', {

Diff for: packages/@aws-cdk/aws-codedeploy/test/lambda/deployment-group.test.ts

+24
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,30 @@ describe('CodeDeploy Lambda DeploymentGroup', () => {
132132
});
133133
});
134134

135+
test('fail with more than 100 characters in name', () => {
136+
const app = new cdk.App();
137+
const stack = new cdk.Stack(app);
138+
const alias = mockAlias(stack);
139+
new codedeploy.LambdaDeploymentGroup(stack, 'MyDG', {
140+
alias,
141+
deploymentGroupName: 'a'.repeat(101),
142+
});
143+
144+
expect(() => app.synth()).toThrow(`Deployment group name: "${'a'.repeat(101)}" can be a max of 100 characters.`);
145+
});
146+
147+
test('fail with unallowed characters in name', () => {
148+
const app = new cdk.App();
149+
const stack = new cdk.Stack(app);
150+
const alias = mockAlias(stack);
151+
new codedeploy.LambdaDeploymentGroup(stack, 'MyDG', {
152+
alias,
153+
deploymentGroupName: 'my name',
154+
});
155+
156+
expect(() => app.synth()).toThrow('Deployment group name: "my name" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).');
157+
});
158+
135159
test('can be created with explicit role', () => {
136160
const stack = new cdk.Stack();
137161
const application = new codedeploy.LambdaApplication(stack, 'MyApp');

Diff for: packages/@aws-cdk/aws-codedeploy/test/server/deployment-config.test.ts

+22
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,26 @@ describe('CodeDeploy DeploymentConfig', () => {
4242

4343
expect(deploymentConfig).not.toEqual(undefined);
4444
});
45+
46+
test('fail with more than 100 characters in name', () => {
47+
const app = new cdk.App();
48+
const stack = new cdk.Stack(app);
49+
new codedeploy.ServerDeploymentConfig(stack, 'DeploymentConfig', {
50+
minimumHealthyHosts: codedeploy.MinimumHealthyHosts.percentage(75),
51+
deploymentConfigName: 'a'.repeat(101),
52+
});
53+
54+
expect(() => app.synth()).toThrow(`Deployment config name: "${'a'.repeat(101)}" can be a max of 100 characters.`);
55+
});
56+
57+
test('fail with unallowed characters in name', () => {
58+
const app = new cdk.App();
59+
const stack = new cdk.Stack(app);
60+
new codedeploy.ServerDeploymentConfig(stack, 'DeploymentConfig', {
61+
minimumHealthyHosts: codedeploy.MinimumHealthyHosts.percentage(75),
62+
deploymentConfigName: 'my name',
63+
});
64+
65+
expect(() => app.synth()).toThrow('Deployment config name: "my name" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).');
66+
});
4567
});

Diff for: packages/@aws-cdk/aws-codedeploy/test/server/deployment-group.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -437,4 +437,25 @@ describe('CodeDeploy Server Deployment Group', () => {
437437
});
438438
});
439439

440+
test('fail with more than 100 characters in name', () => {
441+
const app = new cdk.App();
442+
const stack = new cdk.Stack(app);
443+
new codedeploy.ServerDeploymentGroup(stack, 'MyDG', {
444+
deploymentGroupName: 'a'.repeat(101),
445+
});
446+
447+
expect(() => app.synth()).toThrow(`Deployment group name: "${'a'.repeat(101)}" can be a max of 100 characters.`);
448+
});
449+
450+
test('fail with unallowed characters in name', () => {
451+
const app = new cdk.App();
452+
const stack = new cdk.Stack(app);
453+
new codedeploy.ServerDeploymentGroup(stack, 'MyDG', {
454+
455+
deploymentGroupName: 'my name',
456+
});
457+
458+
expect(() => app.synth()).toThrow('Deployment group name: "my name" can only contain letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), + (plus signs), = (equals signs), , (commas), @ (at signs), - (minus signs).');
459+
});
460+
440461
});

0 commit comments

Comments
 (0)