@friggframework/devtools 2.0.0--canary.428.b4a2c90.0 → 2.0.0--canary.428.4fa6f20.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/infrastructure/serverless-template.js +151 -119
- package/package.json +6 -6
|
@@ -60,15 +60,13 @@ const getAppEnvironmentVars = (AppDefinition) => {
|
|
|
60
60
|
|
|
61
61
|
if (envKeys.length > 0) {
|
|
62
62
|
console.log(
|
|
63
|
-
` Found ${
|
|
64
|
-
envKeys.length
|
|
63
|
+
` Found ${envKeys.length
|
|
65
64
|
} environment variables: ${envKeys.join(', ')}`
|
|
66
65
|
);
|
|
67
66
|
}
|
|
68
67
|
if (skippedKeys.length > 0) {
|
|
69
68
|
console.log(
|
|
70
|
-
` ⚠️ Skipped ${
|
|
71
|
-
skippedKeys.length
|
|
69
|
+
` ⚠️ Skipped ${skippedKeys.length
|
|
72
70
|
} reserved AWS Lambda variables: ${skippedKeys.join(', ')}`
|
|
73
71
|
);
|
|
74
72
|
}
|
|
@@ -372,7 +370,7 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
372
370
|
},
|
|
373
371
|
},
|
|
374
372
|
|
|
375
|
-
// Private Route Table
|
|
373
|
+
// Private Route Table for Private Subnets
|
|
376
374
|
FriggPrivateRouteTable: {
|
|
377
375
|
Type: 'AWS::EC2::RouteTable',
|
|
378
376
|
Properties: {
|
|
@@ -572,6 +570,7 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
572
570
|
* @returns {Object} Complete serverless framework configuration
|
|
573
571
|
*/
|
|
574
572
|
const composeServerlessDefinition = async (AppDefinition) => {
|
|
573
|
+
console.log('composeServerlessDefinition', AppDefinition);
|
|
575
574
|
// Store discovered resources
|
|
576
575
|
let discoveredResources = {};
|
|
577
576
|
|
|
@@ -942,10 +941,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
942
941
|
Resource: '*',
|
|
943
942
|
Condition: {
|
|
944
943
|
StringEquals: {
|
|
945
|
-
'kms:ViaService': `lambda.${
|
|
946
|
-
process.env.AWS_REGION ||
|
|
944
|
+
'kms:ViaService': `lambda.${process.env.AWS_REGION ||
|
|
947
945
|
'us-east-1'
|
|
948
|
-
|
|
946
|
+
}.amazonaws.com`,
|
|
949
947
|
},
|
|
950
948
|
},
|
|
951
949
|
},
|
|
@@ -982,7 +980,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
982
980
|
// No key found and createIfNoneFound is not enabled - error
|
|
983
981
|
throw new Error(
|
|
984
982
|
'KMS field-level encryption is enabled but no KMS key was found. ' +
|
|
985
|
-
|
|
983
|
+
'Either provide an existing KMS key or set encryption.createResourceIfNoneFound to true to create a new key.'
|
|
986
984
|
);
|
|
987
985
|
}
|
|
988
986
|
}
|
|
@@ -1068,11 +1066,11 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1068
1066
|
subnetIds:
|
|
1069
1067
|
AppDefinition.vpc.subnetIds ||
|
|
1070
1068
|
(discoveredResources.privateSubnetId1 &&
|
|
1071
|
-
|
|
1069
|
+
discoveredResources.privateSubnetId2
|
|
1072
1070
|
? [
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1071
|
+
discoveredResources.privateSubnetId1,
|
|
1072
|
+
discoveredResources.privateSubnetId2,
|
|
1073
|
+
]
|
|
1076
1074
|
: []),
|
|
1077
1075
|
};
|
|
1078
1076
|
|
|
@@ -1086,36 +1084,44 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1086
1084
|
// ALWAYS manage NAT Gateway through CloudFormation for self-healing
|
|
1087
1085
|
// This ensures NAT Gateway is always in the correct subnet with proper configuration
|
|
1088
1086
|
|
|
1087
|
+
console.log('AppDefinition.vpc.natGateway', AppDefinition.vpc.natGateway);
|
|
1088
|
+
const natGatewayMethod =
|
|
1089
|
+
AppDefinition.vpc.natGateway?.method || 'useExisting';
|
|
1090
|
+
console.log('natGatewayMethod', natGatewayMethod);
|
|
1089
1091
|
const needsNewNatGateway =
|
|
1090
|
-
|
|
1091
|
-
AppDefinition.vpc.natGateway?.method) ===
|
|
1092
|
-
'createAndManage';
|
|
1092
|
+
natGatewayMethod === 'createAndManage';
|
|
1093
1093
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1094
|
+
console.log('needsNewNatGateway', needsNewNatGateway);
|
|
1095
|
+
|
|
1096
|
+
// Helper function to validate discovered public subnet
|
|
1097
|
+
const isValidPublicSubnet = (subnetId, discoveredResources) => {
|
|
1098
|
+
// Basic validation - in production, AWSDiscovery should check route tables for IGW routes
|
|
1099
|
+
return (
|
|
1100
|
+
discoveredResources.publicSubnetHasIgwRoute !== false
|
|
1097
1101
|
);
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
if (needsNewNatGateway) {
|
|
1105
|
+
// Always create new dedicated resources in create mode to avoid confusion with existing ones
|
|
1098
1106
|
console.log(
|
|
1099
|
-
'
|
|
1107
|
+
'Create mode: Creating dedicated EIP, public subnet, and NAT Gateway...'
|
|
1100
1108
|
);
|
|
1101
1109
|
|
|
1102
|
-
//
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
};
|
|
1116
|
-
}
|
|
1110
|
+
// Create EIP (ignore any discovered)
|
|
1111
|
+
definition.resources.Resources.FriggNATGatewayEIP = {
|
|
1112
|
+
Type: 'AWS::EC2::EIP',
|
|
1113
|
+
Properties: {
|
|
1114
|
+
Domain: 'vpc',
|
|
1115
|
+
Tags: [
|
|
1116
|
+
{
|
|
1117
|
+
Key: 'Name',
|
|
1118
|
+
Value: '${self:service}-${self:provider.stage}-nat-eip',
|
|
1119
|
+
},
|
|
1120
|
+
],
|
|
1121
|
+
},
|
|
1122
|
+
};
|
|
1117
1123
|
|
|
1118
|
-
//
|
|
1124
|
+
// Create public subnet (ignore any discovered; ensure it's in a matching AZ)
|
|
1119
1125
|
if (!discoveredResources.publicSubnetId) {
|
|
1120
1126
|
console.log(
|
|
1121
1127
|
'No public subnet found, creating one for NAT Gateway placement...'
|
|
@@ -1124,28 +1130,28 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1124
1130
|
// Check if Internet Gateway exists or create one
|
|
1125
1131
|
if (!discoveredResources.internetGatewayId) {
|
|
1126
1132
|
definition.resources.Resources.FriggInternetGateway =
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1133
|
+
{
|
|
1134
|
+
Type: 'AWS::EC2::InternetGateway',
|
|
1135
|
+
Properties: {
|
|
1136
|
+
Tags: [
|
|
1137
|
+
{
|
|
1138
|
+
Key: 'Name',
|
|
1139
|
+
Value: '${self:service}-${self:provider.stage}-igw',
|
|
1140
|
+
},
|
|
1141
|
+
],
|
|
1142
|
+
},
|
|
1143
|
+
};
|
|
1138
1144
|
|
|
1139
1145
|
definition.resources.Resources.FriggIGWAttachment =
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
},
|
|
1146
|
+
{
|
|
1147
|
+
Type: 'AWS::EC2::VPCGatewayAttachment',
|
|
1148
|
+
Properties: {
|
|
1149
|
+
VpcId: discoveredResources.defaultVpcId,
|
|
1150
|
+
InternetGatewayId: {
|
|
1151
|
+
Ref: 'FriggInternetGateway',
|
|
1147
1152
|
},
|
|
1148
|
-
}
|
|
1153
|
+
},
|
|
1154
|
+
};
|
|
1149
1155
|
}
|
|
1150
1156
|
|
|
1151
1157
|
// Create a small public subnet for NAT Gateway
|
|
@@ -1155,7 +1161,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1155
1161
|
VpcId: discoveredResources.defaultVpcId,
|
|
1156
1162
|
CidrBlock:
|
|
1157
1163
|
AppDefinition.vpc.natGateway
|
|
1158
|
-
?.publicSubnetCidr || '172.31.250.0/24',
|
|
1164
|
+
?.publicSubnetCidr || '172.31.250.0/24',
|
|
1159
1165
|
AvailabilityZone: {
|
|
1160
1166
|
'Fn::Select': [0, { 'Fn::GetAZs': '' }],
|
|
1161
1167
|
},
|
|
@@ -1205,28 +1211,27 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1205
1211
|
|
|
1206
1212
|
// Associate public subnet with public route table
|
|
1207
1213
|
definition.resources.Resources.FriggPublicSubnetRouteTableAssociation =
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
},
|
|
1214
|
+
{
|
|
1215
|
+
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1216
|
+
Properties: {
|
|
1217
|
+
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
1218
|
+
RouteTableId: {
|
|
1219
|
+
Ref: 'FriggPublicRouteTable',
|
|
1215
1220
|
},
|
|
1216
|
-
}
|
|
1221
|
+
},
|
|
1222
|
+
};
|
|
1217
1223
|
}
|
|
1218
1224
|
|
|
1219
|
-
//
|
|
1225
|
+
// Create NAT Gateway using the new resources
|
|
1220
1226
|
definition.resources.Resources.FriggNATGateway = {
|
|
1221
1227
|
Type: 'AWS::EC2::NatGateway',
|
|
1222
1228
|
Properties: {
|
|
1223
|
-
AllocationId:
|
|
1224
|
-
|
|
1225
|
-
'
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
},
|
|
1229
|
+
AllocationId: {
|
|
1230
|
+
'Fn::GetAtt': [
|
|
1231
|
+
'FriggNATGatewayEIP',
|
|
1232
|
+
'AllocationId',
|
|
1233
|
+
],
|
|
1234
|
+
},
|
|
1230
1235
|
SubnetId: discoveredResources.publicSubnetId || {
|
|
1231
1236
|
Ref: 'FriggPublicSubnet',
|
|
1232
1237
|
},
|
|
@@ -1242,17 +1247,33 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1242
1247
|
],
|
|
1243
1248
|
},
|
|
1244
1249
|
};
|
|
1250
|
+
} else if (discoveredResources.existingNatGatewayId) {
|
|
1251
|
+
console.log('discoveredResources.existingNatGatewayId', discoveredResources.existingNatGatewayId);
|
|
1252
|
+
// Reuse mode: Use existing NAT, but validate first
|
|
1253
|
+
if (
|
|
1254
|
+
discoveredResources.publicSubnetId &&
|
|
1255
|
+
isValidPublicSubnet(
|
|
1256
|
+
discoveredResources.publicSubnetId,
|
|
1257
|
+
discoveredResources
|
|
1258
|
+
)
|
|
1259
|
+
) {
|
|
1260
|
+
console.log(
|
|
1261
|
+
'Reuse mode: Valid existing NAT found; adding routes...'
|
|
1262
|
+
);
|
|
1263
|
+
// No new NAT creation; just add routes referencing existingNatGatewayId
|
|
1264
|
+
} else {
|
|
1265
|
+
throw new Error(
|
|
1266
|
+
'Existing NAT discovered but public subnet is invalid or missing. Set method to "createAndManage" or fix subnet configuration.'
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1245
1269
|
} else {
|
|
1246
|
-
//
|
|
1247
|
-
|
|
1248
|
-
'
|
|
1270
|
+
// No NAT and not in create mode: Error out to prevent isolated subnets
|
|
1271
|
+
throw new Error(
|
|
1272
|
+
'No existing NAT Gateway found and createAndManage not enabled. Update appDefinition.vpc.natGateway.method or ensure discovery finds a valid NAT.'
|
|
1249
1273
|
);
|
|
1250
|
-
|
|
1251
|
-
// Note: CloudFormation will detect if a NAT Gateway already exists with these properties
|
|
1252
|
-
// and will adopt it rather than creating a duplicate
|
|
1253
1274
|
}
|
|
1254
1275
|
|
|
1255
|
-
//
|
|
1276
|
+
// Always add route table and routes (referencing the NAT, whether new or existing)
|
|
1256
1277
|
definition.resources.Resources.FriggLambdaRouteTable = {
|
|
1257
1278
|
Type: 'AWS::EC2::RouteTable',
|
|
1258
1279
|
Properties: {
|
|
@@ -1274,7 +1295,17 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1274
1295
|
Properties: {
|
|
1275
1296
|
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1276
1297
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
1277
|
-
NatGatewayId: { Ref: 'FriggNATGateway' },
|
|
1298
|
+
NatGatewayId: { Ref: 'FriggNATGateway' },
|
|
1299
|
+
},
|
|
1300
|
+
};
|
|
1301
|
+
} else {
|
|
1302
|
+
definition.resources.Resources.FriggNATRoute = {
|
|
1303
|
+
Type: 'AWS::EC2::Route',
|
|
1304
|
+
Properties: {
|
|
1305
|
+
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
1306
|
+
DestinationCidrBlock: '0.0.0.0/0',
|
|
1307
|
+
NatGatewayId:
|
|
1308
|
+
discoveredResources.existingNatGatewayId,
|
|
1278
1309
|
},
|
|
1279
1310
|
};
|
|
1280
1311
|
}
|
|
@@ -1335,28 +1366,30 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1335
1366
|
.VPCEndpointSecurityGroup
|
|
1336
1367
|
) {
|
|
1337
1368
|
definition.resources.Resources.VPCEndpointSecurityGroup =
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1369
|
+
{
|
|
1370
|
+
Type: 'AWS::EC2::SecurityGroup',
|
|
1371
|
+
Properties: {
|
|
1372
|
+
GroupDescription:
|
|
1373
|
+
'Security group for VPC endpoints',
|
|
1374
|
+
VpcId: discoveredResources.defaultVpcId,
|
|
1375
|
+
SecurityGroupIngress: [
|
|
1376
|
+
{
|
|
1377
|
+
IpProtocol: 'tcp',
|
|
1378
|
+
FromPort: 443,
|
|
1379
|
+
ToPort: 443,
|
|
1380
|
+
CidrIp:
|
|
1381
|
+
discoveredResources.vpcCidr ||
|
|
1382
|
+
'10.0.0.0/16', // Dynamic VPC CIDR
|
|
1383
|
+
},
|
|
1384
|
+
],
|
|
1385
|
+
Tags: [
|
|
1386
|
+
{
|
|
1387
|
+
Key: 'Name',
|
|
1388
|
+
Value: '${self:service}-${self:provider.stage}-vpc-endpoints-sg',
|
|
1389
|
+
},
|
|
1390
|
+
],
|
|
1391
|
+
},
|
|
1392
|
+
};
|
|
1360
1393
|
}
|
|
1361
1394
|
|
|
1362
1395
|
definition.resources.Resources.VPCEndpointKMS = {
|
|
@@ -1377,20 +1410,20 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1377
1410
|
// Also add Secrets Manager endpoint if using Secrets Manager
|
|
1378
1411
|
if (AppDefinition.secretsManager?.enable === true) {
|
|
1379
1412
|
definition.resources.Resources.VPCEndpointSecretsManager =
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1413
|
+
{
|
|
1414
|
+
Type: 'AWS::EC2::VPCEndpoint',
|
|
1415
|
+
Properties: {
|
|
1416
|
+
VpcId: discoveredResources.defaultVpcId,
|
|
1417
|
+
ServiceName:
|
|
1418
|
+
'com.amazonaws.${self:provider.region}.secretsmanager',
|
|
1419
|
+
VpcEndpointType: 'Interface',
|
|
1420
|
+
SubnetIds: vpcConfig.subnetIds,
|
|
1421
|
+
SecurityGroupIds: [
|
|
1422
|
+
{ Ref: 'VPCEndpointSecurityGroup' },
|
|
1423
|
+
],
|
|
1424
|
+
PrivateDnsEnabled: true,
|
|
1425
|
+
},
|
|
1426
|
+
};
|
|
1394
1427
|
}
|
|
1395
1428
|
}
|
|
1396
1429
|
}
|
|
@@ -1453,10 +1486,9 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1453
1486
|
};
|
|
1454
1487
|
|
|
1455
1488
|
// Add SQS Queue for the integration
|
|
1456
|
-
const queueReference = `${
|
|
1457
|
-
integrationName.charAt(0).toUpperCase() +
|
|
1489
|
+
const queueReference = `${integrationName.charAt(0).toUpperCase() +
|
|
1458
1490
|
integrationName.slice(1)
|
|
1459
|
-
|
|
1491
|
+
}Queue`;
|
|
1460
1492
|
const queueName = `\${self:service}--\${self:provider.stage}-${queueReference}`;
|
|
1461
1493
|
definition.resources.Resources[queueReference] = {
|
|
1462
1494
|
Type: 'AWS::SQS::Queue',
|
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.
|
|
4
|
+
"version": "2.0.0--canary.428.4fa6f20.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.
|
|
13
|
-
"@friggframework/test": "2.0.0--canary.428.
|
|
12
|
+
"@friggframework/schemas": "2.0.0--canary.428.4fa6f20.0",
|
|
13
|
+
"@friggframework/test": "2.0.0--canary.428.4fa6f20.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.
|
|
36
|
-
"@friggframework/prettier-config": "2.0.0--canary.428.
|
|
35
|
+
"@friggframework/eslint-config": "2.0.0--canary.428.4fa6f20.0",
|
|
36
|
+
"@friggframework/prettier-config": "2.0.0--canary.428.4fa6f20.0",
|
|
37
37
|
"jest": "^30.1.3",
|
|
38
38
|
"prettier": "^2.7.1",
|
|
39
39
|
"serverless": "3.39.0",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "4fa6f20b9371677cb86a8035ac9736af726ffa82"
|
|
70
70
|
}
|