@friggframework/devtools 2.0.0--canary.398.53eac55.0 → 2.0.0--canary.397.878fefa.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/frigg-cli/build-command/index.js +2 -4
- package/frigg-cli/deploy-command/index.js +2 -5
- package/frigg-cli/index.js +1 -11
- package/infrastructure/create-frigg-infrastructure.js +2 -10
- package/infrastructure/serverless-template.js +27 -599
- package/package.json +5 -9
- package/test/mock-integration.js +4 -14
- package/frigg-cli/generate-iam-command.js +0 -115
- package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +0 -245
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +0 -561
- package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +0 -268
- package/infrastructure/GENERATE-IAM-DOCS.md +0 -253
- package/infrastructure/README-TESTING.md +0 -332
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +0 -105
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +0 -391
- package/infrastructure/__tests__/helpers/test-utils.js +0 -277
- package/infrastructure/aws-discovery.js +0 -460
- package/infrastructure/aws-discovery.test.js +0 -373
- package/infrastructure/build-time-discovery.js +0 -206
- package/infrastructure/build-time-discovery.test.js +0 -375
- package/infrastructure/frigg-deployment-iam-stack.yaml +0 -370
- package/infrastructure/iam-generator.js +0 -644
- package/infrastructure/iam-generator.test.js +0 -169
- package/infrastructure/integration.test.js +0 -383
- package/infrastructure/run-discovery.js +0 -110
- package/infrastructure/serverless-template.test.js +0 -498
- package/test/auther-definition-tester.js +0 -125
|
@@ -1,26 +1,7 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const fs = require('fs');
|
|
3
|
-
const { AWSDiscovery } = require('./aws-discovery');
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
* Check if AWS discovery should run based on AppDefinition
|
|
7
|
-
* @param {Object} AppDefinition - Application definition
|
|
8
|
-
* @returns {boolean} True if discovery should run
|
|
9
|
-
*/
|
|
10
|
-
const shouldRunDiscovery = (AppDefinition) => {
|
|
11
|
-
return AppDefinition.vpc?.enable === true ||
|
|
12
|
-
AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true ||
|
|
13
|
-
AppDefinition.ssm?.enable === true;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Find the actual path to node_modules directory
|
|
18
|
-
* Tries multiple methods to locate node_modules:
|
|
19
|
-
* 1. Traversing up from current directory
|
|
20
|
-
* 2. Using npm root command
|
|
21
|
-
* 3. Looking for package.json and adjacent node_modules
|
|
22
|
-
* @returns {string} Path to node_modules directory
|
|
23
|
-
*/
|
|
4
|
+
// Function to find the actual path to node_modules
|
|
24
5
|
const findNodeModulesPath = () => {
|
|
25
6
|
try {
|
|
26
7
|
// Method 1: Try to find node_modules by traversing up from current directory
|
|
@@ -94,12 +75,7 @@ const findNodeModulesPath = () => {
|
|
|
94
75
|
}
|
|
95
76
|
};
|
|
96
77
|
|
|
97
|
-
|
|
98
|
-
* Modify handler paths to point to the correct node_modules location
|
|
99
|
-
* Only modifies paths when running in offline mode
|
|
100
|
-
* @param {Object} functions - Serverless functions configuration object
|
|
101
|
-
* @returns {Object} Modified functions object with updated handler paths
|
|
102
|
-
*/
|
|
78
|
+
// Function to modify handler paths to point to the correct node_modules
|
|
103
79
|
const modifyHandlerPaths = (functions) => {
|
|
104
80
|
// Check if we're running in offline mode
|
|
105
81
|
const isOffline = process.argv.includes('offline');
|
|
@@ -118,8 +94,7 @@ const modifyHandlerPaths = (functions) => {
|
|
|
118
94
|
const functionDef = modifiedFunctions[functionName];
|
|
119
95
|
if (functionDef?.handler?.includes('node_modules/')) {
|
|
120
96
|
// Replace node_modules/ with the actual path to node_modules/
|
|
121
|
-
|
|
122
|
-
functionDef.handler = functionDef.handler.replace('node_modules/', `${relativePath}/`);
|
|
97
|
+
functionDef.handler = functionDef.handler.replace('node_modules/', '../node_modules/');
|
|
123
98
|
console.log(`Updated handler for ${functionName}: ${functionDef.handler}`);
|
|
124
99
|
}
|
|
125
100
|
}
|
|
@@ -127,367 +102,7 @@ const modifyHandlerPaths = (functions) => {
|
|
|
127
102
|
return modifiedFunctions;
|
|
128
103
|
};
|
|
129
104
|
|
|
130
|
-
|
|
131
|
-
* Create VPC infrastructure resources for CloudFormation
|
|
132
|
-
* Creates VPC, subnets, NAT gateway, route tables, and security groups
|
|
133
|
-
* @param {Object} AppDefinition - Application definition object
|
|
134
|
-
* @param {Object} AppDefinition.vpc - VPC configuration
|
|
135
|
-
* @param {string} [AppDefinition.vpc.cidrBlock='10.0.0.0/16'] - CIDR block for VPC
|
|
136
|
-
* @returns {Object} CloudFormation resources for VPC infrastructure
|
|
137
|
-
*/
|
|
138
|
-
const createVPCInfrastructure = (AppDefinition) => {
|
|
139
|
-
const vpcResources = {
|
|
140
|
-
// VPC
|
|
141
|
-
FriggVPC: {
|
|
142
|
-
Type: 'AWS::EC2::VPC',
|
|
143
|
-
Properties: {
|
|
144
|
-
CidrBlock: AppDefinition.vpc.cidrBlock || '10.0.0.0/16',
|
|
145
|
-
EnableDnsHostnames: true,
|
|
146
|
-
EnableDnsSupport: true,
|
|
147
|
-
Tags: [
|
|
148
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc' }
|
|
149
|
-
]
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
// Internet Gateway
|
|
154
|
-
FriggInternetGateway: {
|
|
155
|
-
Type: 'AWS::EC2::InternetGateway',
|
|
156
|
-
Properties: {
|
|
157
|
-
Tags: [
|
|
158
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-igw' }
|
|
159
|
-
]
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
// Attach Internet Gateway to VPC
|
|
164
|
-
FriggVPCGatewayAttachment: {
|
|
165
|
-
Type: 'AWS::EC2::VPCGatewayAttachment',
|
|
166
|
-
Properties: {
|
|
167
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
168
|
-
InternetGatewayId: { Ref: 'FriggInternetGateway' }
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
// Public Subnet for NAT Gateway
|
|
173
|
-
FriggPublicSubnet: {
|
|
174
|
-
Type: 'AWS::EC2::Subnet',
|
|
175
|
-
Properties: {
|
|
176
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
177
|
-
CidrBlock: '10.0.1.0/24',
|
|
178
|
-
AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
|
|
179
|
-
MapPublicIpOnLaunch: true,
|
|
180
|
-
Tags: [
|
|
181
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-subnet' }
|
|
182
|
-
]
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
|
|
186
|
-
// Private Subnet 1 for Lambda
|
|
187
|
-
FriggPrivateSubnet1: {
|
|
188
|
-
Type: 'AWS::EC2::Subnet',
|
|
189
|
-
Properties: {
|
|
190
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
191
|
-
CidrBlock: '10.0.2.0/24',
|
|
192
|
-
AvailabilityZone: { 'Fn::Select': [0, { 'Fn::GetAZs': '' }] },
|
|
193
|
-
Tags: [
|
|
194
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-subnet-1' }
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
|
|
199
|
-
// Private Subnet 2 for Lambda (different AZ for redundancy)
|
|
200
|
-
FriggPrivateSubnet2: {
|
|
201
|
-
Type: 'AWS::EC2::Subnet',
|
|
202
|
-
Properties: {
|
|
203
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
204
|
-
CidrBlock: '10.0.3.0/24',
|
|
205
|
-
AvailabilityZone: { 'Fn::Select': [1, { 'Fn::GetAZs': '' }] },
|
|
206
|
-
Tags: [
|
|
207
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-subnet-2' }
|
|
208
|
-
]
|
|
209
|
-
}
|
|
210
|
-
},
|
|
211
|
-
|
|
212
|
-
// Elastic IP for NAT Gateway
|
|
213
|
-
FriggNATGatewayEIP: {
|
|
214
|
-
Type: 'AWS::EC2::EIP',
|
|
215
|
-
Properties: {
|
|
216
|
-
Domain: 'vpc',
|
|
217
|
-
Tags: [
|
|
218
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-eip' }
|
|
219
|
-
]
|
|
220
|
-
},
|
|
221
|
-
DependsOn: 'FriggVPCGatewayAttachment'
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
// NAT Gateway for private subnet internet access
|
|
225
|
-
FriggNATGateway: {
|
|
226
|
-
Type: 'AWS::EC2::NatGateway',
|
|
227
|
-
Properties: {
|
|
228
|
-
AllocationId: { 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'] },
|
|
229
|
-
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
230
|
-
Tags: [
|
|
231
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-gateway' }
|
|
232
|
-
]
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
|
|
236
|
-
// Public Route Table
|
|
237
|
-
FriggPublicRouteTable: {
|
|
238
|
-
Type: 'AWS::EC2::RouteTable',
|
|
239
|
-
Properties: {
|
|
240
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
241
|
-
Tags: [
|
|
242
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-public-rt' }
|
|
243
|
-
]
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
|
|
247
|
-
// Public Route to Internet Gateway
|
|
248
|
-
FriggPublicRoute: {
|
|
249
|
-
Type: 'AWS::EC2::Route',
|
|
250
|
-
Properties: {
|
|
251
|
-
RouteTableId: { Ref: 'FriggPublicRouteTable' },
|
|
252
|
-
DestinationCidrBlock: '0.0.0.0/0',
|
|
253
|
-
GatewayId: { Ref: 'FriggInternetGateway' }
|
|
254
|
-
},
|
|
255
|
-
DependsOn: 'FriggVPCGatewayAttachment'
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
// Associate Public Subnet with Public Route Table
|
|
259
|
-
FriggPublicSubnetRouteTableAssociation: {
|
|
260
|
-
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
261
|
-
Properties: {
|
|
262
|
-
SubnetId: { Ref: 'FriggPublicSubnet' },
|
|
263
|
-
RouteTableId: { Ref: 'FriggPublicRouteTable' }
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
|
|
267
|
-
// Private Route Table
|
|
268
|
-
FriggPrivateRouteTable: {
|
|
269
|
-
Type: 'AWS::EC2::RouteTable',
|
|
270
|
-
Properties: {
|
|
271
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
272
|
-
Tags: [
|
|
273
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-private-rt' }
|
|
274
|
-
]
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
|
|
278
|
-
// Private Route to NAT Gateway
|
|
279
|
-
FriggPrivateRoute: {
|
|
280
|
-
Type: 'AWS::EC2::Route',
|
|
281
|
-
Properties: {
|
|
282
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' },
|
|
283
|
-
DestinationCidrBlock: '0.0.0.0/0',
|
|
284
|
-
NatGatewayId: { Ref: 'FriggNATGateway' }
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
|
|
288
|
-
// Associate Private Subnet 1 with Private Route Table
|
|
289
|
-
FriggPrivateSubnet1RouteTableAssociation: {
|
|
290
|
-
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
291
|
-
Properties: {
|
|
292
|
-
SubnetId: { Ref: 'FriggPrivateSubnet1' },
|
|
293
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' }
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
|
|
297
|
-
// Associate Private Subnet 2 with Private Route Table
|
|
298
|
-
FriggPrivateSubnet2RouteTableAssociation: {
|
|
299
|
-
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
300
|
-
Properties: {
|
|
301
|
-
SubnetId: { Ref: 'FriggPrivateSubnet2' },
|
|
302
|
-
RouteTableId: { Ref: 'FriggPrivateRouteTable' }
|
|
303
|
-
}
|
|
304
|
-
},
|
|
305
|
-
|
|
306
|
-
// Security Group for Lambda functions
|
|
307
|
-
FriggLambdaSecurityGroup: {
|
|
308
|
-
Type: 'AWS::EC2::SecurityGroup',
|
|
309
|
-
Properties: {
|
|
310
|
-
GroupDescription: 'Security group for Frigg Lambda functions',
|
|
311
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
312
|
-
SecurityGroupEgress: [
|
|
313
|
-
{
|
|
314
|
-
IpProtocol: 'tcp',
|
|
315
|
-
FromPort: 443,
|
|
316
|
-
ToPort: 443,
|
|
317
|
-
CidrIp: '0.0.0.0/0',
|
|
318
|
-
Description: 'HTTPS outbound'
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
IpProtocol: 'tcp',
|
|
322
|
-
FromPort: 80,
|
|
323
|
-
ToPort: 80,
|
|
324
|
-
CidrIp: '0.0.0.0/0',
|
|
325
|
-
Description: 'HTTP outbound'
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
IpProtocol: 'tcp',
|
|
329
|
-
FromPort: 53,
|
|
330
|
-
ToPort: 53,
|
|
331
|
-
CidrIp: '0.0.0.0/0',
|
|
332
|
-
Description: 'DNS TCP'
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
IpProtocol: 'udp',
|
|
336
|
-
FromPort: 53,
|
|
337
|
-
ToPort: 53,
|
|
338
|
-
CidrIp: '0.0.0.0/0',
|
|
339
|
-
Description: 'DNS UDP'
|
|
340
|
-
}
|
|
341
|
-
],
|
|
342
|
-
Tags: [
|
|
343
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-sg' }
|
|
344
|
-
]
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
// Add VPC Endpoints for cost optimization
|
|
350
|
-
if (AppDefinition.vpc.enableVPCEndpoints !== false) {
|
|
351
|
-
// S3 Gateway Endpoint (free)
|
|
352
|
-
vpcResources.FriggS3VPCEndpoint = {
|
|
353
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
354
|
-
Properties: {
|
|
355
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
356
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.s3',
|
|
357
|
-
VpcEndpointType: 'Gateway',
|
|
358
|
-
RouteTableIds: [
|
|
359
|
-
{ Ref: 'FriggPrivateRouteTable' }
|
|
360
|
-
]
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
// DynamoDB Gateway Endpoint (free)
|
|
365
|
-
vpcResources.FriggDynamoDBVPCEndpoint = {
|
|
366
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
367
|
-
Properties: {
|
|
368
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
369
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
|
|
370
|
-
VpcEndpointType: 'Gateway',
|
|
371
|
-
RouteTableIds: [
|
|
372
|
-
{ Ref: 'FriggPrivateRouteTable' }
|
|
373
|
-
]
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// KMS Interface Endpoint (paid, but useful if using KMS)
|
|
378
|
-
if (AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true) {
|
|
379
|
-
vpcResources.FriggKMSVPCEndpoint = {
|
|
380
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
381
|
-
Properties: {
|
|
382
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
383
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.kms',
|
|
384
|
-
VpcEndpointType: 'Interface',
|
|
385
|
-
SubnetIds: [
|
|
386
|
-
{ Ref: 'FriggPrivateSubnet1' },
|
|
387
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
388
|
-
],
|
|
389
|
-
SecurityGroupIds: [
|
|
390
|
-
{ Ref: 'FriggVPCEndpointSecurityGroup' }
|
|
391
|
-
],
|
|
392
|
-
PrivateDnsEnabled: true
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Secrets Manager Interface Endpoint (paid, but useful for secrets)
|
|
398
|
-
vpcResources.FriggSecretsManagerVPCEndpoint = {
|
|
399
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
400
|
-
Properties: {
|
|
401
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
402
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.secretsmanager',
|
|
403
|
-
VpcEndpointType: 'Interface',
|
|
404
|
-
SubnetIds: [
|
|
405
|
-
{ Ref: 'FriggPrivateSubnet1' },
|
|
406
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
407
|
-
],
|
|
408
|
-
SecurityGroupIds: [
|
|
409
|
-
{ Ref: 'FriggVPCEndpointSecurityGroup' }
|
|
410
|
-
],
|
|
411
|
-
PrivateDnsEnabled: true
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
// Security Group for VPC Endpoints
|
|
416
|
-
vpcResources.FriggVPCEndpointSecurityGroup = {
|
|
417
|
-
Type: 'AWS::EC2::SecurityGroup',
|
|
418
|
-
Properties: {
|
|
419
|
-
GroupDescription: 'Security group for Frigg VPC Endpoints',
|
|
420
|
-
VpcId: { Ref: 'FriggVPC' },
|
|
421
|
-
SecurityGroupIngress: [
|
|
422
|
-
{
|
|
423
|
-
IpProtocol: 'tcp',
|
|
424
|
-
FromPort: 443,
|
|
425
|
-
ToPort: 443,
|
|
426
|
-
SourceSecurityGroupId: { Ref: 'FriggLambdaSecurityGroup' },
|
|
427
|
-
Description: 'HTTPS from Lambda'
|
|
428
|
-
}
|
|
429
|
-
],
|
|
430
|
-
Tags: [
|
|
431
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-vpc-endpoint-sg' }
|
|
432
|
-
]
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return vpcResources;
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Compose a complete serverless framework configuration from app definition
|
|
442
|
-
* @param {Object} AppDefinition - Application definition object
|
|
443
|
-
* @param {string} [AppDefinition.name] - Application name
|
|
444
|
-
* @param {string} [AppDefinition.provider='aws'] - Cloud provider
|
|
445
|
-
* @param {Array} AppDefinition.integrations - Array of integration definitions
|
|
446
|
-
* @param {Object} [AppDefinition.vpc] - VPC configuration
|
|
447
|
-
* @param {Object} [AppDefinition.encryption] - KMS encryption configuration
|
|
448
|
-
* @param {Object} [AppDefinition.ssm] - SSM parameter store configuration
|
|
449
|
-
* @param {Object} [AppDefinition.websockets] - WebSocket configuration
|
|
450
|
-
* @param {boolean} [AppDefinition.websockets.enable=false] - Enable WebSocket support for live update streaming
|
|
451
|
-
* @returns {Object} Complete serverless framework configuration
|
|
452
|
-
*/
|
|
453
|
-
const composeServerlessDefinition = async (AppDefinition) => {
|
|
454
|
-
// Store discovered resources
|
|
455
|
-
let discoveredResources = {};
|
|
456
|
-
|
|
457
|
-
// Run AWS discovery if needed
|
|
458
|
-
if (shouldRunDiscovery(AppDefinition)) {
|
|
459
|
-
console.log('🔍 Running AWS resource discovery for serverless template...');
|
|
460
|
-
try {
|
|
461
|
-
const region = process.env.AWS_REGION || 'us-east-1';
|
|
462
|
-
const discovery = new AWSDiscovery(region);
|
|
463
|
-
|
|
464
|
-
const config = {
|
|
465
|
-
vpc: AppDefinition.vpc || {},
|
|
466
|
-
encryption: AppDefinition.encryption || {},
|
|
467
|
-
ssm: AppDefinition.ssm || {}
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
discoveredResources = await discovery.discoverResources(config);
|
|
471
|
-
|
|
472
|
-
console.log('✅ AWS discovery completed successfully!');
|
|
473
|
-
if (discoveredResources.defaultVpcId) {
|
|
474
|
-
console.log(` VPC: ${discoveredResources.defaultVpcId}`);
|
|
475
|
-
}
|
|
476
|
-
if (discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2) {
|
|
477
|
-
console.log(` Subnets: ${discoveredResources.privateSubnetId1}, ${discoveredResources.privateSubnetId2}`);
|
|
478
|
-
}
|
|
479
|
-
if (discoveredResources.defaultSecurityGroupId) {
|
|
480
|
-
console.log(` Security Group: ${discoveredResources.defaultSecurityGroupId}`);
|
|
481
|
-
}
|
|
482
|
-
if (discoveredResources.defaultKmsKeyId) {
|
|
483
|
-
console.log(` KMS Key: ${discoveredResources.defaultKmsKeyId}`);
|
|
484
|
-
}
|
|
485
|
-
} catch (error) {
|
|
486
|
-
console.error('❌ AWS discovery failed:', error.message);
|
|
487
|
-
throw new Error(`AWS discovery failed: ${error.message}`);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
105
|
+
const composeServerlessDefinition = (AppDefinition) => {
|
|
491
106
|
const definition = {
|
|
492
107
|
frameworkVersion: '>=3.17.0',
|
|
493
108
|
service: AppDefinition.name || 'create-frigg-app',
|
|
@@ -505,14 +120,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
505
120
|
environment: {
|
|
506
121
|
STAGE: '${opt:stage}',
|
|
507
122
|
AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1,
|
|
508
|
-
// Add discovered resources to environment if available
|
|
509
|
-
...(discoveredResources.defaultVpcId && { AWS_DISCOVERY_VPC_ID: discoveredResources.defaultVpcId }),
|
|
510
|
-
...(discoveredResources.defaultSecurityGroupId && { AWS_DISCOVERY_SECURITY_GROUP_ID: discoveredResources.defaultSecurityGroupId }),
|
|
511
|
-
...(discoveredResources.privateSubnetId1 && { AWS_DISCOVERY_SUBNET_ID_1: discoveredResources.privateSubnetId1 }),
|
|
512
|
-
...(discoveredResources.privateSubnetId2 && { AWS_DISCOVERY_SUBNET_ID_2: discoveredResources.privateSubnetId2 }),
|
|
513
|
-
...(discoveredResources.publicSubnetId && { AWS_DISCOVERY_PUBLIC_SUBNET_ID: discoveredResources.publicSubnetId }),
|
|
514
|
-
...(discoveredResources.defaultRouteTableId && { AWS_DISCOVERY_ROUTE_TABLE_ID: discoveredResources.defaultRouteTableId }),
|
|
515
|
-
...(discoveredResources.defaultKmsKeyId && { AWS_DISCOVERY_KMS_KEY_ID: discoveredResources.defaultKmsKeyId }),
|
|
516
123
|
},
|
|
517
124
|
iamRoleStatements: [
|
|
518
125
|
{
|
|
@@ -573,6 +180,26 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
573
180
|
},
|
|
574
181
|
},
|
|
575
182
|
functions: {
|
|
183
|
+
defaultWebsocket: {
|
|
184
|
+
handler: 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
185
|
+
events: [
|
|
186
|
+
{
|
|
187
|
+
websocket: {
|
|
188
|
+
route: '$connect',
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
websocket: {
|
|
193
|
+
route: '$default',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
websocket: {
|
|
198
|
+
route: '$disconnect',
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
576
203
|
auth: {
|
|
577
204
|
handler: 'node_modules/@friggframework/core/handlers/routers/auth.handler',
|
|
578
205
|
events: [
|
|
@@ -618,7 +245,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
618
245
|
Type: 'AWS::SQS::Queue',
|
|
619
246
|
Properties: {
|
|
620
247
|
QueueName:
|
|
621
|
-
'
|
|
248
|
+
'internal-error-queue-${self:provider.stage}',
|
|
622
249
|
MessageRetentionPeriod: 300,
|
|
623
250
|
},
|
|
624
251
|
},
|
|
@@ -702,7 +329,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
702
329
|
},
|
|
703
330
|
};
|
|
704
331
|
|
|
705
|
-
|
|
706
332
|
// KMS Configuration based on App Definition
|
|
707
333
|
if (AppDefinition.encryption?.useDefaultKMSForFieldLevelEncryption === true) {
|
|
708
334
|
// Add KMS IAM permissions
|
|
@@ -721,183 +347,12 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
721
347
|
// Add serverless-kms-grants plugin
|
|
722
348
|
definition.plugins.push('serverless-kms-grants');
|
|
723
349
|
|
|
724
|
-
// Configure KMS grants with
|
|
350
|
+
// Configure KMS grants with default key
|
|
725
351
|
definition.custom.kmsGrants = {
|
|
726
|
-
kmsKeyId:
|
|
352
|
+
kmsKeyId: '*'
|
|
727
353
|
};
|
|
728
354
|
}
|
|
729
355
|
|
|
730
|
-
// VPC Configuration based on App Definition
|
|
731
|
-
if (AppDefinition.vpc?.enable === true) {
|
|
732
|
-
// Add VPC-related IAM permissions
|
|
733
|
-
definition.provider.iamRoleStatements.push({
|
|
734
|
-
Effect: 'Allow',
|
|
735
|
-
Action: [
|
|
736
|
-
'ec2:CreateNetworkInterface',
|
|
737
|
-
'ec2:DescribeNetworkInterfaces',
|
|
738
|
-
'ec2:DeleteNetworkInterface',
|
|
739
|
-
'ec2:AttachNetworkInterface',
|
|
740
|
-
'ec2:DetachNetworkInterface'
|
|
741
|
-
],
|
|
742
|
-
Resource: '*'
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
// Default approach: Use AWS Discovery to find existing VPC resources
|
|
746
|
-
if (AppDefinition.vpc.createNew === true) {
|
|
747
|
-
// Option 1: Create new VPC infrastructure (explicit opt-in)
|
|
748
|
-
const vpcConfig = {};
|
|
749
|
-
|
|
750
|
-
if (AppDefinition.vpc.securityGroupIds) {
|
|
751
|
-
// User provided custom security groups
|
|
752
|
-
vpcConfig.securityGroupIds = AppDefinition.vpc.securityGroupIds;
|
|
753
|
-
} else {
|
|
754
|
-
// Use auto-created security group
|
|
755
|
-
vpcConfig.securityGroupIds = [{ Ref: 'FriggLambdaSecurityGroup' }];
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
if (AppDefinition.vpc.subnetIds) {
|
|
759
|
-
// User provided custom subnets
|
|
760
|
-
vpcConfig.subnetIds = AppDefinition.vpc.subnetIds;
|
|
761
|
-
} else {
|
|
762
|
-
// Use auto-created private subnets
|
|
763
|
-
vpcConfig.subnetIds = [
|
|
764
|
-
{ Ref: 'FriggPrivateSubnet1' },
|
|
765
|
-
{ Ref: 'FriggPrivateSubnet2' }
|
|
766
|
-
];
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// Set VPC config for Lambda functions
|
|
770
|
-
definition.provider.vpc = vpcConfig;
|
|
771
|
-
|
|
772
|
-
// Add VPC infrastructure resources to CloudFormation
|
|
773
|
-
const vpcResources = createVPCInfrastructure(AppDefinition);
|
|
774
|
-
Object.assign(definition.resources.Resources, vpcResources);
|
|
775
|
-
} else {
|
|
776
|
-
// Option 2: Use AWS Discovery (default behavior)
|
|
777
|
-
// VPC configuration using discovered or explicitly provided resources
|
|
778
|
-
const vpcConfig = {
|
|
779
|
-
securityGroupIds: AppDefinition.vpc.securityGroupIds ||
|
|
780
|
-
(discoveredResources.defaultSecurityGroupId ? [discoveredResources.defaultSecurityGroupId] : []),
|
|
781
|
-
subnetIds: AppDefinition.vpc.subnetIds ||
|
|
782
|
-
(discoveredResources.privateSubnetId1 && discoveredResources.privateSubnetId2 ?
|
|
783
|
-
[discoveredResources.privateSubnetId1, discoveredResources.privateSubnetId2] :
|
|
784
|
-
[])
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
// Set VPC config for Lambda functions only if we have valid subnet IDs
|
|
788
|
-
if (vpcConfig.subnetIds.length >= 2 && vpcConfig.securityGroupIds.length > 0) {
|
|
789
|
-
definition.provider.vpc = vpcConfig;
|
|
790
|
-
|
|
791
|
-
// Always create NAT Gateway for Lambda internet access
|
|
792
|
-
// Default VPCs don't have NAT gateways, so we need to create them
|
|
793
|
-
definition.resources.Resources.FriggNATGatewayEIP = {
|
|
794
|
-
Type: 'AWS::EC2::EIP',
|
|
795
|
-
Properties: {
|
|
796
|
-
Domain: 'vpc',
|
|
797
|
-
Tags: [
|
|
798
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-eip' }
|
|
799
|
-
]
|
|
800
|
-
}
|
|
801
|
-
};
|
|
802
|
-
|
|
803
|
-
definition.resources.Resources.FriggNATGateway = {
|
|
804
|
-
Type: 'AWS::EC2::NatGateway',
|
|
805
|
-
Properties: {
|
|
806
|
-
AllocationId: { 'Fn::GetAtt': ['FriggNATGatewayEIP', 'AllocationId'] },
|
|
807
|
-
SubnetId: discoveredResources.publicSubnetId || discoveredResources.privateSubnetId1, // Use first discovered subnet if no public subnet found
|
|
808
|
-
Tags: [
|
|
809
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-nat-gateway' }
|
|
810
|
-
]
|
|
811
|
-
}
|
|
812
|
-
};
|
|
813
|
-
|
|
814
|
-
// Create route table for Lambda subnets to use NAT Gateway
|
|
815
|
-
definition.resources.Resources.FriggLambdaRouteTable = {
|
|
816
|
-
Type: 'AWS::EC2::RouteTable',
|
|
817
|
-
Properties: {
|
|
818
|
-
VpcId: discoveredResources.defaultVpcId || { Ref: 'FriggVPC' },
|
|
819
|
-
Tags: [
|
|
820
|
-
{ Key: 'Name', Value: '${self:service}-${self:provider.stage}-lambda-rt' }
|
|
821
|
-
]
|
|
822
|
-
}
|
|
823
|
-
};
|
|
824
|
-
|
|
825
|
-
definition.resources.Resources.FriggNATRoute = {
|
|
826
|
-
Type: 'AWS::EC2::Route',
|
|
827
|
-
Properties: {
|
|
828
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' },
|
|
829
|
-
DestinationCidrBlock: '0.0.0.0/0',
|
|
830
|
-
NatGatewayId: { Ref: 'FriggNATGateway' }
|
|
831
|
-
}
|
|
832
|
-
};
|
|
833
|
-
|
|
834
|
-
// Associate Lambda subnets with NAT Gateway route table
|
|
835
|
-
definition.resources.Resources.FriggSubnet1RouteAssociation = {
|
|
836
|
-
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
837
|
-
Properties: {
|
|
838
|
-
SubnetId: vpcConfig.subnetIds[0],
|
|
839
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' }
|
|
840
|
-
}
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
definition.resources.Resources.FriggSubnet2RouteAssociation = {
|
|
844
|
-
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
845
|
-
Properties: {
|
|
846
|
-
SubnetId: vpcConfig.subnetIds[1],
|
|
847
|
-
RouteTableId: { Ref: 'FriggLambdaRouteTable' }
|
|
848
|
-
}
|
|
849
|
-
};
|
|
850
|
-
|
|
851
|
-
// Add VPC endpoints for AWS service optimization (optional but recommended)
|
|
852
|
-
if (AppDefinition.vpc.enableVPCEndpoints !== false) {
|
|
853
|
-
definition.resources.Resources.VPCEndpointS3 = {
|
|
854
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
855
|
-
Properties: {
|
|
856
|
-
VpcId: discoveredResources.defaultVpcId,
|
|
857
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.s3',
|
|
858
|
-
VpcEndpointType: 'Gateway',
|
|
859
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
860
|
-
}
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
definition.resources.Resources.VPCEndpointDynamoDB = {
|
|
864
|
-
Type: 'AWS::EC2::VPCEndpoint',
|
|
865
|
-
Properties: {
|
|
866
|
-
VpcId: discoveredResources.defaultVpcId,
|
|
867
|
-
ServiceName: 'com.amazonaws.${self:provider.region}.dynamodb',
|
|
868
|
-
VpcEndpointType: 'Gateway',
|
|
869
|
-
RouteTableIds: [{ Ref: 'FriggLambdaRouteTable' }]
|
|
870
|
-
}
|
|
871
|
-
};
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
// SSM Parameter Store Configuration based on App Definition
|
|
878
|
-
if (AppDefinition.ssm?.enable === true) {
|
|
879
|
-
// Add AWS Parameters and Secrets Lambda Extension layer
|
|
880
|
-
definition.provider.layers = [
|
|
881
|
-
'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
|
|
882
|
-
];
|
|
883
|
-
|
|
884
|
-
// Add SSM IAM permissions
|
|
885
|
-
definition.provider.iamRoleStatements.push({
|
|
886
|
-
Effect: 'Allow',
|
|
887
|
-
Action: [
|
|
888
|
-
'ssm:GetParameter',
|
|
889
|
-
'ssm:GetParameters',
|
|
890
|
-
'ssm:GetParametersByPath'
|
|
891
|
-
],
|
|
892
|
-
Resource: [
|
|
893
|
-
'arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*'
|
|
894
|
-
]
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
// Add environment variable for SSM parameter prefix
|
|
898
|
-
definition.provider.environment.SSM_PARAMETER_PREFIX = '/${self:service}/${self:provider.stage}';
|
|
899
|
-
}
|
|
900
|
-
|
|
901
356
|
// Add integration-specific functions and resources
|
|
902
357
|
for (const integration of AppDefinition.integrations) {
|
|
903
358
|
const integrationName = integration.Definition.name;
|
|
@@ -964,33 +419,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
964
419
|
definition.custom[queueReference] = queueName;
|
|
965
420
|
}
|
|
966
421
|
|
|
967
|
-
// Discovery has already run successfully at this point if needed
|
|
968
|
-
// The discoveredResources object contains all the necessary AWS resources
|
|
969
|
-
|
|
970
|
-
// Add websocket function if enabled
|
|
971
|
-
if (AppDefinition.websockets?.enable === true) {
|
|
972
|
-
definition.functions.defaultWebsocket = {
|
|
973
|
-
handler: 'node_modules/@friggframework/core/handlers/routers/websocket.handler',
|
|
974
|
-
events: [
|
|
975
|
-
{
|
|
976
|
-
websocket: {
|
|
977
|
-
route: '$connect',
|
|
978
|
-
},
|
|
979
|
-
},
|
|
980
|
-
{
|
|
981
|
-
websocket: {
|
|
982
|
-
route: '$default',
|
|
983
|
-
},
|
|
984
|
-
},
|
|
985
|
-
{
|
|
986
|
-
websocket: {
|
|
987
|
-
route: '$disconnect',
|
|
988
|
-
},
|
|
989
|
-
},
|
|
990
|
-
],
|
|
991
|
-
};
|
|
992
|
-
}
|
|
993
|
-
|
|
994
422
|
// Modify handler paths to point to the correct node_modules location
|
|
995
423
|
definition.functions = modifyHandlerPaths(definition.functions);
|
|
996
424
|
|