diff --git a/src/constructs/core/identity.test.ts b/src/constructs/core/identity.test.ts index 03da4be62..b9f0c7112 100644 --- a/src/constructs/core/identity.test.ts +++ b/src/constructs/core/identity.test.ts @@ -23,9 +23,9 @@ describe("AppIdentity.suffixText", () => { expect(actual).toEqual(expected); }); - it("should handle hyphens", () => { + it("should handle non-alphanumeric characters (e.g. hyphens)", () => { const actual = AppIdentity.suffixText({ app: "my-app" }, "InstanceType"); - const expected = "InstanceTypeMy-app"; + const expected = "InstanceTypeMyapp"; expect(actual).toEqual(expected); }); }); diff --git a/src/constructs/core/identity.ts b/src/constructs/core/identity.ts index 0605fa194..be467e2b9 100644 --- a/src/constructs/core/identity.ts +++ b/src/constructs/core/identity.ts @@ -15,7 +15,9 @@ export interface Identity extends StackStageIdentity, AppIdentity {} export const AppIdentity = { suffixText(appIdentity: AppIdentity, text: string): string { const titleCaseApp = appIdentity.app.charAt(0).toUpperCase() + appIdentity.app.slice(1); - return `${text}${titleCaseApp}`; + // CloudFormation Logical Ids must be alphanumeric, so remove any non-alphanumeric characters: https://stackoverflow.com/a/20864946 + const alphanumericTitleCaseApp = titleCaseApp.replace(/[\W_]+/g, ""); + return `${text}${alphanumericTitleCaseApp}`; }, taggedConstruct(appIdentity: AppIdentity, construct: T): T { Tags.of(construct).add("App", appIdentity.app); diff --git a/src/constructs/iam/roles/__snapshots__/instance-role.test.ts.snap b/src/constructs/iam/roles/__snapshots__/instance-role.test.ts.snap index 1eda9d6a7..08b07507e 100644 --- a/src/constructs/iam/roles/__snapshots__/instance-role.test.ts.snap +++ b/src/constructs/iam/roles/__snapshots__/instance-role.test.ts.snap @@ -274,16 +274,16 @@ Object { "PolicyName": "describe-ec2-policy", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-first-app", + "Ref": "InstanceRoleMyfirstapp", }, Object { - "Ref": "InstanceRoleMy-second-app", + "Ref": "InstanceRoleMysecondapp", }, ], }, "Type": "AWS::IAM::Policy", }, - "GetDistributablePolicyMyfirstapp9CD90B92": Object { + "GetDistributablePolicyMyfirstappB56CBAB1": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -310,16 +310,16 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "GetDistributablePolicyMyfirstapp9CD90B92", + "PolicyName": "GetDistributablePolicyMyfirstappB56CBAB1", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-first-app", + "Ref": "InstanceRoleMyfirstapp", }, ], }, "Type": "AWS::IAM::Policy", }, - "GetDistributablePolicyMysecondappA8D9FE69": Object { + "GetDistributablePolicyMysecondapp5096BFDB": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -346,10 +346,10 @@ Object { ], "Version": "2012-10-17", }, - "PolicyName": "GetDistributablePolicyMysecondappA8D9FE69", + "PolicyName": "GetDistributablePolicyMysecondapp5096BFDB", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-second-app", + "Ref": "InstanceRoleMysecondapp", }, ], }, @@ -391,16 +391,16 @@ Object { "PolicyName": "GuLogShippingPolicy981BFE5A", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-first-app", + "Ref": "InstanceRoleMyfirstapp", }, Object { - "Ref": "InstanceRoleMy-second-app", + "Ref": "InstanceRoleMysecondapp", }, ], }, "Type": "AWS::IAM::Policy", }, - "InstanceRoleMy-first-app": Object { + "InstanceRoleMyfirstapp": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -448,7 +448,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "InstanceRoleMy-second-app": Object { + "InstanceRoleMysecondapp": Object { "Properties": Object { "AssumeRolePolicyDocument": Object { "Statement": Array [ @@ -496,7 +496,7 @@ Object { }, "Type": "AWS::IAM::Role", }, - "ParameterStoreReadMyfirstappBCF3BB3A": Object { + "ParameterStoreReadMyfirstappE5C5C329": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -530,13 +530,13 @@ Object { "PolicyName": "parameter-store-read-policy", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-first-app", + "Ref": "InstanceRoleMyfirstapp", }, ], }, "Type": "AWS::IAM::Policy", }, - "ParameterStoreReadMysecondapp7B80ABE2": Object { + "ParameterStoreReadMysecondapp76C0E32C": Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ @@ -570,7 +570,7 @@ Object { "PolicyName": "parameter-store-read-policy", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-second-app", + "Ref": "InstanceRoleMysecondapp", }, ], }, @@ -606,10 +606,10 @@ Object { "PolicyName": "ssm-run-command-policy", "Roles": Array [ Object { - "Ref": "InstanceRoleMy-first-app", + "Ref": "InstanceRoleMyfirstapp", }, Object { - "Ref": "InstanceRoleMy-second-app", + "Ref": "InstanceRoleMysecondapp", }, ], },