Skip to content

Commit 4a9e683

Browse files
authored
fix(sns): contentBasedDeduplication is always false for imported topic (#29542)
Closes #29532. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 21dba21 commit 4a9e683

File tree

7 files changed

+296
-10
lines changed

7 files changed

+296
-10
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-sns/test/integ.sns.js.snapshot/SNSInteg.assets.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-sns/test/integ.sns.js.snapshot/SNSInteg.template.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,59 @@
119119
"SignatureVersion": "2",
120120
"TopicName": "fooTopicSignatureVersion"
121121
}
122+
},
123+
"MyTopic288CE2107": {
124+
"Type": "AWS::SNS::Topic",
125+
"Properties": {
126+
"DisplayName": "fooDisplayName2",
127+
"KmsMasterKeyId": {
128+
"Fn::GetAtt": [
129+
"CustomKey1E6D0D07",
130+
"Arn"
131+
]
132+
},
133+
"TopicName": "fooTopic2"
134+
}
135+
},
136+
"PublishRoleF42F66B6": {
137+
"Type": "AWS::IAM::Role",
138+
"Properties": {
139+
"AssumeRolePolicyDocument": {
140+
"Statement": [
141+
{
142+
"Action": "sts:AssumeRole",
143+
"Effect": "Allow",
144+
"Principal": {
145+
"Service": "s3.amazonaws.com"
146+
}
147+
}
148+
],
149+
"Version": "2012-10-17"
150+
}
151+
}
152+
},
153+
"PublishRoleDefaultPolicy9257B12D": {
154+
"Type": "AWS::IAM::Policy",
155+
"Properties": {
156+
"PolicyDocument": {
157+
"Statement": [
158+
{
159+
"Action": "sns:Publish",
160+
"Effect": "Allow",
161+
"Resource": {
162+
"Ref": "MyTopic288CE2107"
163+
}
164+
}
165+
],
166+
"Version": "2012-10-17"
167+
},
168+
"PolicyName": "PublishRoleDefaultPolicy9257B12D",
169+
"Roles": [
170+
{
171+
"Ref": "PublishRoleF42F66B6"
172+
}
173+
]
174+
}
122175
}
123176
},
124177
"Parameters": {

packages/@aws-cdk-testing/framework-integ/test/aws-sns/test/integ.sns.js.snapshot/manifest.json

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-sns/test/integ.sns.js.snapshot/tree.json

Lines changed: 125 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-sns/test/integ.sns.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,25 @@ class SNSInteg extends Stack {
4444
successFeedbackSampleRate: 50,
4545
});
4646

47+
// Topic with signatureVersion
4748
new Topic(this, 'MyTopicSignatureVersion', {
4849
topicName: 'fooTopicSignatureVersion',
4950
displayName: 'fooDisplayNameSignatureVersion',
5051
signatureVersion: '2',
5152
});
53+
54+
// Can import topic
55+
const topic2 = new Topic(this, 'MyTopic2', {
56+
topicName: 'fooTopic2',
57+
displayName: 'fooDisplayName2',
58+
masterKey: key,
59+
});
60+
const importedTopic = Topic.fromTopicArn(this, 'ImportedTopic', topic2.topicArn);
61+
62+
const publishRole = new Role(this, 'PublishRole', {
63+
assumedBy: new ServicePrincipal('s3.amazonaws.com'),
64+
});
65+
importedTopic.grantPublish(publishRole);
5266
}
5367
}
5468

packages/aws-cdk-lib/aws-sns/lib/topic.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,24 @@ export enum LoggingProtocol {
153153
APPLICATION = 'application',
154154
}
155155

156+
/**
157+
* Represents an SNS topic defined outside of this stack.
158+
*/
159+
export interface TopicAttributes {
160+
/**
161+
* The ARN of the SNS topic.
162+
*/
163+
readonly topicArn: string;
164+
165+
/**
166+
* Whether content-based deduplication is enabled.
167+
* Only applicable for FIFO topics.
168+
*
169+
* @default false
170+
*/
171+
readonly contentBasedDeduplication?: boolean;
172+
}
173+
156174
/**
157175
* A new SNS topic
158176
*/
@@ -166,16 +184,34 @@ export class Topic extends TopicBase {
166184
* @param topicArn topic ARN (i.e. arn:aws:sns:us-east-2:444455556666:MyTopic)
167185
*/
168186
public static fromTopicArn(scope: Construct, id: string, topicArn: string): ITopic {
187+
return Topic.fromTopicAttributes(scope, id, { topicArn });
188+
};
189+
190+
/**
191+
* Import an existing SNS topic provided a topic attributes
192+
*
193+
* @param scope The parent creating construct
194+
* @param id The construct's name
195+
* @param attrs the attributes of the topic to import
196+
*/
197+
public static fromTopicAttributes(scope: Construct, id: string, attrs: TopicAttributes): ITopic {
198+
const topicName = Stack.of(scope).splitArn(attrs.topicArn, ArnFormat.NO_RESOURCE_NAME).resource;
199+
const fifo = topicName.endsWith('.fifo');
200+
201+
if (attrs.contentBasedDeduplication && !fifo) {
202+
throw new Error('Cannot import topic; contentBasedDeduplication is only available for FIFO SNS topics.');
203+
}
204+
169205
class Import extends TopicBase {
170-
public readonly topicArn = topicArn;
171-
public readonly topicName = Stack.of(scope).splitArn(topicArn, ArnFormat.NO_RESOURCE_NAME).resource;
172-
public readonly fifo = this.topicName.endsWith('.fifo');
173-
public readonly contentBasedDeduplication = false;
206+
public readonly topicArn = attrs.topicArn;
207+
public readonly topicName = topicName;
208+
public readonly fifo = fifo;
209+
public readonly contentBasedDeduplication = attrs.contentBasedDeduplication || false;
174210
protected autoCreatePolicy: boolean = false;
175211
}
176212

177213
return new Import(scope, id, {
178-
environmentFromArn: topicArn,
214+
environmentFromArn: attrs.topicArn,
179215
});
180216
}
181217

packages/aws-cdk-lib/aws-sns/test/sns.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,48 @@ describe('Topic', () => {
455455
expect(imported.fifo).toEqual(true);
456456
});
457457

458+
test('fromTopicAttributes contentBasedDeduplication false', () => {
459+
// GIVEN
460+
const stack = new cdk.Stack();
461+
462+
// WHEN
463+
const imported = sns.Topic.fromTopicAttributes(stack, 'Imported', {
464+
topicArn: 'arn:aws:sns:*:123456789012:mytopic',
465+
});
466+
467+
// THEN
468+
expect(imported.topicName).toEqual('mytopic');
469+
expect(imported.topicArn).toEqual('arn:aws:sns:*:123456789012:mytopic');
470+
expect(imported.contentBasedDeduplication).toEqual(false);
471+
});
472+
473+
test('fromTopicAttributes contentBasedDeduplication true', () => {
474+
// GIVEN
475+
const stack = new cdk.Stack();
476+
477+
// WHEN
478+
const imported = sns.Topic.fromTopicAttributes(stack, 'Imported', {
479+
topicArn: 'arn:aws:sns:*:123456789012:mytopic.fifo',
480+
contentBasedDeduplication: true,
481+
});
482+
483+
// THEN
484+
expect(imported.topicName).toEqual('mytopic.fifo');
485+
expect(imported.topicArn).toEqual('arn:aws:sns:*:123456789012:mytopic.fifo');
486+
expect(imported.contentBasedDeduplication).toEqual(true);
487+
});
488+
489+
test('fromTopicAttributes throws with contentBasedDeduplication on non-fifo topic', () => {
490+
// GIVEN
491+
const stack = new cdk.Stack();
492+
493+
// WHEN
494+
expect(() => sns.Topic.fromTopicAttributes(stack, 'Imported', {
495+
topicArn: 'arn:aws:sns:*:123456789012:mytopic',
496+
contentBasedDeduplication: true,
497+
})).toThrow(/Cannot import topic; contentBasedDeduplication is only available for FIFO SNS topics./);
498+
});
499+
458500
test('sets account for imported topic env', () => {
459501
// GIVEN
460502
const stack = new cdk.Stack();

0 commit comments

Comments
 (0)