@friggframework/devtools 2.0.0--canary.428.3bab734.0 → 2.0.0--canary.428.08c3f6f.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.
|
@@ -147,6 +147,16 @@ class AWSDiscovery {
|
|
|
147
147
|
* @param {string} subnetId - The subnet ID to check
|
|
148
148
|
* @returns {Promise<boolean>} True if subnet is private, false if public
|
|
149
149
|
*/
|
|
150
|
+
/**
|
|
151
|
+
* Validate if a subnet is truly public (has IGW route)
|
|
152
|
+
* @param {string} subnetId - The subnet ID to validate
|
|
153
|
+
* @returns {Promise<boolean>} true if public (has IGW route), false if private
|
|
154
|
+
*/
|
|
155
|
+
async isSubnetPublic(subnetId) {
|
|
156
|
+
const isPrivate = await this.isSubnetPrivate(subnetId);
|
|
157
|
+
return !isPrivate;
|
|
158
|
+
}
|
|
159
|
+
|
|
150
160
|
async isSubnetPrivate(subnetId) {
|
|
151
161
|
try {
|
|
152
162
|
// First, get the subnet details to find its VPC
|
|
@@ -207,13 +217,25 @@ class AWSDiscovery {
|
|
|
207
217
|
}
|
|
208
218
|
|
|
209
219
|
// Check if route table has a route to an Internet Gateway
|
|
220
|
+
let hasIgwRoute = false;
|
|
221
|
+
let gatewayId = null;
|
|
222
|
+
|
|
210
223
|
for (const route of routeTable.Routes || []) {
|
|
211
224
|
if (route.GatewayId && route.GatewayId.startsWith('igw-')) {
|
|
212
|
-
|
|
225
|
+
hasIgwRoute = true;
|
|
226
|
+
gatewayId = route.GatewayId;
|
|
227
|
+
break;
|
|
213
228
|
}
|
|
214
229
|
}
|
|
215
|
-
|
|
216
|
-
|
|
230
|
+
|
|
231
|
+
// Enhanced logging for validation
|
|
232
|
+
if (hasIgwRoute) {
|
|
233
|
+
console.log(`✅ Subnet ${subnetId} is PUBLIC (has route to IGW ${gatewayId})`);
|
|
234
|
+
return false; // It's a public subnet
|
|
235
|
+
} else {
|
|
236
|
+
console.log(`🔒 Subnet ${subnetId} is PRIVATE (no IGW route found)`);
|
|
237
|
+
return true; // No IGW route found, it's private
|
|
238
|
+
}
|
|
217
239
|
} catch (error) {
|
|
218
240
|
console.warn(`Could not determine if subnet ${subnetId} is private:`, error);
|
|
219
241
|
return true; // Default to private for safety
|
|
@@ -392,37 +414,64 @@ class AWSDiscovery {
|
|
|
392
414
|
const response = await this.ec2Client.send(command);
|
|
393
415
|
|
|
394
416
|
if (response.NatGateways && response.NatGateways.length > 0) {
|
|
395
|
-
//
|
|
396
|
-
|
|
417
|
+
// Sort NAT Gateways to prioritize Frigg-managed ones
|
|
418
|
+
const sortedNatGateways = response.NatGateways.sort((a, b) => {
|
|
419
|
+
const aIsFrigg = a.Tags && a.Tags.some(tag =>
|
|
420
|
+
(tag.Key === 'ManagedBy' && tag.Value === 'Frigg') ||
|
|
421
|
+
(tag.Key === 'Name' && tag.Value.includes('frigg'))
|
|
422
|
+
);
|
|
423
|
+
const bIsFrigg = b.Tags && b.Tags.some(tag =>
|
|
424
|
+
(tag.Key === 'ManagedBy' && tag.Value === 'Frigg') ||
|
|
425
|
+
(tag.Key === 'Name' && tag.Value.includes('frigg'))
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
if (aIsFrigg && !bIsFrigg) return -1;
|
|
429
|
+
if (!aIsFrigg && bIsFrigg) return 1;
|
|
430
|
+
return 0;
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Check each NAT Gateway to ensure it's properly configured
|
|
434
|
+
for (const natGateway of sortedNatGateways) {
|
|
397
435
|
const subnetId = natGateway.SubnetId;
|
|
398
436
|
const isPrivate = await this.isSubnetPrivate(subnetId);
|
|
399
437
|
|
|
400
|
-
if
|
|
401
|
-
console.warn(`WARNING: NAT Gateway ${natGateway.NatGatewayId} is in private subnet ${subnetId} - this will not work!`);
|
|
402
|
-
console.warn('NAT Gateways MUST be placed in public subnets with Internet Gateway routes');
|
|
403
|
-
console.warn('Skipping this misconfigured NAT Gateway...');
|
|
404
|
-
continue; // Skip this NAT Gateway
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Check if it's a Frigg-tagged NAT Gateway
|
|
438
|
+
// Check if it's a Frigg-managed NAT Gateway
|
|
408
439
|
const isFriggNat = natGateway.Tags && natGateway.Tags.some(tag =>
|
|
409
|
-
tag.Key === '
|
|
440
|
+
(tag.Key === 'ManagedBy' && tag.Value === 'Frigg') ||
|
|
441
|
+
(tag.Key === 'Name' && tag.Value.includes('frigg'))
|
|
410
442
|
);
|
|
411
443
|
|
|
444
|
+
if (isPrivate) {
|
|
445
|
+
// NAT Gateway appears to be in a private subnet
|
|
446
|
+
// This could be due to route table misconfiguration
|
|
447
|
+
console.warn(`WARNING: NAT Gateway ${natGateway.NatGatewayId} is in subnet ${subnetId} which appears to be private`);
|
|
448
|
+
|
|
449
|
+
if (isFriggNat) {
|
|
450
|
+
console.warn('This is a Frigg-managed NAT Gateway that may have been misconfigured by route table changes');
|
|
451
|
+
console.warn('Consider enabling selfHeal: true to fix this automatically');
|
|
452
|
+
// Return it anyway if it's Frigg-managed - we can fix the routes
|
|
453
|
+
return natGateway;
|
|
454
|
+
} else {
|
|
455
|
+
console.warn('NAT Gateways MUST be placed in public subnets with Internet Gateway routes');
|
|
456
|
+
console.warn('Skipping this misconfigured NAT Gateway...');
|
|
457
|
+
continue; // Skip non-Frigg NAT Gateways in private subnets
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
412
461
|
if (isFriggNat) {
|
|
413
|
-
console.log(`Found existing Frigg NAT Gateway
|
|
462
|
+
console.log(`Found existing Frigg-managed NAT Gateway: ${natGateway.NatGatewayId}`);
|
|
414
463
|
return natGateway;
|
|
415
464
|
}
|
|
416
465
|
|
|
417
|
-
//
|
|
466
|
+
// Return first valid NAT Gateway that's in a public subnet
|
|
418
467
|
console.log(`Found existing NAT Gateway in public subnet: ${natGateway.NatGatewayId}`);
|
|
419
|
-
return natGateway;
|
|
468
|
+
return natGateway;
|
|
420
469
|
}
|
|
421
470
|
|
|
422
|
-
// All NAT Gateways are in private subnets
|
|
423
|
-
console.error(`ERROR: Found ${response.NatGateways.length} NAT Gateway(s) but all are in private subnets!`);
|
|
424
|
-
console.error('These NAT Gateways will not provide internet connectivity');
|
|
425
|
-
console.error('
|
|
471
|
+
// All non-Frigg NAT Gateways are in private subnets
|
|
472
|
+
console.error(`ERROR: Found ${response.NatGateways.length} NAT Gateway(s) but all non-Frigg ones are in private subnets!`);
|
|
473
|
+
console.error('These NAT Gateways will not provide internet connectivity without route table fixes');
|
|
474
|
+
console.error('Enable selfHeal: true to fix automatically or create a new NAT Gateway');
|
|
426
475
|
return null; // Return null to trigger creation of new NAT Gateway
|
|
427
476
|
}
|
|
428
477
|
|
|
@@ -514,6 +563,221 @@ class AWSDiscovery {
|
|
|
514
563
|
}
|
|
515
564
|
}
|
|
516
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Find Frigg-managed resources by tags
|
|
568
|
+
* @param {string} vpcId - The VPC ID to search within
|
|
569
|
+
* @returns {Promise<Object>} Object containing Frigg-managed resources
|
|
570
|
+
*/
|
|
571
|
+
async findFriggManagedResources(vpcId) {
|
|
572
|
+
try {
|
|
573
|
+
const resources = {
|
|
574
|
+
natGateways: [],
|
|
575
|
+
elasticIps: [],
|
|
576
|
+
subnets: [],
|
|
577
|
+
routeTables: []
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
// Find NAT Gateways with Frigg tags
|
|
581
|
+
const natCommand = new DescribeNatGatewaysCommand({
|
|
582
|
+
Filter: [
|
|
583
|
+
{ Name: 'vpc-id', Values: [vpcId] },
|
|
584
|
+
{ Name: 'state', Values: ['available'] }
|
|
585
|
+
]
|
|
586
|
+
});
|
|
587
|
+
const natResponse = await this.ec2Client.send(natCommand);
|
|
588
|
+
|
|
589
|
+
if (natResponse.NatGateways) {
|
|
590
|
+
resources.natGateways = natResponse.NatGateways.filter(nat =>
|
|
591
|
+
nat.Tags && nat.Tags.some(tag =>
|
|
592
|
+
tag.Key === 'ManagedBy' && tag.Value === 'Frigg'
|
|
593
|
+
)
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Find Elastic IPs with Frigg tags
|
|
598
|
+
const eipCommand = new DescribeAddressesCommand({});
|
|
599
|
+
const eipResponse = await this.ec2Client.send(eipCommand);
|
|
600
|
+
|
|
601
|
+
if (eipResponse.Addresses) {
|
|
602
|
+
resources.elasticIps = eipResponse.Addresses.filter(eip =>
|
|
603
|
+
eip.Tags && eip.Tags.some(tag =>
|
|
604
|
+
tag.Key === 'ManagedBy' && tag.Value === 'Frigg'
|
|
605
|
+
)
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Find Route Tables with Frigg tags
|
|
610
|
+
const rtCommand = new DescribeRouteTablesCommand({
|
|
611
|
+
Filters: [
|
|
612
|
+
{ Name: 'vpc-id', Values: [vpcId] }
|
|
613
|
+
]
|
|
614
|
+
});
|
|
615
|
+
const rtResponse = await this.ec2Client.send(rtCommand);
|
|
616
|
+
|
|
617
|
+
if (rtResponse.RouteTables) {
|
|
618
|
+
resources.routeTables = rtResponse.RouteTables.filter(rt =>
|
|
619
|
+
rt.Tags && rt.Tags.some(tag =>
|
|
620
|
+
tag.Key === 'ManagedBy' && tag.Value === 'Frigg'
|
|
621
|
+
)
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
return resources;
|
|
626
|
+
} catch (error) {
|
|
627
|
+
console.error('Error finding Frigg-managed resources:', error);
|
|
628
|
+
return {
|
|
629
|
+
natGateways: [],
|
|
630
|
+
elasticIps: [],
|
|
631
|
+
subnets: [],
|
|
632
|
+
routeTables: []
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Detect misconfigured resources that need healing
|
|
639
|
+
* @param {string} vpcId - The VPC ID to check
|
|
640
|
+
* @returns {Promise<Object>} Object containing misconfiguration details
|
|
641
|
+
*/
|
|
642
|
+
async detectMisconfiguredResources(vpcId) {
|
|
643
|
+
try {
|
|
644
|
+
const misconfigurations = {
|
|
645
|
+
natGatewaysInPrivateSubnets: [],
|
|
646
|
+
orphanedElasticIps: [],
|
|
647
|
+
misconfiguredRouteTables: [],
|
|
648
|
+
privateSubnetsWithoutNatRoute: []
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
// Find NAT Gateways in private subnets
|
|
652
|
+
const natCommand = new DescribeNatGatewaysCommand({
|
|
653
|
+
Filter: [
|
|
654
|
+
{ Name: 'vpc-id', Values: [vpcId] },
|
|
655
|
+
{ Name: 'state', Values: ['available'] }
|
|
656
|
+
]
|
|
657
|
+
});
|
|
658
|
+
const natResponse = await this.ec2Client.send(natCommand);
|
|
659
|
+
|
|
660
|
+
if (natResponse.NatGateways) {
|
|
661
|
+
for (const nat of natResponse.NatGateways) {
|
|
662
|
+
const isPrivate = await this.isSubnetPrivate(nat.SubnetId);
|
|
663
|
+
if (isPrivate) {
|
|
664
|
+
misconfigurations.natGatewaysInPrivateSubnets.push({
|
|
665
|
+
natGatewayId: nat.NatGatewayId,
|
|
666
|
+
subnetId: nat.SubnetId,
|
|
667
|
+
tags: nat.Tags
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Find orphaned Elastic IPs
|
|
674
|
+
const eipCommand = new DescribeAddressesCommand({});
|
|
675
|
+
const eipResponse = await this.ec2Client.send(eipCommand);
|
|
676
|
+
|
|
677
|
+
if (eipResponse.Addresses) {
|
|
678
|
+
for (const eip of eipResponse.Addresses) {
|
|
679
|
+
if (!eip.InstanceId && !eip.NetworkInterfaceId && !eip.AssociationId) {
|
|
680
|
+
// Check if it's Frigg-managed
|
|
681
|
+
const isFriggManaged = eip.Tags && eip.Tags.some(tag =>
|
|
682
|
+
tag.Key === 'ManagedBy' && tag.Value === 'Frigg'
|
|
683
|
+
);
|
|
684
|
+
if (isFriggManaged) {
|
|
685
|
+
misconfigurations.orphanedElasticIps.push({
|
|
686
|
+
allocationId: eip.AllocationId,
|
|
687
|
+
publicIp: eip.PublicIp,
|
|
688
|
+
tags: eip.Tags
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Find private subnets without NAT route
|
|
696
|
+
const subnets = await this.findPrivateSubnets(vpcId);
|
|
697
|
+
const routeTables = await this.findRouteTables(vpcId);
|
|
698
|
+
|
|
699
|
+
for (const subnet of subnets) {
|
|
700
|
+
let hasNatRoute = false;
|
|
701
|
+
|
|
702
|
+
// Find route table for this subnet
|
|
703
|
+
for (const rt of routeTables) {
|
|
704
|
+
const isAssociated = rt.Associations && rt.Associations.some(
|
|
705
|
+
assoc => assoc.SubnetId === subnet.SubnetId
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
if (isAssociated) {
|
|
709
|
+
hasNatRoute = rt.Routes && rt.Routes.some(
|
|
710
|
+
route => route.NatGatewayId &&
|
|
711
|
+
route.DestinationCidrBlock === '0.0.0.0/0'
|
|
712
|
+
);
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (!hasNatRoute) {
|
|
718
|
+
misconfigurations.privateSubnetsWithoutNatRoute.push({
|
|
719
|
+
subnetId: subnet.SubnetId,
|
|
720
|
+
availabilityZone: subnet.AvailabilityZone
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return misconfigurations;
|
|
726
|
+
} catch (error) {
|
|
727
|
+
console.error('Error detecting misconfigurations:', error);
|
|
728
|
+
return {
|
|
729
|
+
natGatewaysInPrivateSubnets: [],
|
|
730
|
+
orphanedElasticIps: [],
|
|
731
|
+
misconfiguredRouteTables: [],
|
|
732
|
+
privateSubnetsWithoutNatRoute: []
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Get healing recommendations based on detected issues
|
|
739
|
+
* @param {Object} misconfigurations - Object from detectMisconfiguredResources
|
|
740
|
+
* @returns {Array} Array of healing recommendations
|
|
741
|
+
*/
|
|
742
|
+
getHealingRecommendations(misconfigurations) {
|
|
743
|
+
const recommendations = [];
|
|
744
|
+
|
|
745
|
+
if (misconfigurations.natGatewaysInPrivateSubnets.length > 0) {
|
|
746
|
+
recommendations.push({
|
|
747
|
+
severity: 'critical',
|
|
748
|
+
issue: 'NAT Gateway in private subnet',
|
|
749
|
+
recommendation: 'Recreate NAT Gateway in public subnet or fix route tables',
|
|
750
|
+
affectedResources: misconfigurations.natGatewaysInPrivateSubnets.map(n => n.natGatewayId)
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (misconfigurations.orphanedElasticIps.length > 0) {
|
|
755
|
+
recommendations.push({
|
|
756
|
+
severity: 'warning',
|
|
757
|
+
issue: 'Orphaned Elastic IPs',
|
|
758
|
+
recommendation: 'Release unused Elastic IPs to avoid charges',
|
|
759
|
+
affectedResources: misconfigurations.orphanedElasticIps.map(e => e.allocationId)
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (misconfigurations.privateSubnetsWithoutNatRoute.length > 0) {
|
|
764
|
+
recommendations.push({
|
|
765
|
+
severity: 'critical',
|
|
766
|
+
issue: 'Private subnets without NAT route',
|
|
767
|
+
recommendation: 'Add NAT Gateway route to private subnet route tables',
|
|
768
|
+
affectedResources: misconfigurations.privateSubnetsWithoutNatRoute.map(s => s.subnetId)
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Sort by severity
|
|
773
|
+
recommendations.sort((a, b) => {
|
|
774
|
+
const severityOrder = { critical: 0, warning: 1, info: 2 };
|
|
775
|
+
return severityOrder[a.severity] - severityOrder[b.severity];
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
return recommendations;
|
|
779
|
+
}
|
|
780
|
+
|
|
517
781
|
/**
|
|
518
782
|
* Discover all AWS resources needed for Frigg deployment
|
|
519
783
|
* @returns {Promise<Object>} Object containing discovered resource IDs:
|
|
@@ -621,6 +885,126 @@ class AWSDiscovery {
|
|
|
621
885
|
return null;
|
|
622
886
|
}
|
|
623
887
|
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Find Frigg-managed resources by tags
|
|
891
|
+
* @param {string} serviceName - The service name to search for
|
|
892
|
+
* @param {string} stage - The deployment stage
|
|
893
|
+
* @returns {Promise<Object>} Object containing found Frigg-managed resources
|
|
894
|
+
*/
|
|
895
|
+
async findFriggManagedResources(serviceName, stage) {
|
|
896
|
+
try {
|
|
897
|
+
const results = {
|
|
898
|
+
natGateways: [],
|
|
899
|
+
elasticIps: [],
|
|
900
|
+
routeTables: [],
|
|
901
|
+
subnets: [],
|
|
902
|
+
securityGroups: []
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
// Common filter for Frigg-managed resources
|
|
906
|
+
const friggFilters = [
|
|
907
|
+
{
|
|
908
|
+
Name: 'tag:ManagedBy',
|
|
909
|
+
Values: ['Frigg']
|
|
910
|
+
}
|
|
911
|
+
];
|
|
912
|
+
|
|
913
|
+
if (serviceName) {
|
|
914
|
+
friggFilters.push({
|
|
915
|
+
Name: 'tag:Service',
|
|
916
|
+
Values: [serviceName]
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (stage) {
|
|
921
|
+
friggFilters.push({
|
|
922
|
+
Name: 'tag:Stage',
|
|
923
|
+
Values: [stage]
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// Find NAT Gateways
|
|
928
|
+
try {
|
|
929
|
+
const natCommand = new DescribeNatGatewaysCommand({
|
|
930
|
+
Filter: [
|
|
931
|
+
...friggFilters,
|
|
932
|
+
{
|
|
933
|
+
Name: 'state',
|
|
934
|
+
Values: ['available']
|
|
935
|
+
}
|
|
936
|
+
]
|
|
937
|
+
});
|
|
938
|
+
const natResponse = await this.ec2Client.send(natCommand);
|
|
939
|
+
results.natGateways = natResponse.NatGateways || [];
|
|
940
|
+
} catch (err) {
|
|
941
|
+
console.warn('Error finding Frigg NAT Gateways:', err.message);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Find Elastic IPs
|
|
945
|
+
try {
|
|
946
|
+
const eipCommand = new DescribeAddressesCommand({
|
|
947
|
+
Filters: friggFilters
|
|
948
|
+
});
|
|
949
|
+
const eipResponse = await this.ec2Client.send(eipCommand);
|
|
950
|
+
results.elasticIps = eipResponse.Addresses || [];
|
|
951
|
+
} catch (err) {
|
|
952
|
+
console.warn('Error finding Frigg Elastic IPs:', err.message);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Find Route Tables
|
|
956
|
+
try {
|
|
957
|
+
const rtCommand = new DescribeRouteTablesCommand({
|
|
958
|
+
Filters: friggFilters
|
|
959
|
+
});
|
|
960
|
+
const rtResponse = await this.ec2Client.send(rtCommand);
|
|
961
|
+
results.routeTables = rtResponse.RouteTables || [];
|
|
962
|
+
} catch (err) {
|
|
963
|
+
console.warn('Error finding Frigg Route Tables:', err.message);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Find Subnets
|
|
967
|
+
try {
|
|
968
|
+
const subnetCommand = new DescribeSubnetsCommand({
|
|
969
|
+
Filters: friggFilters
|
|
970
|
+
});
|
|
971
|
+
const subnetResponse = await this.ec2Client.send(subnetCommand);
|
|
972
|
+
results.subnets = subnetResponse.Subnets || [];
|
|
973
|
+
} catch (err) {
|
|
974
|
+
console.warn('Error finding Frigg Subnets:', err.message);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// Find Security Groups
|
|
978
|
+
try {
|
|
979
|
+
const sgCommand = new DescribeSecurityGroupsCommand({
|
|
980
|
+
Filters: friggFilters
|
|
981
|
+
});
|
|
982
|
+
const sgResponse = await this.ec2Client.send(sgCommand);
|
|
983
|
+
results.securityGroups = sgResponse.SecurityGroups || [];
|
|
984
|
+
} catch (err) {
|
|
985
|
+
console.warn('Error finding Frigg Security Groups:', err.message);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
console.log('Found Frigg-managed resources:', {
|
|
989
|
+
natGateways: results.natGateways.length,
|
|
990
|
+
elasticIps: results.elasticIps.length,
|
|
991
|
+
routeTables: results.routeTables.length,
|
|
992
|
+
subnets: results.subnets.length,
|
|
993
|
+
securityGroups: results.securityGroups.length
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
return results;
|
|
997
|
+
} catch (error) {
|
|
998
|
+
console.error('Error finding Frigg-managed resources:', error);
|
|
999
|
+
return {
|
|
1000
|
+
natGateways: [],
|
|
1001
|
+
elasticIps: [],
|
|
1002
|
+
routeTables: [],
|
|
1003
|
+
subnets: [],
|
|
1004
|
+
securityGroups: []
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
624
1008
|
}
|
|
625
1009
|
|
|
626
1010
|
module.exports = { AWSDiscovery };
|