From 2c8283782cca6e29b8c80109ed5ed62ef9e0a6c2 Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:14:30 +0900 Subject: [PATCH 1/5] feat(core): add validation for export name in CfnOutput --- packages/aws-cdk-lib/core/lib/cfn-output.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/core/lib/cfn-output.ts b/packages/aws-cdk-lib/core/lib/cfn-output.ts index 8f1bf310ddead..ccf8b69f7a031 100644 --- a/packages/aws-cdk-lib/core/lib/cfn-output.ts +++ b/packages/aws-cdk-lib/core/lib/cfn-output.ts @@ -178,8 +178,16 @@ export class CfnOutput extends CfnElement { } private validateOutput(): string[] { - if (this._exportName && !Token.isUnresolved(this._exportName) && this._exportName.length > 255) { - return [`Export name cannot exceed 255 characters (got ${this._exportName.length} characters)`]; + if (this._exportName !== undefined && !Token.isUnresolved(this._exportName)) { + if (this._exportName.length === 0) { + return ['Export name cannot be empty']; + } + if (this._exportName.length > 255) { + return [`Export name cannot exceed 255 characters (got ${this._exportName.length} characters)`]; + } + if (!/^[A-Za-z0-9-:]*$/.test(this._exportName)) { + return [`Export name must only include alphanumeric characters, colons, or hyphens (got '${this._exportName}')`]; + } } return []; } From 5f2912d40396c457376c305e041949852db5f071 Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:27:14 +0900 Subject: [PATCH 2/5] add unit tests --- packages/aws-cdk-lib/core/test/output.test.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/aws-cdk-lib/core/test/output.test.ts b/packages/aws-cdk-lib/core/test/output.test.ts index 335173bd944d4..22b9ce94a1494 100644 --- a/packages/aws-cdk-lib/core/test/output.test.ts +++ b/packages/aws-cdk-lib/core/test/output.test.ts @@ -143,4 +143,31 @@ describe('output', () => { expect.stringContaining('Export name cannot exceed 255 characters'), ]); }); + + test('Verify zero length of export name', () => { + const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: '' }); + const errors = output.node.validate(); + + expect(errors).toEqual([ + expect.stringContaining('Export name cannot be empty'), + ]); + }); + + test('throw if export name has invalid string (space)', () => { + const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: 'SOME INVALID EXPORT NAME' }); + const errors = output.node.validate(); + + expect(errors).toEqual([ + expect.stringContaining('Export name must only include alphanumeric characters, colons, or hyphens (got \'SOME INVALID EXPORT NAME\''), + ]); + }); + + test('throw if export name has invalid string (under_bar)', () => { + const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: 'SOME_INVALID_EXPORT_NAME' }); + const errors = output.node.validate(); + + expect(errors).toEqual([ + expect.stringContaining('Export name must only include alphanumeric characters, colons, or hyphens (got \'SOME_INVALID_EXPORT_NAME\''), + ]); + }); }); From bc1ddc8d857b2892f7069edd04828b34121c0812 Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:54:45 +0900 Subject: [PATCH 3/5] modify valid-templates.test.ts in aws-cdk-lib/cloudformation-include --- .../cloudformation-include/test/valid-templates.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/cloudformation-include/test/valid-templates.test.ts b/packages/aws-cdk-lib/cloudformation-include/test/valid-templates.test.ts index 3ed846172ac11..b6ff1bea6f681 100644 --- a/packages/aws-cdk-lib/cloudformation-include/test/valid-templates.test.ts +++ b/packages/aws-cdk-lib/cloudformation-include/test/valid-templates.test.ts @@ -727,7 +727,7 @@ describe('CDK Include', () => { const output = cfnTemplate.getOutput('Output1'); output.value = 'a mutated value'; output.description = undefined; - output.exportName = 'an export'; + output.exportName = 'an-export'; output.condition = new core.CfnCondition(stack, 'MyCondition', { expression: core.Fn.conditionIf('AlwaysFalseCond', core.Aws.NO_VALUE, true), }); @@ -755,7 +755,7 @@ describe('CDK Include', () => { "Output1": { "Value": "a mutated value", "Export": { - "Name": "an export", + "Name": "an-export", }, "Condition": "MyCondition", }, From 62b2f74779ced8efc2ac9da43383cd7db2b487ae Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:03:53 +0900 Subject: [PATCH 4/5] change logic --- packages/aws-cdk-lib/core/lib/cfn-output.ts | 9 +++++---- packages/aws-cdk-lib/core/test/output.test.ts | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/aws-cdk-lib/core/lib/cfn-output.ts b/packages/aws-cdk-lib/core/lib/cfn-output.ts index ccf8b69f7a031..b0bb1cb38ef63 100644 --- a/packages/aws-cdk-lib/core/lib/cfn-output.ts +++ b/packages/aws-cdk-lib/core/lib/cfn-output.ts @@ -178,18 +178,19 @@ export class CfnOutput extends CfnElement { } private validateOutput(): string[] { + const errors: string[] = []; if (this._exportName !== undefined && !Token.isUnresolved(this._exportName)) { if (this._exportName.length === 0) { - return ['Export name cannot be empty']; + errors.push('Export name cannot be empty'); } if (this._exportName.length > 255) { - return [`Export name cannot exceed 255 characters (got ${this._exportName.length} characters)`]; + errors.push(`Export name cannot exceed 255 characters (got ${this._exportName.length} characters)`); } if (!/^[A-Za-z0-9-:]*$/.test(this._exportName)) { - return [`Export name must only include alphanumeric characters, colons, or hyphens (got '${this._exportName}')`]; + errors.push(`Export name must only include alphanumeric characters, colons, or hyphens (got '${this._exportName}')`); } } - return []; + return errors; } } diff --git a/packages/aws-cdk-lib/core/test/output.test.ts b/packages/aws-cdk-lib/core/test/output.test.ts index 22b9ce94a1494..94a4eec333beb 100644 --- a/packages/aws-cdk-lib/core/test/output.test.ts +++ b/packages/aws-cdk-lib/core/test/output.test.ts @@ -140,7 +140,7 @@ describe('output', () => { const errors = output.node.validate(); expect(errors).toEqual([ - expect.stringContaining('Export name cannot exceed 255 characters'), + expect.stringContaining('Export name cannot exceed 255 characters (got 260 characters)'), ]); }); @@ -153,7 +153,7 @@ describe('output', () => { ]); }); - test('throw if export name has invalid string (space)', () => { + test('throw if export name has invalid strings (space)', () => { const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: 'SOME INVALID EXPORT NAME' }); const errors = output.node.validate(); @@ -162,7 +162,7 @@ describe('output', () => { ]); }); - test('throw if export name has invalid string (under_bar)', () => { + test('throw if export name has invalid strings (under_bar)', () => { const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: 'SOME_INVALID_EXPORT_NAME' }); const errors = output.node.validate(); @@ -170,4 +170,14 @@ describe('output', () => { expect.stringContaining('Export name must only include alphanumeric characters, colons, or hyphens (got \'SOME_INVALID_EXPORT_NAME\''), ]); }); + + test('throw if export name exceeds maximum length and has invalid strings', () => { + const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: ' '.repeat(260) }); + const errors = output.node.validate(); + + expect(errors).toEqual([ + expect.stringContaining('Export name cannot exceed 255 characters (got 260 characters)'), + expect.stringContaining(`Export name must only include alphanumeric characters, colons, or hyphens (got '${' '.repeat(260)}'`), + ]); + }); }); From 29144aef1e7df16d414f04b9e07984be2bb49581 Mon Sep 17 00:00:00 2001 From: "k.goto" <24818752+go-to-k@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:28:45 +0900 Subject: [PATCH 5/5] Update packages/aws-cdk-lib/core/test/output.test.ts --- packages/aws-cdk-lib/core/test/output.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/core/test/output.test.ts b/packages/aws-cdk-lib/core/test/output.test.ts index 94a4eec333beb..57507edcd9fb6 100644 --- a/packages/aws-cdk-lib/core/test/output.test.ts +++ b/packages/aws-cdk-lib/core/test/output.test.ts @@ -162,7 +162,7 @@ describe('output', () => { ]); }); - test('throw if export name has invalid strings (under_bar)', () => { + test('throw if export name has invalid strings (underscore)', () => { const output = new CfnOutput(stack, 'SomeOutput', { value: 'x', exportName: 'SOME_INVALID_EXPORT_NAME' }); const errors = output.node.validate();