@friggframework/devtools 2.0.0--canary.487.63ed8db.0 → 2.0.0--canary.490.eec7dcd.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.
|
@@ -216,6 +216,27 @@ class CloudFormationDiscovery {
|
|
|
216
216
|
discovered.natGatewayId = PhysicalResourceId;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// Route Table (Lambda route table for external VPC pattern)
|
|
220
|
+
if (LogicalResourceId === 'FriggLambdaRouteTable' && ResourceType === 'AWS::EC2::RouteTable') {
|
|
221
|
+
discovered.routeTableId = PhysicalResourceId;
|
|
222
|
+
discovered.privateRouteTableId = PhysicalResourceId;
|
|
223
|
+
console.log(` ✓ Found route table in stack: ${PhysicalResourceId}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// NAT Route (proves NAT configuration exists)
|
|
227
|
+
if (LogicalResourceId === 'FriggNATRoute' && ResourceType === 'AWS::EC2::Route') {
|
|
228
|
+
discovered.natRoute = PhysicalResourceId;
|
|
229
|
+
console.log(` ✓ Found NAT route in stack`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Route Table Associations (links subnets to route table)
|
|
233
|
+
if (LogicalResourceId.includes('RouteAssociation') && ResourceType === 'AWS::EC2::SubnetRouteTableAssociation') {
|
|
234
|
+
if (!discovered.routeTableAssociations) {
|
|
235
|
+
discovered.routeTableAssociations = [];
|
|
236
|
+
}
|
|
237
|
+
discovered.routeTableAssociations.push(PhysicalResourceId);
|
|
238
|
+
}
|
|
239
|
+
|
|
219
240
|
// VPC - direct extraction (primary method)
|
|
220
241
|
if (LogicalResourceId === 'FriggVPC' && ResourceType === 'AWS::EC2::VPC') {
|
|
221
242
|
discovered.defaultVpcId = PhysicalResourceId;
|
|
@@ -278,21 +299,46 @@ class CloudFormationDiscovery {
|
|
|
278
299
|
discovered.vpcEndpointSecurityGroupId = PhysicalResourceId;
|
|
279
300
|
}
|
|
280
301
|
|
|
281
|
-
// VPC Endpoints
|
|
282
|
-
|
|
302
|
+
// VPC Endpoints - support both old and new naming conventions
|
|
303
|
+
// Initialize vpcEndpoints object for structured access
|
|
304
|
+
if (!discovered.vpcEndpoints) {
|
|
305
|
+
discovered.vpcEndpoints = {};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// S3 Endpoint (both naming patterns)
|
|
309
|
+
if ((LogicalResourceId === 'FriggS3VPCEndpoint' || LogicalResourceId === 'VPCEndpointS3') &&
|
|
310
|
+
ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
283
311
|
discovered.s3VpcEndpointId = PhysicalResourceId;
|
|
312
|
+
discovered.vpcEndpoints.s3 = PhysicalResourceId;
|
|
313
|
+
console.log(` ✓ Found S3 VPC endpoint in stack: ${PhysicalResourceId}`);
|
|
284
314
|
}
|
|
285
|
-
|
|
315
|
+
|
|
316
|
+
// DynamoDB Endpoint (both naming patterns)
|
|
317
|
+
if ((LogicalResourceId === 'FriggDynamoDBVPCEndpoint' || LogicalResourceId === 'VPCEndpointDynamoDB') &&
|
|
318
|
+
ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
286
319
|
discovered.dynamoDbVpcEndpointId = PhysicalResourceId;
|
|
320
|
+
discovered.vpcEndpoints.dynamodb = PhysicalResourceId;
|
|
321
|
+
console.log(` ✓ Found DynamoDB VPC endpoint in stack: ${PhysicalResourceId}`);
|
|
287
322
|
}
|
|
288
|
-
|
|
323
|
+
|
|
324
|
+
// KMS Endpoint (both naming patterns)
|
|
325
|
+
if ((LogicalResourceId === 'FriggKMSVPCEndpoint' || LogicalResourceId === 'VPCEndpointKMS') &&
|
|
326
|
+
ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
289
327
|
discovered.kmsVpcEndpointId = PhysicalResourceId;
|
|
328
|
+
discovered.vpcEndpoints.kms = PhysicalResourceId;
|
|
329
|
+
console.log(` ✓ Found KMS VPC endpoint in stack: ${PhysicalResourceId}`);
|
|
290
330
|
}
|
|
331
|
+
|
|
332
|
+
// Secrets Manager Endpoint
|
|
291
333
|
if (LogicalResourceId === 'FriggSecretsManagerVPCEndpoint' && ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
292
334
|
discovered.secretsManagerVpcEndpointId = PhysicalResourceId;
|
|
335
|
+
discovered.vpcEndpoints.secretsManager = PhysicalResourceId;
|
|
293
336
|
}
|
|
337
|
+
|
|
338
|
+
// SQS Endpoint
|
|
294
339
|
if (LogicalResourceId === 'FriggSQSVPCEndpoint' && ResourceType === 'AWS::EC2::VPCEndpoint') {
|
|
295
340
|
discovered.sqsVpcEndpointId = PhysicalResourceId;
|
|
341
|
+
discovered.vpcEndpoints.sqs = PhysicalResourceId;
|
|
296
342
|
}
|
|
297
343
|
}
|
|
298
344
|
|
|
@@ -586,5 +586,113 @@ describe('CloudFormationDiscovery', () => {
|
|
|
586
586
|
expect(mockProvider.describeKmsKey).toHaveBeenCalledWith('alias/test-service-dev-frigg-kms');
|
|
587
587
|
});
|
|
588
588
|
});
|
|
589
|
+
|
|
590
|
+
describe('External VPC with routing infrastructure pattern', () => {
|
|
591
|
+
it('should discover routing resources when VPC is external', async () => {
|
|
592
|
+
// This tests the Frontify pattern: external VPC/subnets/KMS,
|
|
593
|
+
// but stack creates routing infrastructure (route table, NAT route, VPC endpoints)
|
|
594
|
+
const mockStack = {
|
|
595
|
+
StackName: 'create-frigg-app-production',
|
|
596
|
+
Outputs: [],
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const mockResources = [
|
|
600
|
+
{
|
|
601
|
+
LogicalResourceId: 'FriggLambdaRouteTable',
|
|
602
|
+
PhysicalResourceId: 'rtb-0b83aca77ccde20a6',
|
|
603
|
+
ResourceType: 'AWS::EC2::RouteTable',
|
|
604
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
LogicalResourceId: 'FriggNATRoute',
|
|
608
|
+
PhysicalResourceId: 'rtb-0b83aca77ccde20a6|0.0.0.0/0',
|
|
609
|
+
ResourceType: 'AWS::EC2::Route',
|
|
610
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
LogicalResourceId: 'FriggSubnet1RouteAssociation',
|
|
614
|
+
PhysicalResourceId: 'rtbassoc-07245da0b447ca469',
|
|
615
|
+
ResourceType: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
616
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
LogicalResourceId: 'FriggSubnet2RouteAssociation',
|
|
620
|
+
PhysicalResourceId: 'rtbassoc-0806f9783c4ea181f',
|
|
621
|
+
ResourceType: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
622
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
LogicalResourceId: 'VPCEndpointS3',
|
|
626
|
+
PhysicalResourceId: 'vpce-0352ceac2124c14be',
|
|
627
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
628
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
LogicalResourceId: 'VPCEndpointDynamoDB',
|
|
632
|
+
PhysicalResourceId: 'vpce-0b06c4f631199ea68',
|
|
633
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
634
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
635
|
+
},
|
|
636
|
+
];
|
|
637
|
+
|
|
638
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
639
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
640
|
+
|
|
641
|
+
const result = await cfDiscovery.discoverFromStack('create-frigg-app-production');
|
|
642
|
+
|
|
643
|
+
// Verify routing infrastructure was discovered
|
|
644
|
+
expect(result.routeTableId).toBe('rtb-0b83aca77ccde20a6');
|
|
645
|
+
expect(result.privateRouteTableId).toBe('rtb-0b83aca77ccde20a6');
|
|
646
|
+
expect(result.natRoute).toBe('rtb-0b83aca77ccde20a6|0.0.0.0/0');
|
|
647
|
+
expect(result.routeTableAssociations).toEqual([
|
|
648
|
+
'rtbassoc-07245da0b447ca469',
|
|
649
|
+
'rtbassoc-0806f9783c4ea181f',
|
|
650
|
+
]);
|
|
651
|
+
|
|
652
|
+
// Verify VPC endpoints were discovered (both naming conventions)
|
|
653
|
+
expect(result.vpcEndpoints).toBeDefined();
|
|
654
|
+
expect(result.vpcEndpoints.s3).toBe('vpce-0352ceac2124c14be');
|
|
655
|
+
expect(result.vpcEndpoints.dynamodb).toBe('vpce-0b06c4f631199ea68');
|
|
656
|
+
expect(result.s3VpcEndpointId).toBe('vpce-0352ceac2124c14be');
|
|
657
|
+
expect(result.dynamoDbVpcEndpointId).toBe('vpce-0b06c4f631199ea68');
|
|
658
|
+
|
|
659
|
+
// Verify NO VPC/KMS resources (they're external)
|
|
660
|
+
expect(result.defaultVpcId).toBeUndefined();
|
|
661
|
+
expect(result.defaultKmsKeyId).toBeUndefined();
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it('should work with legacy VPC endpoint naming (FriggS3VPCEndpoint)', async () => {
|
|
665
|
+
const mockStack = {
|
|
666
|
+
StackName: 'test-stack',
|
|
667
|
+
Outputs: [],
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
const mockResources = [
|
|
671
|
+
{
|
|
672
|
+
LogicalResourceId: 'FriggS3VPCEndpoint',
|
|
673
|
+
PhysicalResourceId: 'vpce-legacy-s3',
|
|
674
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
675
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
LogicalResourceId: 'FriggDynamoDBVPCEndpoint',
|
|
679
|
+
PhysicalResourceId: 'vpce-legacy-ddb',
|
|
680
|
+
ResourceType: 'AWS::EC2::VPCEndpoint',
|
|
681
|
+
ResourceStatus: 'CREATE_COMPLETE',
|
|
682
|
+
},
|
|
683
|
+
];
|
|
684
|
+
|
|
685
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
686
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
687
|
+
|
|
688
|
+
const result = await cfDiscovery.discoverFromStack('test-stack');
|
|
689
|
+
|
|
690
|
+
// Both naming conventions should work
|
|
691
|
+
expect(result.vpcEndpoints.s3).toBe('vpce-legacy-s3');
|
|
692
|
+
expect(result.vpcEndpoints.dynamodb).toBe('vpce-legacy-ddb');
|
|
693
|
+
expect(result.s3VpcEndpointId).toBe('vpce-legacy-s3');
|
|
694
|
+
expect(result.dynamoDbVpcEndpointId).toBe('vpce-legacy-ddb');
|
|
695
|
+
});
|
|
696
|
+
});
|
|
589
697
|
});
|
|
590
698
|
|
|
@@ -95,11 +95,23 @@ async function gatherDiscoveredResources(appDefinition) {
|
|
|
95
95
|
const cfDiscovery = new CloudFormationDiscovery(provider, { serviceName, stage });
|
|
96
96
|
const stackResources = await cfDiscovery.discoverFromStack(stackName);
|
|
97
97
|
|
|
98
|
-
// Validate CF discovery results -
|
|
99
|
-
const hasVpcData = stackResources?.defaultVpcId;
|
|
100
|
-
const hasKmsData = stackResources?.defaultKmsKeyId;
|
|
101
|
-
const hasAuroraData = stackResources?.auroraClusterId;
|
|
102
|
-
|
|
98
|
+
// Validate CF discovery results - check for ANY useful infrastructure
|
|
99
|
+
const hasVpcData = stackResources?.defaultVpcId; // VPC resource in stack
|
|
100
|
+
const hasKmsData = stackResources?.defaultKmsKeyId; // KMS resource in stack
|
|
101
|
+
const hasAuroraData = stackResources?.auroraClusterId; // Aurora in stack
|
|
102
|
+
|
|
103
|
+
// Check for routing infrastructure (proves VPC config exists even with external VPC)
|
|
104
|
+
const hasRoutingInfra = stackResources?.routeTableId || // FriggLambdaRouteTable
|
|
105
|
+
stackResources?.natRoute || // FriggNATRoute
|
|
106
|
+
stackResources?.vpcEndpoints?.s3 || // VPC endpoints
|
|
107
|
+
stackResources?.vpcEndpoints?.dynamodb;
|
|
108
|
+
|
|
109
|
+
// Stack is useful if it has EITHER actual resources OR routing infrastructure
|
|
110
|
+
const hasSomeUsefulData = hasVpcData || hasKmsData || hasAuroraData || hasRoutingInfra;
|
|
111
|
+
|
|
112
|
+
if (hasRoutingInfra && !hasVpcData) {
|
|
113
|
+
console.log(' ✓ Found VPC routing infrastructure in stack (external VPC pattern)');
|
|
114
|
+
}
|
|
103
115
|
|
|
104
116
|
// Check if we're in isolated mode (each stage gets its own VPC/Aurora)
|
|
105
117
|
const isIsolatedMode = appDefinition.managementMode === 'managed' &&
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.
|
|
4
|
+
"version": "2.0.0--canary.490.eec7dcd.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"@babel/eslint-parser": "^7.18.9",
|
|
17
17
|
"@babel/parser": "^7.25.3",
|
|
18
18
|
"@babel/traverse": "^7.25.3",
|
|
19
|
-
"@friggframework/core": "2.0.0--canary.
|
|
20
|
-
"@friggframework/schemas": "2.0.0--canary.
|
|
21
|
-
"@friggframework/test": "2.0.0--canary.
|
|
19
|
+
"@friggframework/core": "2.0.0--canary.490.eec7dcd.0",
|
|
20
|
+
"@friggframework/schemas": "2.0.0--canary.490.eec7dcd.0",
|
|
21
|
+
"@friggframework/test": "2.0.0--canary.490.eec7dcd.0",
|
|
22
22
|
"@hapi/boom": "^10.0.1",
|
|
23
23
|
"@inquirer/prompts": "^5.3.8",
|
|
24
24
|
"axios": "^1.7.2",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"validate-npm-package-name": "^5.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
50
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
49
|
+
"@friggframework/eslint-config": "2.0.0--canary.490.eec7dcd.0",
|
|
50
|
+
"@friggframework/prettier-config": "2.0.0--canary.490.eec7dcd.0",
|
|
51
51
|
"aws-sdk-client-mock": "^4.1.0",
|
|
52
52
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
53
53
|
"jest": "^30.1.3",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "eec7dcdaf12585353103eb99ebc141dfa60a6743"
|
|
83
83
|
}
|