diff --git a/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts b/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts index c985c538cac81..46cb62b27c218 100644 --- a/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts +++ b/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts @@ -3,6 +3,7 @@ import { Node, IConstruct } from 'constructs'; import { ISynthesisSession } from './types'; import * as cxschema from '../../../cloud-assembly-schema'; import { Stack } from '../stack'; +import { Token } from '../token'; /** * Shared logic of writing stack artifact to the Cloud Assembly @@ -20,10 +21,20 @@ export function addStackArtifactToAssembly( stackProps: Partial, additionalStackDependencies: string[]) { + const stackTags = stack.tags.tagValues(); + // nested stack tags are applied at the AWS::CloudFormation::Stack resource // level and are not needed in the cloud assembly. - if (stack.tags.hasTags()) { - stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags()); + if (Object.entries(stackTags).length > 0) { + for (const [k, v] of Object.entries(stackTags)) { + if (Token.isUnresolved(k) || Token.isUnresolved(v)) { + throw new Error(`Stack tags may not contain deploy-time values (tag: ${k}=${v}). Apply tags containing deploy-time values to resources only, avoid tagging stacks.`); + } + } + + stack.node.addMetadata( + cxschema.ArtifactMetadataEntryType.STACK_TAGS, + Object.entries(stackTags).map(([key, value]) => ({ Key: key, Value: value }))); } const deps = [ @@ -46,7 +57,7 @@ export function addStackArtifactToAssembly( const properties: cxschema.AwsCloudFormationStackProperties = { templateFile: stack.templateFile, terminationProtection: stack.terminationProtection, - tags: nonEmptyDict(stack.tags.tagValues()), + tags: nonEmptyDict(stackTags), validateOnSynth: session.validateOnSynth, notificationArns: stack._notificationArns, ...stackProps, diff --git a/packages/aws-cdk-lib/core/test/stack.test.ts b/packages/aws-cdk-lib/core/test/stack.test.ts index 1f53e0f990337..0f67d1ad6ac7b 100644 --- a/packages/aws-cdk-lib/core/test/stack.test.ts +++ b/packages/aws-cdk-lib/core/test/stack.test.ts @@ -2075,6 +2075,21 @@ describe('stack', () => { expect(asm.getStackArtifact(stack2.artifactId).tags).toEqual(expected); }); + test('stack tags may not contain tokens', () => { + // GIVEN + const app = new App({ + stackTraces: false, + }); + + const stack = new Stack(app, 'stack1', { + tags: { + foo: Lazy.string({ produce: () => 'lazy' }), + }, + }); + + expect(() => app.synth()).toThrow(/Stack tags may not contain deploy-time values/); + }); + test('stack notification arns are reflected in the stack artifact properties', () => { // GIVEN const NOTIFICATION_ARNS = ['arn:aws:sns:bermuda-triangle-1337:123456789012:MyTopic'];