diff --git a/packages/aws-cdk/lib/cli/cdk-toolkit.ts b/packages/aws-cdk/lib/cli/cdk-toolkit.ts index 400a77987..eb3b0294e 100644 --- a/packages/aws-cdk/lib/cli/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cli/cdk-toolkit.ts @@ -256,8 +256,18 @@ export class CdkToolkit { } public async acknowledge(noticeId: string) { + const issueNumber = Number(noticeId); + if (!Number.isInteger(issueNumber)) { + throw new ToolkitError( + 'InvalidAcknowledgementId', + `Invalid notice ID '${noticeId}': 'cdk acknowledge' only accepts numeric notice IDs (e.g. 'cdk acknowledge 12345'). ` + + 'Scoped construct warnings such as \'@aws-cdk/aws-ecs:minHealthyPercent\' are acknowledged in code with ' + + 'Annotations.of(scope).acknowledgeWarning(\'\').', + ); + } + const acks = new Set(this.props.configuration.context.get('acknowledged-issue-numbers') ?? []); - acks.add(Number(noticeId)); + acks.add(issueNumber); this.props.configuration.context.set('acknowledged-issue-numbers', Array.from(acks)); await this.props.configuration.saveContext(); } diff --git a/packages/aws-cdk/test/commands/acknowledge.test.ts b/packages/aws-cdk/test/commands/acknowledge.test.ts index 300a749b9..a58ad375d 100644 --- a/packages/aws-cdk/test/commands/acknowledge.test.ts +++ b/packages/aws-cdk/test/commands/acknowledge.test.ts @@ -29,4 +29,16 @@ describe('acknowledge command', () => { // THEN expect(configuration.context.get('acknowledged-issue-numbers')).toEqual([12345]); }); + + test('acknowledging a scoped construct warning id throws and does not corrupt the context', async () => { + // WHEN / THEN + await expect(toolkit.acknowledge('@aws-cdk/aws-ecs:minHealthyPercent')).rejects.toThrow(/numeric notice IDs/i); + + // AND the context is not corrupted with a `null` entry + expect(configuration.context.get('acknowledged-issue-numbers')).toBeUndefined(); + }); + + test('acknowledging a non-numeric id throws', async () => { + await expect(toolkit.acknowledge('not-a-number')).rejects.toThrow(/Invalid notice ID/i); + }); });