@friggframework/devtools 2.0.0--canary.428.1c210bc.0 → 2.0.0--canary.428.4968614.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.
@@ -559,8 +559,23 @@ class AWSDiscovery {
559
559
  const response = await this.ec2Client.send(command);
560
560
 
561
561
  if (response.NatGateways && response.NatGateways.length > 0) {
562
+ // Filter out any NAT Gateways that are not truly available
563
+ const availableNatGateways = response.NatGateways.filter(nat => {
564
+ // Double-check the state is truly 'available'
565
+ if (nat.State !== 'available') {
566
+ console.warn(`Skipping NAT Gateway ${nat.NatGatewayId} with state: ${nat.State}`);
567
+ return false;
568
+ }
569
+ return true;
570
+ });
571
+
572
+ if (availableNatGateways.length === 0) {
573
+ console.warn('No truly available NAT Gateways found in VPC');
574
+ return null;
575
+ }
576
+
562
577
  // Sort NAT Gateways to prioritize Frigg-managed ones
563
- const sortedNatGateways = response.NatGateways.sort((a, b) => {
578
+ const sortedNatGateways = availableNatGateways.sort((a, b) => {
564
579
  const aIsFrigg =
565
580
  a.Tags &&
566
581
  a.Tags.some(
@@ -632,7 +647,7 @@ class AWSDiscovery {
632
647
 
633
648
  if (isFriggNat) {
634
649
  console.log(
635
- `Found existing Frigg-managed NAT Gateway: ${natGateway.NatGatewayId}`
650
+ `Found existing Frigg-managed NAT Gateway: ${natGateway.NatGatewayId} (State: ${natGateway.State})`
636
651
  );
637
652
  natGateway._isInPrivateSubnet = false;
638
653
  return natGateway;
@@ -640,7 +655,7 @@ class AWSDiscovery {
640
655
 
641
656
  // Return first valid NAT Gateway that's in a public subnet
642
657
  console.log(
643
- `Found existing NAT Gateway in public subnet: ${natGateway.NatGatewayId}`
658
+ `Found existing NAT Gateway in public subnet: ${natGateway.NatGatewayId} (State: ${natGateway.State})`
644
659
  );
645
660
  natGateway._isInPrivateSubnet = false;
646
661
  return natGateway;
@@ -1252,6 +1267,7 @@ class AWSDiscovery {
1252
1267
 
1253
1268
  return {
1254
1269
  defaultVpcId: vpc.VpcId,
1270
+ vpcCidr: vpc.CidrBlock, // Add VPC CIDR for security group configuration
1255
1271
  defaultSecurityGroupId: securityGroup.GroupId,
1256
1272
  privateSubnetId1: privateSubnets[0]?.SubnetId,
1257
1273
  privateSubnetId2:
@@ -56,6 +56,7 @@ describe('BuildTimeDiscovery', () => {
56
56
  describe('discoverAndCreateConfig', () => {
57
57
  const mockResources = {
58
58
  defaultVpcId: 'vpc-12345678',
59
+ vpcCidr: '172.31.0.0/16',
59
60
  defaultSecurityGroupId: 'sg-12345678',
60
61
  privateSubnetId1: 'subnet-1',
61
62
  privateSubnetId2: 'subnet-2',
@@ -100,6 +101,7 @@ describe('BuildTimeDiscovery', () => {
100
101
  describe('replaceTemplateVariables', () => {
101
102
  const mockResources = {
102
103
  defaultVpcId: 'vpc-12345678',
104
+ vpcCidr: '172.31.0.0/16',
103
105
  defaultSecurityGroupId: 'sg-12345678',
104
106
  privateSubnetId1: 'subnet-1',
105
107
  privateSubnetId2: 'subnet-2',
@@ -225,6 +227,7 @@ describe('BuildTimeDiscovery', () => {
225
227
  describe('preBuildHook', () => {
226
228
  const mockResources = {
227
229
  defaultVpcId: 'vpc-12345678',
230
+ vpcCidr: '172.31.0.0/16',
228
231
  defaultSecurityGroupId: 'sg-12345678',
229
232
  privateSubnetId1: 'subnet-1',
230
233
  privateSubnetId2: 'subnet-2',
@@ -1893,6 +1893,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
1893
1893
  }
1894
1894
 
1895
1895
  // Always add route table and routes (referencing the NAT, whether new or existing)
1896
+ // IMPORTANT: Create a new route table to ensure clean routing configuration
1897
+ // This avoids issues with stale routes pointing to deleted NAT Gateways
1896
1898
  definition.resources.Resources.FriggLambdaRouteTable = {
1897
1899
  Type: 'AWS::EC2::RouteTable',
1898
1900
  Properties: {
@@ -1904,6 +1906,10 @@ const composeServerlessDefinition = async (AppDefinition) => {
1904
1906
  Key: 'Name',
1905
1907
  Value: '${self:service}-${self:provider.stage}-lambda-rt',
1906
1908
  },
1909
+ {
1910
+ Key: 'ManagedBy',
1911
+ Value: 'Frigg',
1912
+ },
1907
1913
  ],
1908
1914
  },
1909
1915
  };
@@ -1914,18 +1920,23 @@ const composeServerlessDefinition = async (AppDefinition) => {
1914
1920
  if (reuseExistingNatGateway) {
1915
1921
  // Use the existing NAT Gateway that we're reusing
1916
1922
  natGatewayIdForRoute = discoveredResources.existingNatGatewayId;
1923
+ console.log(`Using discovered NAT Gateway for routing: ${natGatewayIdForRoute}`);
1917
1924
  } else if (needsNewNatGateway && !reuseExistingNatGateway) {
1918
1925
  // Reference the new NAT Gateway being created
1919
1926
  natGatewayIdForRoute = { Ref: 'FriggNATGateway' };
1927
+ console.log('Using newly created NAT Gateway for routing');
1920
1928
  } else if (discoveredResources.existingNatGatewayId) {
1921
1929
  // Use the existing NAT Gateway ID
1922
1930
  natGatewayIdForRoute = discoveredResources.existingNatGatewayId;
1931
+ console.log(`Using discovered NAT Gateway for routing: ${natGatewayIdForRoute}`);
1923
1932
  } else if (AppDefinition.vpc.natGateway?.id) {
1924
1933
  // Use explicitly provided NAT Gateway ID
1925
1934
  natGatewayIdForRoute = AppDefinition.vpc.natGateway.id;
1935
+ console.log(`Using explicitly provided NAT Gateway for routing: ${natGatewayIdForRoute}`);
1926
1936
  } else if (AppDefinition.vpc.selfHeal === true) {
1927
1937
  // Self-healing enabled but no NAT Gateway - skip NAT route
1928
1938
  natGatewayIdForRoute = null;
1939
+ console.log('No NAT Gateway available - skipping NAT route creation');
1929
1940
  } else {
1930
1941
  throw new Error(
1931
1942
  'Unable to determine NAT Gateway ID for routing. ' +
@@ -1935,7 +1946,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
1935
1946
 
1936
1947
  // Only create NAT route if we have a NAT Gateway
1937
1948
  if (natGatewayIdForRoute) {
1938
- definition.resources.Resources.FriggNATRoute = {
1949
+ console.log(`Creating NAT route: 0.0.0.0/0 ${natGatewayIdForRoute}`);
1950
+ definition.resources.Resources.FriggNATRoute = {
1939
1951
  Type: 'AWS::EC2::Route',
1940
1952
  Properties: {
1941
1953
  RouteTableId: { Ref: 'FriggLambdaRouteTable' },
@@ -1943,6 +1955,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
1943
1955
  NatGatewayId: natGatewayIdForRoute,
1944
1956
  },
1945
1957
  };
1958
+ } else {
1959
+ console.warn('⚠️ No NAT Gateway configured - Lambda functions will not have internet access');
1946
1960
  }
1947
1961
 
1948
1962
  // Associate Lambda subnets with NAT Gateway route table
@@ -2028,6 +2042,13 @@ const composeServerlessDefinition = async (AppDefinition) => {
2028
2042
  AppDefinition.encryption?.fieldLevelEncryptionMethod ===
2029
2043
  'kms'
2030
2044
  ) {
2045
+ // Validate we have VPC CIDR for security group configuration
2046
+ if (!discoveredResources.vpcCidr) {
2047
+ console.warn(
2048
+ '⚠️ Warning: VPC CIDR not discovered. VPC endpoint security group may not work correctly.'
2049
+ );
2050
+ }
2051
+
2031
2052
  // Create security group for VPC endpoints if it doesn't exist
2032
2053
  if (
2033
2054
  !definition.resources.Resources
@@ -2040,16 +2061,16 @@ const composeServerlessDefinition = async (AppDefinition) => {
2040
2061
  GroupDescription:
2041
2062
  'Security group for VPC endpoints',
2042
2063
  VpcId: discoveredResources.defaultVpcId,
2043
- SecurityGroupIngress: [
2044
- {
2045
- IpProtocol: 'tcp',
2046
- FromPort: 443,
2047
- ToPort: 443,
2048
- CidrIp:
2049
- discoveredResources.vpcCidr ||
2050
- '10.0.0.0/16', // Dynamic VPC CIDR
2051
- },
2052
- ],
2064
+ SecurityGroupIngress: discoveredResources.vpcCidr
2065
+ ? [
2066
+ {
2067
+ IpProtocol: 'tcp',
2068
+ FromPort: 443,
2069
+ ToPort: 443,
2070
+ CidrIp: discoveredResources.vpcCidr, // Use discovered VPC CIDR
2071
+ },
2072
+ ]
2073
+ : [], // Empty array if no VPC CIDR discovered
2053
2074
  Tags: [
2054
2075
  {
2055
2076
  Key: 'Name',
@@ -7,6 +7,7 @@ jest.mock('./aws-discovery', () => {
7
7
  return {
8
8
  discoverResources: jest.fn().mockResolvedValue({
9
9
  defaultVpcId: 'vpc-123456',
10
+ vpcCidr: '172.31.0.0/16', // Add VPC CIDR for security group configuration
10
11
  defaultSecurityGroupId: 'sg-123456',
11
12
  privateSubnetId1: 'subnet-123456',
12
13
  privateSubnetId2: 'subnet-789012',
@@ -484,6 +485,10 @@ describe('composeServerlessDefinition', () => {
484
485
  Key: 'Name',
485
486
  Value: '${self:service}-${self:provider.stage}-frigg-kms-key'
486
487
  },
488
+ {
489
+ Key: 'ManagedBy',
490
+ Value: 'Frigg'
491
+ },
487
492
  {
488
493
  Key: 'Purpose',
489
494
  Value: 'Field-level encryption for Frigg application'
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.428.1c210bc.0",
4
+ "version": "2.0.0--canary.428.4968614.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-ec2": "^3.835.0",
7
7
  "@aws-sdk/client-kms": "^3.835.0",
@@ -9,8 +9,8 @@
9
9
  "@babel/eslint-parser": "^7.18.9",
10
10
  "@babel/parser": "^7.25.3",
11
11
  "@babel/traverse": "^7.25.3",
12
- "@friggframework/schemas": "2.0.0--canary.428.1c210bc.0",
13
- "@friggframework/test": "2.0.0--canary.428.1c210bc.0",
12
+ "@friggframework/schemas": "2.0.0--canary.428.4968614.0",
13
+ "@friggframework/test": "2.0.0--canary.428.4968614.0",
14
14
  "@hapi/boom": "^10.0.1",
15
15
  "@inquirer/prompts": "^5.3.8",
16
16
  "axios": "^1.7.2",
@@ -32,8 +32,8 @@
32
32
  "serverless-http": "^2.7.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@friggframework/eslint-config": "2.0.0--canary.428.1c210bc.0",
36
- "@friggframework/prettier-config": "2.0.0--canary.428.1c210bc.0",
35
+ "@friggframework/eslint-config": "2.0.0--canary.428.4968614.0",
36
+ "@friggframework/prettier-config": "2.0.0--canary.428.4968614.0",
37
37
  "aws-sdk-client-mock": "^4.1.0",
38
38
  "aws-sdk-client-mock-jest": "^4.1.0",
39
39
  "jest": "^30.1.3",
@@ -68,5 +68,5 @@
68
68
  "publishConfig": {
69
69
  "access": "public"
70
70
  },
71
- "gitHead": "1c210bc49b0013c033077c703eaa7e388927d4bf"
71
+ "gitHead": "49686143bbd8303507c1824ef167465d1efeaa1e"
72
72
  }