@friggframework/devtools 2.0.0--canary.490.feacde9.0 → 2.0.0--canary.497.a3f25f9.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/deploy-command/index.js +3 -9
- package/infrastructure/README.md +0 -28
- package/infrastructure/domains/database/migration-builder.js +13 -19
- package/infrastructure/domains/database/migration-builder.test.js +0 -57
- package/infrastructure/domains/integration/integration-builder.js +14 -19
- package/infrastructure/domains/integration/integration-builder.test.js +74 -0
- package/infrastructure/domains/networking/vpc-builder.js +18 -240
- package/infrastructure/domains/networking/vpc-builder.test.js +13 -711
- package/infrastructure/domains/networking/vpc-resolver.js +40 -221
- package/infrastructure/domains/networking/vpc-resolver.test.js +18 -318
- package/infrastructure/domains/security/kms-builder.js +6 -55
- package/infrastructure/domains/security/kms-builder.test.js +1 -19
- package/infrastructure/domains/shared/cloudformation-discovery.js +13 -310
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +0 -395
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +6 -41
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +0 -39
- package/infrastructure/domains/shared/resource-discovery.js +5 -17
- package/infrastructure/domains/shared/resource-discovery.test.js +0 -36
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +17 -27
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +0 -73
- package/infrastructure/infrastructure-composer.js +3 -11
- package/infrastructure/scripts/build-prisma-layer.js +81 -8
- package/infrastructure/scripts/build-prisma-layer.test.js +53 -1
- package/infrastructure/scripts/verify-prisma-layer.js +72 -0
- package/package.json +7 -7
- package/layers/prisma/.build-complete +0 -3
|
@@ -23,35 +23,13 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
23
23
|
*/
|
|
24
24
|
resolveVpc(appDefinition, discovery) {
|
|
25
25
|
const userIntent = appDefinition.vpc?.ownership?.vpc || 'auto';
|
|
26
|
-
const vpcManagement = appDefinition.vpc?.management; // Legacy config
|
|
27
26
|
|
|
28
27
|
// Explicit external
|
|
29
28
|
if (userIntent === 'external') {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return this.createExternalDecision(
|
|
35
|
-
externalVpcId,
|
|
36
|
-
'User specified ownership=external with hardcoded vpcId'
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// No hardcoded ID - try discovery
|
|
41
|
-
const discoveredVpcId = discovery.defaultVpcId;
|
|
42
|
-
|
|
43
|
-
if (discoveredVpcId) {
|
|
44
|
-
return this.createExternalDecision(
|
|
45
|
-
discoveredVpcId,
|
|
46
|
-
'User specified ownership=external - using discovered VPC'
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Discovery found nothing - error
|
|
51
|
-
throw new Error(
|
|
52
|
-
"ownership='external' for VPC requires either:\n" +
|
|
53
|
-
" 1. Hardcoded external.vpcId, OR\n" +
|
|
54
|
-
" 2. A VPC discovered via AWS discovery"
|
|
29
|
+
this.requireExternalIds(appDefinition.vpc?.external?.vpcId, 'vpcId');
|
|
30
|
+
return this.createExternalDecision(
|
|
31
|
+
appDefinition.vpc.external.vpcId,
|
|
32
|
+
'User specified ownership=external for VPC'
|
|
55
33
|
);
|
|
56
34
|
}
|
|
57
35
|
|
|
@@ -65,35 +43,20 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
65
43
|
}
|
|
66
44
|
|
|
67
45
|
// Auto-decide
|
|
68
|
-
|
|
46
|
+
return this.resolveResourceOwnership(
|
|
69
47
|
'auto',
|
|
70
48
|
'FriggVPC',
|
|
71
49
|
'AWS::EC2::VPC',
|
|
72
50
|
discovery
|
|
73
51
|
);
|
|
74
|
-
|
|
75
|
-
// CRITICAL: If auto-resolution wants to create a VPC but management mode is 'discover' (or undefined),
|
|
76
|
-
// throw an error instead. Creating a VPC is expensive and should be explicit.
|
|
77
|
-
if (decision.ownership === ResourceOwnership.STACK &&
|
|
78
|
-
!decision.physicalId &&
|
|
79
|
-
vpcManagement !== 'create-new' &&
|
|
80
|
-
userIntent === 'auto') {
|
|
81
|
-
throw new Error(
|
|
82
|
-
'VPC discovery failed: No VPC found. ' +
|
|
83
|
-
'Either set vpc.management to "create-new" or provide vpc.vpcId with vpc.management "use-existing".'
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return decision;
|
|
88
52
|
}
|
|
89
53
|
|
|
90
54
|
/**
|
|
91
55
|
* Resolve Security Group ownership
|
|
92
56
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* - Otherwise → STACK (create FriggLambdaSecurityGroup)
|
|
57
|
+
* Special logic: We ALWAYS create our own FriggLambdaSecurityGroup with specific
|
|
58
|
+
* rules unless the user explicitly provides external SG IDs. The discovered
|
|
59
|
+
* defaultSecurityGroupId is the VPC's default SG, but we need our own Lambda SG.
|
|
97
60
|
*
|
|
98
61
|
* @param {Object} appDefinition - App definition
|
|
99
62
|
* @param {Object} discovery - Discovery result
|
|
@@ -102,95 +65,33 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
102
65
|
resolveSecurityGroup(appDefinition, discovery) {
|
|
103
66
|
const userIntent = appDefinition.vpc?.ownership?.securityGroup || 'auto';
|
|
104
67
|
|
|
105
|
-
// Explicit external
|
|
68
|
+
// Explicit external - only use external SGs if user explicitly provides them
|
|
106
69
|
if (userIntent === 'external') {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (externalIds && externalIds.length > 0) {
|
|
111
|
-
return this.createExternalDecision(
|
|
112
|
-
externalIds,
|
|
113
|
-
'User specified ownership=external with hardcoded securityGroupIds'
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// No hardcoded IDs - try discovery
|
|
118
|
-
const structured = discovery._structured || discovery;
|
|
119
|
-
|
|
120
|
-
// When ownership='external', use ONLY the default SG, not the stack-managed lambda SG
|
|
121
|
-
const lambdaSgId = structured.lambdaSecurityGroupId || discovery.lambdaSecurityGroupId;
|
|
122
|
-
const defaultSgId = structured.defaultSecurityGroupId || discovery.defaultSecurityGroupId;
|
|
123
|
-
|
|
124
|
-
// If we have a default SG AND it's different from the lambda SG, use the default
|
|
125
|
-
if (defaultSgId && defaultSgId !== lambdaSgId) {
|
|
126
|
-
return this.createExternalDecision(
|
|
127
|
-
[defaultSgId],
|
|
128
|
-
'User specified ownership=external - using discovered default security group'
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// If only defaultSgId exists (no lambdaSgId), use it
|
|
133
|
-
if (defaultSgId && !lambdaSgId) {
|
|
134
|
-
return this.createExternalDecision(
|
|
135
|
-
[defaultSgId],
|
|
136
|
-
'User specified ownership=external - using discovered default security group'
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Discovery found nothing - error
|
|
141
|
-
throw new Error(
|
|
142
|
-
"ownership='external' for securityGroup requires either:\n" +
|
|
143
|
-
" 1. Hardcoded external.securityGroupIds array, OR\n" +
|
|
144
|
-
" 2. A default security group discovered via AWS discovery"
|
|
70
|
+
this.requireExternalIds(
|
|
71
|
+
appDefinition.vpc?.external?.securityGroupIds,
|
|
72
|
+
'securityGroupIds'
|
|
145
73
|
);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (userIntent === 'stack') {
|
|
150
|
-
const inStack = this.findInStack('FriggLambdaSecurityGroup', discovery);
|
|
151
|
-
return this.createStackDecision(
|
|
152
|
-
inStack?.physicalId,
|
|
153
|
-
inStack
|
|
154
|
-
? 'Found FriggLambdaSecurityGroup in CloudFormation stack'
|
|
155
|
-
: 'User specified ownership=stack - will create FriggLambdaSecurityGroup'
|
|
74
|
+
return this.createExternalDecision(
|
|
75
|
+
appDefinition.vpc.external.securityGroupIds,
|
|
76
|
+
'User specified ownership=external for security group'
|
|
156
77
|
);
|
|
157
78
|
}
|
|
158
79
|
|
|
159
|
-
//
|
|
80
|
+
// For stack or auto: check if FriggLambdaSecurityGroup exists in stack
|
|
81
|
+
// If it does, reuse it. If not, create it. Never use discovered default SG.
|
|
160
82
|
const inStack = this.findInStack('FriggLambdaSecurityGroup', discovery);
|
|
161
83
|
|
|
162
84
|
if (inStack) {
|
|
163
85
|
return this.createStackDecision(
|
|
164
86
|
inStack.physicalId,
|
|
165
|
-
'Found FriggLambdaSecurityGroup in CloudFormation stack
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Also check flat discovery for lambdaSecurityGroupId (from CloudFormation extraction)
|
|
170
|
-
const structured = discovery._structured || discovery;
|
|
171
|
-
const lambdaSgId = structured.lambdaSecurityGroupId || discovery.lambdaSecurityGroupId;
|
|
172
|
-
|
|
173
|
-
if (lambdaSgId) {
|
|
174
|
-
return this.createStackDecision(
|
|
175
|
-
lambdaSgId,
|
|
176
|
-
'Found FriggLambdaSecurityGroup in CloudFormation stack - must keep in template'
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Check for discovered default security group (from external VPC pattern)
|
|
181
|
-
const defaultSgId = structured.defaultSecurityGroupId || discovery.defaultSecurityGroupId;
|
|
182
|
-
|
|
183
|
-
if (defaultSgId) {
|
|
184
|
-
return this.createExternalDecision(
|
|
185
|
-
[defaultSgId],
|
|
186
|
-
'Found default security group via discovery - will reuse (matches canary behavior)'
|
|
87
|
+
'Found FriggLambdaSecurityGroup in CloudFormation stack'
|
|
187
88
|
);
|
|
188
89
|
}
|
|
189
90
|
|
|
190
|
-
//
|
|
91
|
+
// Create new FriggLambdaSecurityGroup in stack
|
|
191
92
|
return this.createStackDecision(
|
|
192
93
|
null,
|
|
193
|
-
'No
|
|
94
|
+
'No existing FriggLambdaSecurityGroup - will create in stack'
|
|
194
95
|
);
|
|
195
96
|
}
|
|
196
97
|
|
|
@@ -205,32 +106,13 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
205
106
|
|
|
206
107
|
// Explicit external
|
|
207
108
|
if (userIntent === 'external') {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// No hardcoded IDs - try discovery
|
|
219
|
-
const discoveredSubnet1 = discovery.privateSubnetId1;
|
|
220
|
-
const discoveredSubnet2 = discovery.privateSubnetId2;
|
|
221
|
-
|
|
222
|
-
if (discoveredSubnet1 && discoveredSubnet2) {
|
|
223
|
-
return this.createExternalDecision(
|
|
224
|
-
[discoveredSubnet1, discoveredSubnet2],
|
|
225
|
-
'User specified ownership=external - using discovered subnets'
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Discovery found nothing - error
|
|
230
|
-
throw new Error(
|
|
231
|
-
"ownership='external' for subnets requires either:\n" +
|
|
232
|
-
" 1. Hardcoded external.subnetIds array (minimum 2), OR\n" +
|
|
233
|
-
" 2. At least 2 subnets discovered via AWS discovery"
|
|
109
|
+
this.requireExternalIds(
|
|
110
|
+
appDefinition.vpc?.external?.subnetIds,
|
|
111
|
+
'subnetIds'
|
|
112
|
+
);
|
|
113
|
+
return this.createExternalDecision(
|
|
114
|
+
appDefinition.vpc.external.subnetIds,
|
|
115
|
+
'User specified ownership=external for subnets'
|
|
234
116
|
);
|
|
235
117
|
}
|
|
236
118
|
|
|
@@ -318,31 +200,13 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
318
200
|
|
|
319
201
|
// Explicit external
|
|
320
202
|
if (userIntent === 'external') {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// No hardcoded ID - try discovery
|
|
332
|
-
const discoveredNatId = discovery.natGatewayId;
|
|
333
|
-
|
|
334
|
-
if (discoveredNatId) {
|
|
335
|
-
return this.createExternalDecision(
|
|
336
|
-
discoveredNatId,
|
|
337
|
-
'User specified ownership=external - using discovered NAT gateway'
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Discovery found nothing - error
|
|
342
|
-
throw new Error(
|
|
343
|
-
"ownership='external' for NAT gateway requires either:\n" +
|
|
344
|
-
" 1. Hardcoded external.natGatewayId, OR\n" +
|
|
345
|
-
" 2. A NAT gateway discovered via AWS discovery"
|
|
203
|
+
this.requireExternalIds(
|
|
204
|
+
appDefinition.vpc?.external?.natGatewayId,
|
|
205
|
+
'natGatewayId'
|
|
206
|
+
);
|
|
207
|
+
return this.createExternalDecision(
|
|
208
|
+
appDefinition.vpc.external.natGatewayId,
|
|
209
|
+
'User specified ownership=external for NAT gateway'
|
|
346
210
|
);
|
|
347
211
|
}
|
|
348
212
|
|
|
@@ -389,16 +253,9 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
389
253
|
const encryptionMethod = appDefinition.encryption?.fieldLevelEncryptionMethod;
|
|
390
254
|
const needsKms = encryptionMethod === 'kms';
|
|
391
255
|
|
|
392
|
-
// DynamoDB endpoint only needed if using DynamoDB (not MongoDB or PostgreSQL)
|
|
393
|
-
// Currently framework only supports MongoDB (via Prisma) and PostgreSQL (via Aurora)
|
|
394
|
-
// If not using DynamoDB, skip the endpoint (CloudFormation will delete if it exists)
|
|
395
|
-
const usesDynamoDB = appDefinition.database?.dynamodb?.enable === true;
|
|
396
|
-
|
|
397
256
|
const endpoints = {
|
|
398
257
|
s3: this._resolveEndpoint('FriggS3VPCEndpoint', 's3', userIntent, appDefinition, discovery),
|
|
399
|
-
dynamodb:
|
|
400
|
-
? this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery)
|
|
401
|
-
: { ownership: null, reason: 'DynamoDB endpoint not needed (application uses MongoDB/PostgreSQL, not DynamoDB)' },
|
|
258
|
+
dynamodb: this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery),
|
|
402
259
|
kms: needsKms
|
|
403
260
|
? this._resolveEndpoint('FriggKMSVPCEndpoint', 'kms', userIntent, appDefinition, discovery)
|
|
404
261
|
: { ownership: null, reason: 'KMS endpoint not needed (encryption method is not KMS)' },
|
|
@@ -411,20 +268,9 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
411
268
|
|
|
412
269
|
/**
|
|
413
270
|
* Resolve individual VPC endpoint
|
|
414
|
-
* Checks both old and new logical ID patterns for backwards compatibility
|
|
415
271
|
* @private
|
|
416
272
|
*/
|
|
417
273
|
_resolveEndpoint(logicalId, endpointType, userIntent, appDefinition, discovery) {
|
|
418
|
-
// Map of old logical IDs (for backwards compatibility with stacks created before naming standardization)
|
|
419
|
-
const oldLogicalIdMap = {
|
|
420
|
-
'FriggS3VPCEndpoint': 'VPCEndpointS3',
|
|
421
|
-
'FriggDynamoDBVPCEndpoint': 'VPCEndpointDynamoDB',
|
|
422
|
-
'FriggKMSVPCEndpoint': 'VPCEndpointKMS',
|
|
423
|
-
'FriggSecretsManagerVPCEndpoint': 'VPCEndpointSecretsManager',
|
|
424
|
-
'FriggSQSVPCEndpoint': 'VPCEndpointSQS'
|
|
425
|
-
};
|
|
426
|
-
const oldLogicalId = oldLogicalIdMap[logicalId];
|
|
427
|
-
|
|
428
274
|
// Explicit external
|
|
429
275
|
if (userIntent === 'external') {
|
|
430
276
|
const externalId = appDefinition.vpc?.external?.vpcEndpointIds?.[endpointType];
|
|
@@ -438,49 +284,22 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
438
284
|
return { ownership: null, reason: `External ${endpointType} endpoint ID not provided` };
|
|
439
285
|
}
|
|
440
286
|
|
|
441
|
-
// Explicit stack
|
|
287
|
+
// Explicit stack
|
|
442
288
|
if (userIntent === 'stack') {
|
|
443
|
-
|
|
444
|
-
if (!inStack && oldLogicalId) {
|
|
445
|
-
inStack = this.findInStack(oldLogicalId, discovery);
|
|
446
|
-
}
|
|
289
|
+
const inStack = this.findInStack(logicalId, discovery);
|
|
447
290
|
return this.createStackDecision(
|
|
448
291
|
inStack?.physicalId,
|
|
449
292
|
`User specified ownership=stack for ${endpointType} endpoint`
|
|
450
293
|
);
|
|
451
294
|
}
|
|
452
295
|
|
|
453
|
-
// Auto-decide
|
|
454
|
-
|
|
455
|
-
let stackResource = inStack ? this.findInStack(logicalId, discovery) : null;
|
|
456
|
-
let actualLogicalId = logicalId; // Track which ID we found
|
|
457
|
-
|
|
458
|
-
// If not found with new ID, try old ID pattern
|
|
459
|
-
if (!inStack && oldLogicalId) {
|
|
460
|
-
inStack = this.isInStack(oldLogicalId, discovery);
|
|
461
|
-
stackResource = inStack ? this.findInStack(oldLogicalId, discovery) : null;
|
|
462
|
-
if (inStack) {
|
|
463
|
-
actualLogicalId = oldLogicalId; // Found with old ID - use that for resolution
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const decision = this.resolveResourceOwnership(
|
|
296
|
+
// Auto-decide
|
|
297
|
+
return this.resolveResourceOwnership(
|
|
468
298
|
'auto',
|
|
469
|
-
|
|
299
|
+
logicalId,
|
|
470
300
|
'AWS::EC2::VPCEndpoint',
|
|
471
301
|
discovery
|
|
472
302
|
);
|
|
473
|
-
|
|
474
|
-
// Override reason with more detailed explanation
|
|
475
|
-
if (decision.ownership === 'stack' && decision.physicalId) {
|
|
476
|
-
decision.reason = `Found in CloudFormation stack (must keep in template to avoid deletion)`;
|
|
477
|
-
} else if (decision.ownership === 'stack' && !decision.physicalId) {
|
|
478
|
-
decision.reason = `No existing ${endpointType} endpoint found - will create in stack`;
|
|
479
|
-
} else if (decision.ownership === 'external') {
|
|
480
|
-
decision.reason = `Found external ${endpointType} endpoint via discovery`;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return decision;
|
|
484
303
|
}
|
|
485
304
|
|
|
486
305
|
/**
|