Skip to content

Commit 97697a9

Browse files
authored
set removal policy for resources to destroy in sandbox deployments (#2242)
1 parent 995a84c commit 97697a9

File tree

4 files changed

+74
-13
lines changed

4 files changed

+74
-13
lines changed

.changeset/hip-yaks-remain.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@aws-amplify/backend': patch
3+
---
4+
5+
set removal policy for resources to destroy in sandbox deployments

packages/backend/src/engine/amplify_stack.test.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@ import { AmplifyStack } from './amplify_stack.js';
44
import { Template } from 'aws-cdk-lib/assertions';
55
import assert from 'node:assert';
66
import { FederatedPrincipal, Role } from 'aws-cdk-lib/aws-iam';
7+
import { BackendIdentifier } from '@aws-amplify/plugin-types';
8+
import { Bucket } from 'aws-cdk-lib/aws-s3';
9+
10+
const branchBackendId: BackendIdentifier = {
11+
namespace: 'testId',
12+
name: 'testBranch',
13+
type: 'branch',
14+
};
715

816
void describe('AmplifyStack', () => {
917
void it('renames nested stack logical IDs to non-redundant value', () => {
1018
const app = new App();
11-
const rootStack = new AmplifyStack(app, 'test-id');
19+
const rootStack = new AmplifyStack(app, branchBackendId);
1220
new NestedStack(rootStack, 'testName');
1321

1422
const rootStackTemplate = Template.fromStack(rootStack);
@@ -23,7 +31,7 @@ void describe('AmplifyStack', () => {
2331

2432
void it('allows roles with properly configured cognito trust policies', () => {
2533
const app = new App();
26-
const rootStack = new AmplifyStack(app, 'test-id');
34+
const rootStack = new AmplifyStack(app, branchBackendId);
2735
new Role(rootStack, 'correctRole', {
2836
assumedBy: new FederatedPrincipal(
2937
'cognito-identity.amazonaws.com',
@@ -43,7 +51,7 @@ void describe('AmplifyStack', () => {
4351

4452
void it('throws on roles with cognito trust policy missing amr condition', () => {
4553
const app = new App();
46-
const rootStack = new AmplifyStack(app, 'test-id');
54+
const rootStack = new AmplifyStack(app, branchBackendId);
4755
new Role(rootStack, 'missingAmrCondition', {
4856
assumedBy: new FederatedPrincipal(
4957
'cognito-identity.amazonaws.com',
@@ -64,7 +72,7 @@ void describe('AmplifyStack', () => {
6472

6573
void it('throws on roles with cognito trust policy missing aud condition', () => {
6674
const app = new App();
67-
const rootStack = new AmplifyStack(app, 'test-id');
75+
const rootStack = new AmplifyStack(app, branchBackendId);
6876
new Role(rootStack, 'missingAudCondition', {
6977
assumedBy: new FederatedPrincipal(
7078
'cognito-identity.amazonaws.com',
@@ -82,4 +90,32 @@ void describe('AmplifyStack', () => {
8290
'Cannot create a Role trust policy with Cognito that does not have a StringEquals condition for cognito-identity.amazonaws.com:aud',
8391
});
8492
});
93+
94+
void it('keeps default removal policy of retain for resources in branch deployments', () => {
95+
const app = new App();
96+
const rootStack = new AmplifyStack(app, branchBackendId);
97+
// bucket has default removal policy to retain
98+
new Bucket(rootStack, 'testBucket', { enforceSSL: true });
99+
const template = Template.fromStack(rootStack);
100+
101+
template.hasResource('AWS::S3::Bucket', {
102+
DeletionPolicy: 'Retain',
103+
});
104+
});
105+
106+
void it('sets removal policy to destroy for resources in sandbox deployments', () => {
107+
const app = new App();
108+
const rootStack = new AmplifyStack(app, {
109+
namespace: 'testId',
110+
name: 'testSandbox',
111+
type: 'sandbox',
112+
});
113+
// bucket has default removal policy to retain
114+
new Bucket(rootStack, 'testBucket', { enforceSSL: true });
115+
const template = Template.fromStack(rootStack);
116+
117+
template.hasResource('AWS::S3::Bucket', {
118+
DeletionPolicy: 'Delete',
119+
});
120+
});
85121
});

packages/backend/src/engine/amplify_stack.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1-
import { AmplifyFault } from '@aws-amplify/platform-core';
2-
import { Aspects, CfnElement, IAspect, Stack } from 'aws-cdk-lib';
1+
import {
2+
AmplifyFault,
3+
BackendIdentifierConversions,
4+
} from '@aws-amplify/platform-core';
5+
import { BackendIdentifier } from '@aws-amplify/plugin-types';
6+
import {
7+
Aspects,
8+
CfnElement,
9+
CfnResource,
10+
IAspect,
11+
RemovalPolicy,
12+
Stack,
13+
} from 'aws-cdk-lib';
314
import { Role } from 'aws-cdk-lib/aws-iam';
415
import { Construct, IConstruct } from 'constructs';
516

@@ -10,9 +21,13 @@ export class AmplifyStack extends Stack {
1021
/**
1122
* Default constructor
1223
*/
13-
constructor(scope: Construct, id: string) {
14-
super(scope, id);
24+
constructor(scope: Construct, backendId: BackendIdentifier) {
25+
super(scope, BackendIdentifierConversions.toStackName(backendId));
1526
Aspects.of(this).add(new CognitoRoleTrustPolicyValidator());
27+
28+
if (backendId.type === 'sandbox') {
29+
Aspects.of(this).add(new SandboxRemovalPolicyDestroyAspect());
30+
}
1631
}
1732
/**
1833
* Overrides Stack.allocateLogicalId to prevent redundant nested stack logical IDs
@@ -93,3 +108,12 @@ class CognitoRoleTrustPolicyValidator implements IAspect {
93108
}
94109
};
95110
}
111+
112+
// This aspect sets removal policy of all resources to destroy for sandbox deployments
113+
class SandboxRemovalPolicyDestroyAspect implements IAspect {
114+
visit(node: IConstruct): void {
115+
if (CfnResource.isCfnResource(node)) {
116+
node.applyRemovalPolicy(RemovalPolicy.DESTROY);
117+
}
118+
}
119+
}

packages/backend/src/project_environment_main_stack_creator.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { BackendIdentifier, MainStackCreator } from '@aws-amplify/plugin-types';
22
import { Construct } from 'constructs';
33
import { Stack, Tags } from 'aws-cdk-lib';
44
import { AmplifyStack } from './engine/amplify_stack.js';
5-
import { BackendIdentifierConversions } from '@aws-amplify/platform-core';
65

76
/**
87
* Creates stacks that are tied to a given project environment via an SSM parameter
@@ -22,10 +21,7 @@ export class ProjectEnvironmentMainStackCreator implements MainStackCreator {
2221
*/
2322
getOrCreateMainStack = (): Stack => {
2423
if (this.mainStack === undefined) {
25-
this.mainStack = new AmplifyStack(
26-
this.scope,
27-
BackendIdentifierConversions.toStackName(this.backendId)
28-
);
24+
this.mainStack = new AmplifyStack(this.scope, this.backendId);
2925
}
3026

3127
const deploymentType = this.backendId.type;

0 commit comments

Comments
 (0)