From a220ae4336f153964d1f338000333b3451b1a605 Mon Sep 17 00:00:00 2001 From: Amir Szekely Date: Mon, 5 Jan 2026 23:24:12 +0000 Subject: [PATCH 1/6] fix(ecs): stack name can result in noncompliant capacity provider name Previsouly fixed with #29235 but only for lower case stack names. The error could still be reproduced with stack names starting with `Ecs` or `AWS`, etc. ``` const app = new cdk.App(); const stack = new cdk.Stack(app, 'EcsCp'); const vpc = new ec2.Vpc(stack, 'Vpc'); const cluster = new ecs.Cluster(stack, 'EcsCluster'); const autoScalingGroupAl2 = new autoscaling.AutoScalingGroup(stack, 'asgal2', { vpc, instanceType: new ec2.InstanceType('bogus'), machineImage: ecs.EcsOptimizedImage.amazonLinux2(), }); const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provideral2-2', { autoScalingGroup: autoScalingGroupAl2, enableManagedTerminationProtection: false, }); ``` Deploying the code above will result in: ``` Resource handler returned message: "Invalid request provided: CreateCapacityProvider error: The specified capacity provider name is invalid. Up to 255 characters are allowed, including letters (upper and lowercase), numbers, underscores, and hyphens. The name cannot be prefixed with "aws", "ecs", or "fargate". Specify a valid name and try again. (Service: Ecs, Status Code: 400, Request ID: 6c28bb07-463b-497a-9e18-046f8ef58de0) (SDK Attempt Count: 1)" (RequestToken: 2e19581f-7343-6fda-588e-94cbe50066d1, HandlerErrorCode: InvalidRequest) ``` Fixes #29151 --- packages/aws-cdk-lib/aws-ecs/lib/cluster.ts | 4 +-- .../aws-cdk-lib/aws-ecs/test/cluster.test.ts | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts b/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts index 41f2c8f7f378f..a72cbadbbf7dc 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/cluster.ts @@ -1662,7 +1662,7 @@ export class ManagedInstancesCapacityProvider extends Construct implements ec2.I // Handle capacity provider name generation similar to AsgCapacityProvider let capacityProviderName = props.capacityProviderName; - const capacityProviderNameRegex = /^(?!aws|ecs|fargate).+/gm; + const capacityProviderNameRegex = /^(?!aws|ecs|fargate).+/gmi; if (capacityProviderName) { if (!(capacityProviderNameRegex.test(capacityProviderName))) { throw new ValidationError(`Invalid Capacity Provider Name: ${capacityProviderName}, If a name is specified, it cannot start with aws, ecs, or fargate.`, this); @@ -1962,7 +1962,7 @@ export class AsgCapacityProvider extends Construct { } } - const capacityProviderNameRegex = /^(?!aws|ecs|fargate).+/gm; + const capacityProviderNameRegex = /^(?!aws|ecs|fargate).+/gmi; if (capacityProviderName) { if (!(capacityProviderNameRegex.test(capacityProviderName))) { throw new ValidationError(`Invalid Capacity Provider Name: ${capacityProviderName}, If a name is specified, it cannot start with aws, ecs, or fargate.`, this); diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index 5766bddee2808..d2614bcd36352 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -4810,6 +4810,40 @@ test('throws when ASG Capacity Provider with no capacityProviderName but stack n cluster.addAsgCapacityProvider(capacityProvider); }).not.toThrow(); + + // Verify the capacity provider name is set and starts with 'cp-' + Template.fromStack(stack).hasResourceProperties('AWS::ECS::CapacityProvider', { + Name: Match.stringLikeRegexp('^cp-'), + }); +}); + +test('throws when ASG Capacity Provider with no capacityProviderName but stack name starting with ECS (case-insensitive)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'EcsCp'); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + const autoScalingGroupAl2 = new autoscaling.AutoScalingGroup(stack, 'asgal2', { + vpc, + instanceType: new ec2.InstanceType('bogus'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(), + }); + + expect(() => { + // WHEN Capacity Provider when stack name starts with ECS (uppercase). + const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provideral2-2', { + autoScalingGroup: autoScalingGroupAl2, + enableManagedTerminationProtection: false, + }); + + cluster.addAsgCapacityProvider(capacityProvider); + }).not.toThrow(); + + // Verify the capacity provider name is set and starts with 'cp-' + Template.fromStack(stack).hasResourceProperties('AWS::ECS::CapacityProvider', { + Name: Match.stringLikeRegexp('^cp-'), + }); }); test('throws when InstanceWarmupPeriod is less than 0', () => { From c53ecf839bc3fc4fab6961c7e3a0441bd0770eeb Mon Sep 17 00:00:00 2001 From: Amir Szekely Date: Thu, 29 Jan 2026 10:21:32 -0500 Subject: [PATCH 2/6] fix test names --- packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index 6a06db2c33018..42426fbe74830 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -5091,7 +5091,7 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with }).toThrow(/Invalid Capacity Provider Name: ecscp, If a name is specified, it cannot start with aws, ecs, or fargate./); }); -test('throws when ASG Capacity Provider with no capacityProviderName but stack name starting with aws, ecs or fargate', () => { +test('does not throw and sets a proper capacity provider name when ASG Capacity Provider with no capacityProviderName but stack name starting with aws, ecs or fargate', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'ecscp'); @@ -5120,7 +5120,7 @@ test('throws when ASG Capacity Provider with no capacityProviderName but stack n }); }); -test('throws when ASG Capacity Provider with no capacityProviderName but stack name starting with ECS (case-insensitive)', () => { +test('does not throw and sets a proper capacity provider name when ASG Capacity Provider with no capacityProviderName but stack name starting with ECS (case-insensitive)', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'EcsCp'); From 4976199e7175de57175f9c1984698a78f45c97cc Mon Sep 17 00:00:00 2001 From: Amir Szekely Date: Fri, 30 Jan 2026 16:12:20 +0000 Subject: [PATCH 3/6] add exception tests --- .../aws-cdk-lib/aws-ecs/test/cluster.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index 42426fbe74830..b350c41fea692 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -5089,6 +5089,28 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with cluster.addAsgCapacityProvider(capacityProviderAl2); }).toThrow(/Invalid Capacity Provider Name: ecscp, If a name is specified, it cannot start with aws, ecs, or fargate./); + + expect(() => { + // WHEN Capacity Provider define capacityProviderName start with Aws. + const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-3', { + autoScalingGroup: autoScalingGroupAl2, + enableManagedTerminationProtection: false, + capacityProviderName: 'AwsCp', + }); + + cluster.addAsgCapacityProvider(capacityProviderAl2); + }).toThrow(/Invalid Capacity Provider Name: AwsCp, If a name is specified, it cannot start with aws, ecs, or fargate./); + + expect(() => { + // WHEN Capacity Provider define capacityProviderName start with Ecs. + const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-4', { + autoScalingGroup: autoScalingGroupAl2, + enableManagedTerminationProtection: false, + capacityProviderName: 'EcsCp', + }); + + cluster.addAsgCapacityProvider(capacityProviderAl2); + }).toThrow(/Invalid Capacity Provider Name: EcsCp, If a name is specified, it cannot start with aws, ecs, or fargate./); }); test('does not throw and sets a proper capacity provider name when ASG Capacity Provider with no capacityProviderName but stack name starting with aws, ecs or fargate', () => { From 62cb68b412c92b11c21bac9b6ac64356798e8ec8 Mon Sep 17 00:00:00 2001 From: Amir Szekely Date: Tue, 3 Feb 2026 14:52:56 +0000 Subject: [PATCH 4/6] cover fargate case --- .../aws-cdk-lib/aws-ecs/test/cluster.test.ts | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index b350c41fea692..4babba86c3406 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -5091,8 +5091,19 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with }).toThrow(/Invalid Capacity Provider Name: ecscp, If a name is specified, it cannot start with aws, ecs, or fargate./); expect(() => { - // WHEN Capacity Provider define capacityProviderName start with Aws. + // WHEN Capacity Provider define capacityProviderName start with ecs. const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-3', { + autoScalingGroup: autoScalingGroupAl2, + enableManagedTerminationProtection: false, + capacityProviderName: 'fargatecp', + }); + + cluster.addAsgCapacityProvider(capacityProviderAl2); + }).toThrow(/Invalid Capacity Provider Name: fargatecp, If a name is specified, it cannot start with aws, ecs, or fargate./); + + expect(() => { + // WHEN Capacity Provider define capacityProviderName start with Aws. + const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-4', { autoScalingGroup: autoScalingGroupAl2, enableManagedTerminationProtection: false, capacityProviderName: 'AwsCp', @@ -5103,7 +5114,7 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with expect(() => { // WHEN Capacity Provider define capacityProviderName start with Ecs. - const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-4', { + const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-5', { autoScalingGroup: autoScalingGroupAl2, enableManagedTerminationProtection: false, capacityProviderName: 'EcsCp', @@ -5111,6 +5122,17 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with cluster.addAsgCapacityProvider(capacityProviderAl2); }).toThrow(/Invalid Capacity Provider Name: EcsCp, If a name is specified, it cannot start with aws, ecs, or fargate./); + + expect(() => { + // WHEN Capacity Provider define capacityProviderName start with Ecs. + const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-6', { + autoScalingGroup: autoScalingGroupAl2, + enableManagedTerminationProtection: false, + capacityProviderName: 'FargateCp', + }); + + cluster.addAsgCapacityProvider(capacityProviderAl2); + }).toThrow(/Invalid Capacity Provider Name: FargateCp, If a name is specified, it cannot start with aws, ecs, or fargate./); }); test('does not throw and sets a proper capacity provider name when ASG Capacity Provider with no capacityProviderName but stack name starting with aws, ecs or fargate', () => { From f3e642cedf687dbff8ad326b3e0d4e1fb81f2331 Mon Sep 17 00:00:00 2001 From: Amir Szekely Date: Wed, 4 Feb 2026 10:05:04 -0500 Subject: [PATCH 5/6] typo Co-authored-by: Luca Pizzini --- packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index 4babba86c3406..b819d35cee1a7 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -5091,7 +5091,7 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with }).toThrow(/Invalid Capacity Provider Name: ecscp, If a name is specified, it cannot start with aws, ecs, or fargate./); expect(() => { - // WHEN Capacity Provider define capacityProviderName start with ecs. + // WHEN Capacity Provider define capacityProviderName start with fargate. const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-3', { autoScalingGroup: autoScalingGroupAl2, enableManagedTerminationProtection: false, From c97aecd7a798452ed45ee88fd6c3cce2472c4b77 Mon Sep 17 00:00:00 2001 From: Amir Szekely Date: Wed, 4 Feb 2026 10:05:16 -0500 Subject: [PATCH 6/6] typo Co-authored-by: Luca Pizzini --- packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index b819d35cee1a7..9cf1935934262 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -5124,7 +5124,7 @@ test('throws when ASG Capacity Provider with capacityProviderName starting with }).toThrow(/Invalid Capacity Provider Name: EcsCp, If a name is specified, it cannot start with aws, ecs, or fargate./); expect(() => { - // WHEN Capacity Provider define capacityProviderName start with Ecs. + // WHEN Capacity Provider define capacityProviderName start with Fargate. const capacityProviderAl2 = new ecs.AsgCapacityProvider(stack, 'provideral2-6', { autoScalingGroup: autoScalingGroupAl2, enableManagedTerminationProtection: false,