@friggframework/devtools 2.0.0--canary.490.5a16b80.0 → 2.0.0--canary.490.4043720.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.
|
@@ -28,6 +28,9 @@ class CloudFormationDiscovery {
|
|
|
28
28
|
*/
|
|
29
29
|
async discoverFromStack(stackName) {
|
|
30
30
|
try {
|
|
31
|
+
// Store stack name for use in helper methods
|
|
32
|
+
this.currentStackName = stackName;
|
|
33
|
+
|
|
31
34
|
// Try to get the stack
|
|
32
35
|
const stack = await this.provider.describeStack(stackName);
|
|
33
36
|
|
|
@@ -118,11 +121,10 @@ class CloudFormationDiscovery {
|
|
|
118
121
|
* We query EC2 to get the actual VPC ID, NAT Gateway ID, and subnet IDs from the route table.
|
|
119
122
|
*
|
|
120
123
|
* @private
|
|
121
|
-
* @param {string} stackName - Stack name
|
|
122
124
|
* @param {Array} resources - CloudFormation stack resources
|
|
123
125
|
* @param {Object} discovered - Object to populate with discovered resources
|
|
124
126
|
*/
|
|
125
|
-
async _extractExternalReferencesFromStackResources(
|
|
127
|
+
async _extractExternalReferencesFromStackResources(resources, discovered) {
|
|
126
128
|
if (!this.provider || !this.provider.getEC2Client) {
|
|
127
129
|
console.log(' ℹ Skipping external reference extraction (EC2 client not available)');
|
|
128
130
|
return;
|
|
@@ -444,7 +446,7 @@ class CloudFormationDiscovery {
|
|
|
444
446
|
|
|
445
447
|
// Extract VPC ID and other external references from routing resource properties
|
|
446
448
|
// This handles the pattern where VPC is external but routing is in the stack
|
|
447
|
-
await this._extractExternalReferencesFromStackResources(
|
|
449
|
+
await this._extractExternalReferencesFromStackResources(resources, discovered);
|
|
448
450
|
|
|
449
451
|
// If we have a VPC ID but no subnet IDs, query EC2 for Frigg-managed subnets
|
|
450
452
|
if (discovered.defaultVpcId && this.provider &&
|
|
@@ -693,6 +693,116 @@ describe('CloudFormationDiscovery', () => {
|
|
|
693
693
|
expect(result.s3VpcEndpointId).toBe('vpce-legacy-s3');
|
|
694
694
|
expect(result.dynamoDbVpcEndpointId).toBe('vpce-legacy-ddb');
|
|
695
695
|
});
|
|
696
|
+
|
|
697
|
+
it('should extract FriggLambdaSecurityGroup from stack', async () => {
|
|
698
|
+
const mockStack = {
|
|
699
|
+
StackName: 'test-stack',
|
|
700
|
+
Outputs: [],
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
const mockResources = [
|
|
704
|
+
{
|
|
705
|
+
LogicalResourceId: 'FriggLambdaSecurityGroup',
|
|
706
|
+
PhysicalResourceId: 'sg-01002240c6a446202',
|
|
707
|
+
ResourceType: 'AWS::EC2::SecurityGroup',
|
|
708
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
LogicalResourceId: 'FriggLambdaRouteTable',
|
|
712
|
+
PhysicalResourceId: 'rtb-08af43bbf0775602d',
|
|
713
|
+
ResourceType: 'AWS::EC2::RouteTable',
|
|
714
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
715
|
+
},
|
|
716
|
+
];
|
|
717
|
+
|
|
718
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
719
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
720
|
+
|
|
721
|
+
const result = await cfDiscovery.discoverFromStack('test-stack');
|
|
722
|
+
|
|
723
|
+
// Lambda security group should be extracted
|
|
724
|
+
expect(result.lambdaSecurityGroupId).toBe('sg-01002240c6a446202');
|
|
725
|
+
expect(result.defaultSecurityGroupId).toBe('sg-01002240c6a446202');
|
|
726
|
+
expect(result.existingLogicalIds).toContain('FriggLambdaSecurityGroup');
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
it('should support FriggPrivateRoute naming for NAT routes', async () => {
|
|
730
|
+
const mockStack = {
|
|
731
|
+
StackName: 'test-stack',
|
|
732
|
+
Outputs: [],
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
const mockResources = [
|
|
736
|
+
{
|
|
737
|
+
LogicalResourceId: 'FriggLambdaRouteTable',
|
|
738
|
+
PhysicalResourceId: 'rtb-123',
|
|
739
|
+
ResourceType: 'AWS::EC2::RouteTable',
|
|
740
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
LogicalResourceId: 'FriggPrivateRoute',
|
|
744
|
+
PhysicalResourceId: 'rtb-123|0.0.0.0/0',
|
|
745
|
+
ResourceType: 'AWS::EC2::Route',
|
|
746
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
747
|
+
},
|
|
748
|
+
];
|
|
749
|
+
|
|
750
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
751
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
752
|
+
|
|
753
|
+
const result = await cfDiscovery.discoverFromStack('test-stack');
|
|
754
|
+
|
|
755
|
+
// Both FriggNATRoute and FriggPrivateRoute should be recognized
|
|
756
|
+
expect(result.natRoute).toBe('rtb-123|0.0.0.0/0');
|
|
757
|
+
expect(result.routeTableId).toBe('rtb-123');
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
it('should extract external references from route table without stackName error', async () => {
|
|
761
|
+
const mockStack = {
|
|
762
|
+
StackName: 'test-stack',
|
|
763
|
+
Outputs: [],
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
const mockResources = [
|
|
767
|
+
{
|
|
768
|
+
LogicalResourceId: 'FriggLambdaRouteTable',
|
|
769
|
+
PhysicalResourceId: 'rtb-real-id',
|
|
770
|
+
ResourceType: 'AWS::EC2::RouteTable',
|
|
771
|
+
ResourceStatus: 'UPDATE_COMPLETE',
|
|
772
|
+
},
|
|
773
|
+
];
|
|
774
|
+
|
|
775
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
776
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
777
|
+
|
|
778
|
+
// Mock EC2 DescribeRouteTables to return route table with VPC info
|
|
779
|
+
mockProvider.getEC2Client = jest.fn().mockReturnValue({
|
|
780
|
+
send: jest.fn().mockResolvedValue({
|
|
781
|
+
RouteTables: [{
|
|
782
|
+
RouteTableId: 'rtb-real-id',
|
|
783
|
+
VpcId: 'vpc-extracted',
|
|
784
|
+
Routes: [
|
|
785
|
+
{ NatGatewayId: 'nat-extracted', DestinationCidrBlock: '0.0.0.0/0' }
|
|
786
|
+
],
|
|
787
|
+
Associations: [
|
|
788
|
+
{ SubnetId: 'subnet-1' },
|
|
789
|
+
{ SubnetId: 'subnet-2' }
|
|
790
|
+
]
|
|
791
|
+
}]
|
|
792
|
+
})
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
const result = await cfDiscovery.discoverFromStack('test-stack');
|
|
796
|
+
|
|
797
|
+
// Should extract VPC, NAT, and subnets from route table
|
|
798
|
+
expect(result.defaultVpcId).toBe('vpc-extracted');
|
|
799
|
+
expect(result.existingNatGatewayId).toBe('nat-extracted');
|
|
800
|
+
expect(result.privateSubnetId1).toBe('subnet-1');
|
|
801
|
+
expect(result.privateSubnetId2).toBe('subnet-2');
|
|
802
|
+
|
|
803
|
+
// Should NOT throw 'stackName is not defined' error
|
|
804
|
+
expect(result).toBeDefined();
|
|
805
|
+
});
|
|
696
806
|
});
|
|
697
807
|
});
|
|
698
808
|
|
|
@@ -415,6 +415,42 @@ describe('Resource Discovery', () => {
|
|
|
415
415
|
delete process.env.SLS_STAGE;
|
|
416
416
|
});
|
|
417
417
|
|
|
418
|
+
it('should recognize routing infrastructure as useful data', async () => {
|
|
419
|
+
const appDefinition = {
|
|
420
|
+
name: 'test-app',
|
|
421
|
+
vpc: { enable: true },
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
process.env.SLS_STAGE = 'production';
|
|
425
|
+
|
|
426
|
+
// Mock CloudFormation discovery to return routing infrastructure but no VPC resource
|
|
427
|
+
const mockCloudFormationDiscovery = {
|
|
428
|
+
discoverFromStack: jest.fn().mockResolvedValue({
|
|
429
|
+
fromCloudFormationStack: true,
|
|
430
|
+
routeTableId: 'rtb-123',
|
|
431
|
+
natRoute: 'rtb-123|0.0.0.0/0',
|
|
432
|
+
vpcEndpoints: {
|
|
433
|
+
s3: 'vpce-s3',
|
|
434
|
+
dynamodb: 'vpce-ddb'
|
|
435
|
+
},
|
|
436
|
+
existingLogicalIds: ['FriggLambdaRouteTable', 'FriggNATRoute']
|
|
437
|
+
// NO defaultVpcId, NO defaultKmsKeyId, NO auroraClusterId
|
|
438
|
+
})
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const { CloudFormationDiscovery } = require('./cloudformation-discovery');
|
|
442
|
+
CloudFormationDiscovery.mockImplementation(() => mockCloudFormationDiscovery);
|
|
443
|
+
|
|
444
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
445
|
+
|
|
446
|
+
// Should use CloudFormation data without falling back to AWS API
|
|
447
|
+
expect(result.routeTableId).toBe('rtb-123');
|
|
448
|
+
expect(result.vpcEndpoints.s3).toBe('vpce-s3');
|
|
449
|
+
|
|
450
|
+
// Should NOT call AWS API discovery
|
|
451
|
+
expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
|
|
452
|
+
});
|
|
453
|
+
|
|
418
454
|
it('should include secrets in SSM discovery by default', async () => {
|
|
419
455
|
const appDefinition = {
|
|
420
456
|
ssm: { enable: true },
|
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.490.
|
|
4
|
+
"version": "2.0.0--canary.490.4043720.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.490.
|
|
20
|
-
"@friggframework/schemas": "2.0.0--canary.490.
|
|
21
|
-
"@friggframework/test": "2.0.0--canary.490.
|
|
19
|
+
"@friggframework/core": "2.0.0--canary.490.4043720.0",
|
|
20
|
+
"@friggframework/schemas": "2.0.0--canary.490.4043720.0",
|
|
21
|
+
"@friggframework/test": "2.0.0--canary.490.4043720.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.490.
|
|
50
|
-
"@friggframework/prettier-config": "2.0.0--canary.490.
|
|
49
|
+
"@friggframework/eslint-config": "2.0.0--canary.490.4043720.0",
|
|
50
|
+
"@friggframework/prettier-config": "2.0.0--canary.490.4043720.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": "4043720019e546de4fb9bf2dbb3265599fef0e3a"
|
|
83
83
|
}
|