@friggframework/devtools 2.0.0--canary.490.feacde9.0 → 2.0.0--canary.497.a3f25f9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frigg-cli/deploy-command/index.js +3 -9
- package/infrastructure/README.md +0 -28
- package/infrastructure/domains/database/migration-builder.js +13 -19
- package/infrastructure/domains/database/migration-builder.test.js +0 -57
- package/infrastructure/domains/integration/integration-builder.js +14 -19
- package/infrastructure/domains/integration/integration-builder.test.js +74 -0
- package/infrastructure/domains/networking/vpc-builder.js +18 -240
- package/infrastructure/domains/networking/vpc-builder.test.js +13 -711
- package/infrastructure/domains/networking/vpc-resolver.js +40 -221
- package/infrastructure/domains/networking/vpc-resolver.test.js +18 -318
- package/infrastructure/domains/security/kms-builder.js +6 -55
- package/infrastructure/domains/security/kms-builder.test.js +1 -19
- package/infrastructure/domains/shared/cloudformation-discovery.js +13 -310
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +0 -395
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +6 -41
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +0 -39
- package/infrastructure/domains/shared/resource-discovery.js +5 -17
- package/infrastructure/domains/shared/resource-discovery.test.js +0 -36
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +17 -27
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +0 -73
- package/infrastructure/infrastructure-composer.js +3 -11
- package/infrastructure/scripts/build-prisma-layer.js +81 -8
- package/infrastructure/scripts/build-prisma-layer.test.js +53 -1
- package/infrastructure/scripts/verify-prisma-layer.js +72 -0
- package/package.json +7 -7
- package/layers/prisma/.build-complete +0 -3
|
@@ -149,7 +149,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
149
149
|
physicalId = flatDiscovery.defaultVpcId;
|
|
150
150
|
} else if (logicalId === 'FriggLambdaSecurityGroup') {
|
|
151
151
|
resourceType = 'AWS::EC2::SecurityGroup';
|
|
152
|
-
physicalId = flatDiscovery.
|
|
152
|
+
physicalId = flatDiscovery.defaultSecurityGroupId || flatDiscovery.securityGroupId;
|
|
153
153
|
} else if (logicalId === 'FriggPrivateSubnet1') {
|
|
154
154
|
resourceType = 'AWS::EC2::Subnet';
|
|
155
155
|
physicalId = flatDiscovery.privateSubnetId1;
|
|
@@ -159,27 +159,21 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
159
159
|
} else if (logicalId === 'FriggNATGateway') {
|
|
160
160
|
resourceType = 'AWS::EC2::NatGateway';
|
|
161
161
|
physicalId = flatDiscovery.existingNatGatewayId;
|
|
162
|
-
} else if (logicalId === '
|
|
163
|
-
resourceType = 'AWS::EC2::RouteTable';
|
|
164
|
-
physicalId = flatDiscovery.routeTableId;
|
|
165
|
-
} else if (logicalId === 'FriggS3VPCEndpoint' || logicalId === 'VPCEndpointS3') {
|
|
162
|
+
} else if (logicalId === 'FriggS3VPCEndpoint') {
|
|
166
163
|
resourceType = 'AWS::EC2::VPCEndpoint';
|
|
167
164
|
physicalId = flatDiscovery.s3VpcEndpointId;
|
|
168
|
-
} else if (logicalId === 'FriggDynamoDBVPCEndpoint'
|
|
165
|
+
} else if (logicalId === 'FriggDynamoDBVPCEndpoint') {
|
|
169
166
|
resourceType = 'AWS::EC2::VPCEndpoint';
|
|
170
167
|
physicalId = flatDiscovery.dynamodbVpcEndpointId;
|
|
171
|
-
} else if (logicalId === 'FriggKMSVPCEndpoint'
|
|
168
|
+
} else if (logicalId === 'FriggKMSVPCEndpoint') {
|
|
172
169
|
resourceType = 'AWS::EC2::VPCEndpoint';
|
|
173
170
|
physicalId = flatDiscovery.kmsVpcEndpointId;
|
|
174
|
-
} else if (logicalId === 'FriggSecretsManagerVPCEndpoint'
|
|
171
|
+
} else if (logicalId === 'FriggSecretsManagerVPCEndpoint') {
|
|
175
172
|
resourceType = 'AWS::EC2::VPCEndpoint';
|
|
176
173
|
physicalId = flatDiscovery.secretsManagerVpcEndpointId;
|
|
177
|
-
} else if (logicalId === 'FriggSQSVPCEndpoint'
|
|
174
|
+
} else if (logicalId === 'FriggSQSVPCEndpoint') {
|
|
178
175
|
resourceType = 'AWS::EC2::VPCEndpoint';
|
|
179
176
|
physicalId = flatDiscovery.sqsVpcEndpointId;
|
|
180
|
-
} else if (logicalId === 'FriggNATRoute' || logicalId === 'FriggPrivateRoute') {
|
|
181
|
-
resourceType = 'AWS::EC2::Route';
|
|
182
|
-
physicalId = flatDiscovery.natRoute;
|
|
183
177
|
}
|
|
184
178
|
|
|
185
179
|
if (physicalId && typeof physicalId === 'string') {
|
|
@@ -190,11 +184,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
190
184
|
});
|
|
191
185
|
}
|
|
192
186
|
});
|
|
193
|
-
|
|
194
|
-
// Also check for external resources extracted via CloudFormation queries
|
|
195
|
-
// (e.g., VPC ID from security group query, subnets from route table associations)
|
|
196
|
-
// These are NOT in the stack but were discovered through stack resources
|
|
197
|
-
this._addExternalResourcesFromCloudFormationQueries(flatDiscovery, discovery, existingLogicalIds);
|
|
198
187
|
} else {
|
|
199
188
|
// Resources discovered from AWS API (not CloudFormation)
|
|
200
189
|
// These go into external array
|
|
@@ -298,70 +287,9 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
298
287
|
}
|
|
299
288
|
}
|
|
300
289
|
|
|
301
|
-
// Add flat discovery properties directly to discovery object for resolver access
|
|
302
|
-
// The resolver checks both discovery.defaultSecurityGroupId and discovery.external array
|
|
303
|
-
discovery.defaultVpcId = flatDiscovery.defaultVpcId;
|
|
304
|
-
discovery.defaultSecurityGroupId = flatDiscovery.defaultSecurityGroupId;
|
|
305
|
-
discovery.privateSubnetId1 = flatDiscovery.privateSubnetId1;
|
|
306
|
-
discovery.privateSubnetId2 = flatDiscovery.privateSubnetId2;
|
|
307
|
-
discovery.natGatewayId = flatDiscovery.natGatewayId;
|
|
308
|
-
discovery.lambdaSecurityGroupId = flatDiscovery.lambdaSecurityGroupId;
|
|
309
|
-
|
|
310
290
|
return discovery;
|
|
311
291
|
}
|
|
312
292
|
|
|
313
|
-
/**
|
|
314
|
-
* Add external resources that were discovered via CloudFormation queries
|
|
315
|
-
* (e.g., VPC ID extracted from security group, subnets from route table associations)
|
|
316
|
-
*
|
|
317
|
-
* @private
|
|
318
|
-
*/
|
|
319
|
-
_addExternalResourcesFromCloudFormationQueries(flatDiscovery, discovery, existingLogicalIds) {
|
|
320
|
-
// VPC ID extracted from SG or route table (NOT a stack resource)
|
|
321
|
-
if (flatDiscovery.defaultVpcId &&
|
|
322
|
-
typeof flatDiscovery.defaultVpcId === 'string' &&
|
|
323
|
-
!existingLogicalIds.includes('FriggVPC')) {
|
|
324
|
-
discovery.external.push({
|
|
325
|
-
physicalId: flatDiscovery.defaultVpcId,
|
|
326
|
-
resourceType: 'AWS::EC2::VPC',
|
|
327
|
-
source: 'cloudformation-query'
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Subnets extracted from route table associations (NOT stack resources)
|
|
332
|
-
if (flatDiscovery.privateSubnetId1 &&
|
|
333
|
-
typeof flatDiscovery.privateSubnetId1 === 'string' &&
|
|
334
|
-
!existingLogicalIds.includes('FriggPrivateSubnet1')) {
|
|
335
|
-
discovery.external.push({
|
|
336
|
-
physicalId: flatDiscovery.privateSubnetId1,
|
|
337
|
-
resourceType: 'AWS::EC2::Subnet',
|
|
338
|
-
source: 'cloudformation-query'
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (flatDiscovery.privateSubnetId2 &&
|
|
343
|
-
typeof flatDiscovery.privateSubnetId2 === 'string' &&
|
|
344
|
-
!existingLogicalIds.includes('FriggPrivateSubnet2')) {
|
|
345
|
-
discovery.external.push({
|
|
346
|
-
physicalId: flatDiscovery.privateSubnetId2,
|
|
347
|
-
resourceType: 'AWS::EC2::Subnet',
|
|
348
|
-
source: 'cloudformation-query'
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// NAT Gateway extracted from route table routes
|
|
353
|
-
if (flatDiscovery.existingNatGatewayId &&
|
|
354
|
-
typeof flatDiscovery.existingNatGatewayId === 'string' &&
|
|
355
|
-
!existingLogicalIds.includes('FriggNATGateway') &&
|
|
356
|
-
!existingLogicalIds.includes('FriggNatGateway')) {
|
|
357
|
-
discovery.external.push({
|
|
358
|
-
physicalId: flatDiscovery.existingNatGatewayId,
|
|
359
|
-
resourceType: 'AWS::EC2::NatGateway',
|
|
360
|
-
source: 'cloudformation-query'
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
293
|
/**
|
|
366
294
|
* Translate legacy configuration (management modes) to new ownership-based configuration
|
|
367
295
|
* Provides backwards compatibility for existing app definitions
|
|
@@ -537,7 +465,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
537
465
|
iamStatements: [],
|
|
538
466
|
outputs: {},
|
|
539
467
|
environment: {},
|
|
540
|
-
discovery: discoveredResources, // Store for backwards compatibility checks
|
|
541
468
|
};
|
|
542
469
|
|
|
543
470
|
// Add IAM permissions for VPC-enabled Lambda functions
|
|
@@ -556,7 +483,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
556
483
|
this.buildNatGatewayFromDecision(decisions.natGateway, appDefinition, discoveredResources, result);
|
|
557
484
|
|
|
558
485
|
// Build VPC Endpoints based on ownership decisions
|
|
559
|
-
this.buildVpcEndpointsFromDecisions(decisions.vpcEndpoints,
|
|
486
|
+
this.buildVpcEndpointsFromDecisions(decisions.vpcEndpoints, appDefinition, result);
|
|
560
487
|
|
|
561
488
|
// Set VPC_ENABLED environment variable
|
|
562
489
|
result.environment.VPC_ENABLED = 'true';
|
|
@@ -590,10 +517,11 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
590
517
|
* Build VPC based on ownership decision
|
|
591
518
|
*
|
|
592
519
|
* For STACK ownership: ALWAYS add definitions to template.
|
|
520
|
+
* CloudFormation idempotency ensures existing resources aren't recreated.
|
|
593
521
|
*/
|
|
594
522
|
buildVpcFromDecision(decision, appDefinition, result) {
|
|
595
523
|
if (decision.ownership === ResourceOwnership.STACK) {
|
|
596
|
-
// For STACK ownership: ALWAYS create definitions
|
|
524
|
+
// For STACK ownership: ALWAYS create definitions (CloudFormation idempotency)
|
|
597
525
|
if (decision.physicalId) {
|
|
598
526
|
console.log(` → Adding VPC definition to template (existing: ${decision.physicalId})`);
|
|
599
527
|
} else {
|
|
@@ -652,6 +580,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
652
580
|
buildSecurityGroupFromDecision(decision, appDefinition, result) {
|
|
653
581
|
if (decision.ownership === ResourceOwnership.STACK) {
|
|
654
582
|
// Always create security group resource in template
|
|
583
|
+
// CloudFormation handles idempotency if it already exists
|
|
655
584
|
console.log(' → Adding Lambda Security Group to template...');
|
|
656
585
|
|
|
657
586
|
result.resources.FriggLambdaSecurityGroup = {
|
|
@@ -701,6 +630,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
701
630
|
}
|
|
702
631
|
|
|
703
632
|
// For STACK ownership: ALWAYS add definitions to template
|
|
633
|
+
// CloudFormation idempotency ensures existing resources won't be recreated
|
|
704
634
|
if (decision.physicalIds && decision.physicalIds.length >= 2) {
|
|
705
635
|
console.log(` → Adding subnet definitions to template (existing: ${decision.physicalIds.join(', ')})`);
|
|
706
636
|
} else {
|
|
@@ -924,8 +854,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
924
854
|
/**
|
|
925
855
|
* Build VPC Endpoints based on ownership decisions
|
|
926
856
|
*/
|
|
927
|
-
buildVpcEndpointsFromDecisions(
|
|
928
|
-
const decisions = endpointDecisions; // For backwards compatibility with existing code
|
|
857
|
+
buildVpcEndpointsFromDecisions(decisions, appDefinition, result) {
|
|
929
858
|
const endpointsToCreate = [];
|
|
930
859
|
const endpointsInStack = [];
|
|
931
860
|
const externalEndpoints = [];
|
|
@@ -943,8 +872,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
943
872
|
|
|
944
873
|
if (endpointsInStack.length > 0) {
|
|
945
874
|
console.log(` ✓ VPC Endpoints in stack: ${endpointsInStack.join(', ')}`);
|
|
946
|
-
// CRITICAL: Must add stack-managed endpoints back to template or CloudFormation will DELETE them!
|
|
947
|
-
this._addStackManagedEndpointsToTemplate(decisions, securityGroupDecision, discoveredResources, result);
|
|
948
875
|
}
|
|
949
876
|
|
|
950
877
|
if (externalEndpoints.length > 0) {
|
|
@@ -1007,15 +934,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1007
934
|
// Create security group for interface endpoints if needed
|
|
1008
935
|
const needsInterfaceEndpoints = endpointsToCreate.some(type => ['kms', 'secretsManager', 'sqs'].includes(type));
|
|
1009
936
|
if (needsInterfaceEndpoints) {
|
|
1010
|
-
// Determine source security group for ingress rule
|
|
1011
|
-
let sourceSgId;
|
|
1012
|
-
if (securityGroupDecision.ownership === ResourceOwnership.STACK) {
|
|
1013
|
-
sourceSgId = { Ref: 'FriggLambdaSecurityGroup' };
|
|
1014
|
-
} else {
|
|
1015
|
-
// External - use the physical ID
|
|
1016
|
-
sourceSgId = securityGroupDecision.physicalIds[0];
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
937
|
result.resources.FriggVPCEndpointSecurityGroup = {
|
|
1020
938
|
Type: 'AWS::EC2::SecurityGroup',
|
|
1021
939
|
Properties: {
|
|
@@ -1026,7 +944,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1026
944
|
IpProtocol: 'tcp',
|
|
1027
945
|
FromPort: 443,
|
|
1028
946
|
ToPort: 443,
|
|
1029
|
-
SourceSecurityGroupId:
|
|
947
|
+
SourceSecurityGroupId: { Ref: 'FriggLambdaSecurityGroup' },
|
|
1030
948
|
Description: 'HTTPS from Lambda',
|
|
1031
949
|
},
|
|
1032
950
|
],
|
|
@@ -1134,119 +1052,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1134
1052
|
return healingReport;
|
|
1135
1053
|
}
|
|
1136
1054
|
|
|
1137
|
-
/**
|
|
1138
|
-
* Add stack-managed VPC endpoints back to template
|
|
1139
|
-
*
|
|
1140
|
-
* CRITICAL: CloudFormation will DELETE resources that exist in the previous template
|
|
1141
|
-
* but are missing from the new template. We must re-add discovered stack-managed
|
|
1142
|
-
* endpoints to prevent CloudFormation from deleting them.
|
|
1143
|
-
*
|
|
1144
|
-
* @private
|
|
1145
|
-
*/
|
|
1146
|
-
_addStackManagedEndpointsToTemplate(endpointDecisions, securityGroupDecision, discoveredResources, result) {
|
|
1147
|
-
const decisions = endpointDecisions; // For backwards compatibility
|
|
1148
|
-
const vpcId = result.vpcId;
|
|
1149
|
-
|
|
1150
|
-
// Determine logical IDs based on what exists in stack for backwards compatibility
|
|
1151
|
-
// CRITICAL: Frontify production uses OLD naming (VPCEndpointS3, not FriggS3VPCEndpoint)
|
|
1152
|
-
const existingLogicalIds = discoveredResources?.existingLogicalIds || [];
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
const logicalIdMap = {
|
|
1156
|
-
s3: existingLogicalIds.includes('VPCEndpointS3') ? 'VPCEndpointS3' : 'FriggS3VPCEndpoint',
|
|
1157
|
-
dynamodb: existingLogicalIds.includes('VPCEndpointDynamoDB') ? 'VPCEndpointDynamoDB' : 'FriggDynamoDBVPCEndpoint',
|
|
1158
|
-
kms: existingLogicalIds.includes('VPCEndpointKMS') ? 'VPCEndpointKMS' : 'FriggKMSVPCEndpoint',
|
|
1159
|
-
secretsManager: existingLogicalIds.includes('VPCEndpointSecretsManager') ? 'VPCEndpointSecretsManager' : 'FriggSecretsManagerVPCEndpoint',
|
|
1160
|
-
sqs: existingLogicalIds.includes('VPCEndpointSQS') ? 'VPCEndpointSQS' : 'FriggSQSVPCEndpoint'
|
|
1161
|
-
};
|
|
1162
|
-
|
|
1163
|
-
Object.entries(decisions).forEach(([type, decision]) => {
|
|
1164
|
-
if (decision.ownership === ResourceOwnership.STACK) {
|
|
1165
|
-
const logicalId = logicalIdMap[type];
|
|
1166
|
-
|
|
1167
|
-
// Determine endpoint type and properties based on service
|
|
1168
|
-
if (type === 's3') {
|
|
1169
|
-
result.resources[logicalId] = {
|
|
1170
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
1171
|
-
Properties: {
|
|
1172
|
-
VpcId: vpcId,
|
|
1173
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.s3',
|
|
1174
|
-
VpcEndpointType: 'Gateway',
|
|
1175
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
1176
|
-
}
|
|
1177
|
-
};
|
|
1178
|
-
} else if (type === 'dynamodb') {
|
|
1179
|
-
result.resources[logicalId] = {
|
|
1180
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
1181
|
-
Properties: {
|
|
1182
|
-
VpcId: vpcId,
|
|
1183
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
|
|
1184
|
-
VpcEndpointType: 'Gateway',
|
|
1185
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
1186
|
-
}
|
|
1187
|
-
};
|
|
1188
|
-
} else {
|
|
1189
|
-
// Interface endpoints (KMS, Secrets Manager, SQS)
|
|
1190
|
-
const serviceMap = {
|
|
1191
|
-
kms: 'kms',
|
|
1192
|
-
secretsManager: 'secretsmanager',
|
|
1193
|
-
sqs: 'sqs'
|
|
1194
|
-
};
|
|
1195
|
-
|
|
1196
|
-
result.resources[logicalId] = {
|
|
1197
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
1198
|
-
Properties: {
|
|
1199
|
-
VpcId: vpcId,
|
|
1200
|
-
ServiceName: `com.amazonaws.\${self:provider.region}.${serviceMap[type]}`,
|
|
1201
|
-
VpcEndpointType: 'Interface',
|
|
1202
|
-
SubnetIds: result.vpcConfig.subnetIds,
|
|
1203
|
-
SecurityGroupIds: [{ Ref: 'FriggVPCEndpointSecurityGroup' }],
|
|
1204
|
-
PrivateDnsEnabled: true
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
});
|
|
1210
|
-
|
|
1211
|
-
// If any interface endpoints exist, ensure security group is in template
|
|
1212
|
-
const hasInterfaceEndpoints = ['kms', 'secretsManager', 'sqs'].some(
|
|
1213
|
-
type => decisions[type]?.ownership === ResourceOwnership.STACK && decisions[type]?.physicalId
|
|
1214
|
-
);
|
|
1215
|
-
|
|
1216
|
-
if (hasInterfaceEndpoints && !result.resources.FriggVPCEndpointSecurityGroup) {
|
|
1217
|
-
// Determine source security group for ingress rule
|
|
1218
|
-
// If Lambda SG is stack-managed, use CloudFormation Ref
|
|
1219
|
-
// If Lambda SG is external, use the physical ID directly
|
|
1220
|
-
let sourceSgId;
|
|
1221
|
-
if (securityGroupDecision.ownership === ResourceOwnership.STACK) {
|
|
1222
|
-
sourceSgId = { Ref: 'FriggLambdaSecurityGroup' };
|
|
1223
|
-
} else {
|
|
1224
|
-
// External - use the physical ID
|
|
1225
|
-
sourceSgId = securityGroupDecision.physicalIds[0];
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
result.resources.FriggVPCEndpointSecurityGroup = {
|
|
1229
|
-
Type: 'AWS::EC2::SecurityGroup',
|
|
1230
|
-
Properties: {
|
|
1231
|
-
GroupDescription: 'Security group for VPC Endpoints',
|
|
1232
|
-
VpcId: vpcId,
|
|
1233
|
-
SecurityGroupIngress: [
|
|
1234
|
-
{
|
|
1235
|
-
IpProtocol: 'tcp',
|
|
1236
|
-
FromPort: 443,
|
|
1237
|
-
ToPort: 443,
|
|
1238
|
-
SourceSecurityGroupId: sourceSgId
|
|
1239
|
-
}
|
|
1240
|
-
],
|
|
1241
|
-
Tags: [
|
|
1242
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg' },
|
|
1243
|
-
{ Key: 'ManagedBy', Value: 'Frigg' }
|
|
1244
|
-
]
|
|
1245
|
-
}
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
1055
|
/**
|
|
1251
1056
|
* Build new VPC from scratch
|
|
1252
1057
|
*/
|
|
@@ -1766,29 +1571,8 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1766
1571
|
|
|
1767
1572
|
/**
|
|
1768
1573
|
* Create route table and associations for NAT Gateway
|
|
1769
|
-
* Always adds to template - CloudFormation handles idempotency
|
|
1770
|
-
* Uses existing logical IDs from stack to prevent AlreadyExists errors
|
|
1771
1574
|
*/
|
|
1772
1575
|
createNatGatewayRouting(appDefinition, discoveredResources, result, natGatewayId) {
|
|
1773
|
-
// Note: We always add routing resources to the template.
|
|
1774
|
-
// CloudFormation's idempotency ensures existing resources are updated, not recreated.
|
|
1775
|
-
// Removing resources from the template causes CloudFormation to try CREATE on next deploy → AlreadyExists error
|
|
1776
|
-
|
|
1777
|
-
// Determine which logical ID to use for the NAT route based on what exists in stack
|
|
1778
|
-
// Older stacks use 'FriggNATRoute', newer ones use 'FriggPrivateRoute'
|
|
1779
|
-
// CRITICAL: Must check existingLogicalIds to avoid AlreadyExists errors on logical ID mismatch
|
|
1780
|
-
const existingLogicalIds = discoveredResources?.existingLogicalIds || [];
|
|
1781
|
-
|
|
1782
|
-
const routeLogicalId = existingLogicalIds.includes('FriggNATRoute')
|
|
1783
|
-
? 'FriggNATRoute' // Use existing logical ID from stack (backwards compatibility)
|
|
1784
|
-
: 'FriggPrivateRoute'; // Default for new stacks
|
|
1785
|
-
|
|
1786
|
-
// Always use new logical IDs to force recreation and fix drift
|
|
1787
|
-
// Old IDs (FriggSubnet1RouteAssociation) may have drifted from CloudFormation state
|
|
1788
|
-
// Using new IDs forces CloudFormation to delete old and create new associations
|
|
1789
|
-
const subnet1AssocLogicalId = 'FriggPrivateSubnet1RouteTableAssociation';
|
|
1790
|
-
const subnet2AssocLogicalId = 'FriggPrivateSubnet2RouteTableAssociation';
|
|
1791
|
-
|
|
1792
1576
|
// Private route table with NAT Gateway route
|
|
1793
1577
|
if (!result.resources.FriggLambdaRouteTable) {
|
|
1794
1578
|
result.resources.FriggLambdaRouteTable = {
|
|
@@ -1803,7 +1587,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1803
1587
|
};
|
|
1804
1588
|
}
|
|
1805
1589
|
|
|
1806
|
-
result.resources
|
|
1590
|
+
result.resources.FriggPrivateRoute = {
|
|
1807
1591
|
Type: 'AWS::EC2::Route',
|
|
1808
1592
|
Properties: {
|
|
1809
1593
|
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
@@ -1817,18 +1601,16 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1817
1601
|
const subnet1Id = discoveredResources.privateSubnetId1 || { Ref: 'FriggPrivateSubnet1' };
|
|
1818
1602
|
const subnet2Id = discoveredResources.privateSubnetId2 || { Ref: 'FriggPrivateSubnet2' };
|
|
1819
1603
|
|
|
1820
|
-
result.resources
|
|
1604
|
+
result.resources.FriggPrivateSubnet1RouteTableAssociation = {
|
|
1821
1605
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1822
|
-
UpdateReplacePolicy: 'Delete',
|
|
1823
1606
|
Properties: {
|
|
1824
1607
|
SubnetId: subnet1Id,
|
|
1825
1608
|
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1826
1609
|
},
|
|
1827
1610
|
};
|
|
1828
1611
|
|
|
1829
|
-
result.resources
|
|
1612
|
+
result.resources.FriggPrivateSubnet2RouteTableAssociation = {
|
|
1830
1613
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1831
|
-
UpdateReplacePolicy: 'Delete',
|
|
1832
1614
|
Properties: {
|
|
1833
1615
|
SubnetId: subnet2Id,
|
|
1834
1616
|
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
@@ -1844,9 +1626,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1844
1626
|
*/
|
|
1845
1627
|
ensureSubnetAssociations(appDefinition, discoveredResources, result) {
|
|
1846
1628
|
// Skip if associations already created (by NAT Gateway routing)
|
|
1847
|
-
|
|
1848
|
-
if (result.resources.FriggPrivateSubnet1RouteTableAssociation ||
|
|
1849
|
-
result.resources.FriggSubnet1RouteAssociation) {
|
|
1629
|
+
if (result.resources.FriggPrivateSubnet1RouteTableAssociation) {
|
|
1850
1630
|
return; // Already handled by NAT Gateway routing
|
|
1851
1631
|
}
|
|
1852
1632
|
|
|
@@ -1856,7 +1636,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1856
1636
|
|
|
1857
1637
|
result.resources.FriggPrivateSubnet1RouteTableAssociation = {
|
|
1858
1638
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1859
|
-
UpdateReplacePolicy: 'Delete',
|
|
1860
1639
|
Properties: {
|
|
1861
1640
|
SubnetId: subnet1Id,
|
|
1862
1641
|
RouteTableId: routeTableId,
|
|
@@ -1865,7 +1644,6 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1865
1644
|
|
|
1866
1645
|
result.resources.FriggPrivateSubnet2RouteTableAssociation = {
|
|
1867
1646
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1868
|
-
UpdateReplacePolicy: 'Delete',
|
|
1869
1647
|
Properties: {
|
|
1870
1648
|
SubnetId: subnet2Id,
|
|
1871
1649
|
RouteTableId: routeTableId,
|
|
@@ -1883,7 +1661,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
1883
1661
|
// Stack-managed resources should be reused, not recreated
|
|
1884
1662
|
const stackManagedEndpoints = {
|
|
1885
1663
|
s3: discoveredResources.s3VpcEndpointId && typeof discoveredResources.s3VpcEndpointId === 'string',
|
|
1886
|
-
dynamodb: discoveredResources.
|
|
1664
|
+
dynamodb: discoveredResources.dynamoDbVpcEndpointId && typeof discoveredResources.dynamoDbVpcEndpointId === 'string',
|
|
1887
1665
|
kms: discoveredResources.kmsVpcEndpointId && typeof discoveredResources.kmsVpcEndpointId === 'string',
|
|
1888
1666
|
secretsManager: discoveredResources.secretsManagerVpcEndpointId && typeof discoveredResources.secretsManagerVpcEndpointId === 'string',
|
|
1889
1667
|
sqs: discoveredResources.sqsVpcEndpointId && typeof discoveredResources.sqsVpcEndpointId === 'string',
|