@friggframework/devtools 2.0.0--canary.490.df708d7.0 → 2.0.0--canary.490.a308628.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.
|
@@ -27,10 +27,31 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
27
27
|
|
|
28
28
|
// Explicit external
|
|
29
29
|
if (userIntent === 'external') {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const externalVpcId = appDefinition.vpc?.external?.vpcId;
|
|
31
|
+
|
|
32
|
+
// If hardcoded ID provided, use it
|
|
33
|
+
if (externalVpcId) {
|
|
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"
|
|
34
55
|
);
|
|
35
56
|
}
|
|
36
57
|
|
|
@@ -81,15 +102,34 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
81
102
|
resolveSecurityGroup(appDefinition, discovery) {
|
|
82
103
|
const userIntent = appDefinition.vpc?.ownership?.securityGroup || 'auto';
|
|
83
104
|
|
|
84
|
-
// Explicit external
|
|
105
|
+
// Explicit external
|
|
85
106
|
if (userIntent === 'external') {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
107
|
+
const externalIds = appDefinition.vpc?.external?.securityGroupIds;
|
|
108
|
+
|
|
109
|
+
// If hardcoded IDs provided, use those
|
|
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
|
+
const defaultSgId = structured.defaultSecurityGroupId || discovery.defaultSecurityGroupId;
|
|
120
|
+
|
|
121
|
+
if (defaultSgId) {
|
|
122
|
+
return this.createExternalDecision(
|
|
123
|
+
[defaultSgId],
|
|
124
|
+
'User specified ownership=external - using discovered default security group'
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Discovery found nothing - error
|
|
129
|
+
throw new Error(
|
|
130
|
+
"ownership='external' for securityGroup requires either:\n" +
|
|
131
|
+
" 1. Hardcoded external.securityGroupIds array, OR\n" +
|
|
132
|
+
" 2. A default security group discovered via AWS discovery"
|
|
93
133
|
);
|
|
94
134
|
}
|
|
95
135
|
|
|
@@ -153,13 +193,32 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
153
193
|
|
|
154
194
|
// Explicit external
|
|
155
195
|
if (userIntent === 'external') {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
196
|
+
const externalSubnetIds = appDefinition.vpc?.external?.subnetIds;
|
|
197
|
+
|
|
198
|
+
// If hardcoded IDs provided, use those
|
|
199
|
+
if (externalSubnetIds && externalSubnetIds.length >= 2) {
|
|
200
|
+
return this.createExternalDecision(
|
|
201
|
+
externalSubnetIds,
|
|
202
|
+
'User specified ownership=external with hardcoded subnetIds'
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// No hardcoded IDs - try discovery
|
|
207
|
+
const discoveredSubnet1 = discovery.privateSubnetId1;
|
|
208
|
+
const discoveredSubnet2 = discovery.privateSubnetId2;
|
|
209
|
+
|
|
210
|
+
if (discoveredSubnet1 && discoveredSubnet2) {
|
|
211
|
+
return this.createExternalDecision(
|
|
212
|
+
[discoveredSubnet1, discoveredSubnet2],
|
|
213
|
+
'User specified ownership=external - using discovered subnets'
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Discovery found nothing - error
|
|
218
|
+
throw new Error(
|
|
219
|
+
"ownership='external' for subnets requires either:\n" +
|
|
220
|
+
" 1. Hardcoded external.subnetIds array (minimum 2), OR\n" +
|
|
221
|
+
" 2. At least 2 subnets discovered via AWS discovery"
|
|
163
222
|
);
|
|
164
223
|
}
|
|
165
224
|
|
|
@@ -247,13 +306,31 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
247
306
|
|
|
248
307
|
// Explicit external
|
|
249
308
|
if (userIntent === 'external') {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
309
|
+
const externalNatId = appDefinition.vpc?.external?.natGatewayId;
|
|
310
|
+
|
|
311
|
+
// If hardcoded ID provided, use it
|
|
312
|
+
if (externalNatId) {
|
|
313
|
+
return this.createExternalDecision(
|
|
314
|
+
externalNatId,
|
|
315
|
+
'User specified ownership=external with hardcoded natGatewayId'
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// No hardcoded ID - try discovery
|
|
320
|
+
const discoveredNatId = discovery.natGatewayId;
|
|
321
|
+
|
|
322
|
+
if (discoveredNatId) {
|
|
323
|
+
return this.createExternalDecision(
|
|
324
|
+
discoveredNatId,
|
|
325
|
+
'User specified ownership=external - using discovered NAT gateway'
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Discovery found nothing - error
|
|
330
|
+
throw new Error(
|
|
331
|
+
"ownership='external' for NAT gateway requires either:\n" +
|
|
332
|
+
" 1. Hardcoded external.natGatewayId, OR\n" +
|
|
333
|
+
" 2. A NAT gateway discovered via AWS discovery"
|
|
257
334
|
);
|
|
258
335
|
}
|
|
259
336
|
|
|
@@ -302,21 +379,14 @@ class VpcResourceResolver extends BaseResourceResolver {
|
|
|
302
379
|
|
|
303
380
|
// DynamoDB endpoint only needed if using DynamoDB (not MongoDB or PostgreSQL)
|
|
304
381
|
// Currently framework only supports MongoDB (via Prisma) and PostgreSQL (via Aurora)
|
|
305
|
-
//
|
|
382
|
+
// If not using DynamoDB, skip the endpoint (CloudFormation will delete if it exists)
|
|
306
383
|
const usesDynamoDB = appDefinition.database?.dynamodb?.enable === true;
|
|
307
|
-
|
|
308
|
-
// Special case: If DynamoDB endpoint exists in stack but not needed, preserve it
|
|
309
|
-
// to avoid deletion (user may have enabled it previously)
|
|
310
|
-
const dynamoDbInStack = this.isInStack('FriggDynamoDBVPCEndpoint', discovery);
|
|
311
|
-
const shouldPreserveDynamoDB = !usesDynamoDB && dynamoDbInStack;
|
|
312
384
|
|
|
313
385
|
const endpoints = {
|
|
314
386
|
s3: this._resolveEndpoint('FriggS3VPCEndpoint', 's3', userIntent, appDefinition, discovery),
|
|
315
387
|
dynamodb: usesDynamoDB
|
|
316
388
|
? this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery)
|
|
317
|
-
:
|
|
318
|
-
? this._resolveEndpoint('FriggDynamoDBVPCEndpoint', 'dynamodb', userIntent, appDefinition, discovery)
|
|
319
|
-
: { ownership: null, reason: 'DynamoDB endpoint not needed (application uses MongoDB/PostgreSQL, not DynamoDB)' },
|
|
389
|
+
: { ownership: null, reason: 'DynamoDB endpoint not needed (application uses MongoDB/PostgreSQL, not DynamoDB)' },
|
|
320
390
|
kms: needsKms
|
|
321
391
|
? this._resolveEndpoint('FriggKMSVPCEndpoint', 'kms', userIntent, appDefinition, discovery)
|
|
322
392
|
: { ownership: null, reason: 'KMS endpoint not needed (encryption method is not KMS)' },
|
|
@@ -9,7 +9,7 @@ describe('VpcResourceResolver', () => {
|
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
describe('resolveVpc', () => {
|
|
12
|
-
it('should resolve to EXTERNAL
|
|
12
|
+
it('should resolve to EXTERNAL with hardcoded vpcId', () => {
|
|
13
13
|
const appDefinition = {
|
|
14
14
|
vpc: {
|
|
15
15
|
ownership: { vpc: 'external' },
|
|
@@ -22,20 +22,46 @@ describe('VpcResourceResolver', () => {
|
|
|
22
22
|
|
|
23
23
|
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
24
24
|
expect(decision.physicalId).toBe('vpc-external-123');
|
|
25
|
-
expect(decision.reason).toContain('
|
|
25
|
+
expect(decision.reason).toContain('hardcoded vpcId');
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
it('should
|
|
28
|
+
it('should resolve to EXTERNAL using discovered VPC when no hardcoded ID', () => {
|
|
29
29
|
const appDefinition = {
|
|
30
30
|
vpc: {
|
|
31
|
-
ownership: { vpc: 'external' }
|
|
32
|
-
external
|
|
31
|
+
ownership: { vpc: 'external' }
|
|
32
|
+
// No external.vpcId provided
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
|
-
const discovery = {
|
|
35
|
+
const discovery = {
|
|
36
|
+
stackManaged: [],
|
|
37
|
+
external: [],
|
|
38
|
+
fromCloudFormation: false,
|
|
39
|
+
defaultVpcId: 'vpc-discovered-123'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const decision = resolver.resolveVpc(appDefinition, discovery);
|
|
43
|
+
|
|
44
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
45
|
+
expect(decision.physicalId).toBe('vpc-discovered-123');
|
|
46
|
+
expect(decision.reason).toContain('discovered VPC');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should throw when external specified but no vpcId and no discovery', () => {
|
|
50
|
+
const appDefinition = {
|
|
51
|
+
vpc: {
|
|
52
|
+
ownership: { vpc: 'external' }
|
|
53
|
+
// No external.vpcId provided
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const discovery = {
|
|
57
|
+
stackManaged: [],
|
|
58
|
+
external: [],
|
|
59
|
+
fromCloudFormation: false
|
|
60
|
+
// No defaultVpcId discovered
|
|
61
|
+
};
|
|
36
62
|
|
|
37
63
|
expect(() => resolver.resolveVpc(appDefinition, discovery)).toThrow(
|
|
38
|
-
|
|
64
|
+
/ownership='external' for VPC requires either/
|
|
39
65
|
);
|
|
40
66
|
});
|
|
41
67
|
|
|
@@ -97,17 +123,17 @@ describe('VpcResourceResolver', () => {
|
|
|
97
123
|
expect(decision.physicalId).toBe('vpc-external');
|
|
98
124
|
});
|
|
99
125
|
|
|
100
|
-
it('should auto
|
|
126
|
+
it('should throw error when auto mode finds no VPC (changed behavior)', () => {
|
|
101
127
|
const appDefinition = {
|
|
102
128
|
vpc: { ownership: { vpc: 'auto' } }
|
|
129
|
+
// No management specified - defaults to discover
|
|
103
130
|
};
|
|
104
131
|
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
105
132
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
expect(decision.reason).toContain('No existing resource found');
|
|
133
|
+
// NEW BEHAVIOR: Auto mode with no VPC found should throw error (prevent accidental VPC creation)
|
|
134
|
+
expect(() => resolver.resolveVpc(appDefinition, discovery)).toThrow(
|
|
135
|
+
'VPC discovery failed: No VPC found'
|
|
136
|
+
);
|
|
111
137
|
});
|
|
112
138
|
|
|
113
139
|
it('should throw error when auto mode finds no VPC and management is not create-new', () => {
|
|
@@ -134,7 +160,8 @@ describe('VpcResourceResolver', () => {
|
|
|
134
160
|
const appDefinition = {
|
|
135
161
|
vpc: {
|
|
136
162
|
enable: true,
|
|
137
|
-
management: 'create-new'
|
|
163
|
+
management: 'create-new',
|
|
164
|
+
ownership: { vpc: 'auto' }
|
|
138
165
|
}
|
|
139
166
|
};
|
|
140
167
|
const discovery = {
|
|
@@ -147,12 +174,12 @@ describe('VpcResourceResolver', () => {
|
|
|
147
174
|
const decision = resolver.resolveVpc(appDefinition, discovery);
|
|
148
175
|
|
|
149
176
|
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
150
|
-
expect(decision.physicalId).
|
|
177
|
+
expect(decision.physicalId).toBeUndefined(); // resolveResourceOwnership returns undefined, not null
|
|
151
178
|
});
|
|
152
179
|
});
|
|
153
180
|
|
|
154
181
|
describe('resolveSecurityGroup', () => {
|
|
155
|
-
it('should resolve to EXTERNAL with user-provided IDs', () => {
|
|
182
|
+
it('should resolve to EXTERNAL with user-provided hardcoded IDs', () => {
|
|
156
183
|
const appDefinition = {
|
|
157
184
|
vpc: {
|
|
158
185
|
ownership: { securityGroup: 'external' },
|
|
@@ -165,6 +192,47 @@ describe('VpcResourceResolver', () => {
|
|
|
165
192
|
|
|
166
193
|
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
167
194
|
expect(decision.physicalIds).toEqual(['sg-1', 'sg-2']);
|
|
195
|
+
expect(decision.reason).toContain('hardcoded');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should resolve to EXTERNAL using discovered default SG when no hardcoded IDs', () => {
|
|
199
|
+
const appDefinition = {
|
|
200
|
+
vpc: {
|
|
201
|
+
ownership: { securityGroup: 'external' }
|
|
202
|
+
// No external.securityGroupIds provided
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const discovery = {
|
|
206
|
+
stackManaged: [],
|
|
207
|
+
external: [],
|
|
208
|
+
fromCloudFormation: false,
|
|
209
|
+
defaultSecurityGroupId: 'sg-discovered-default'
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const decision = resolver.resolveSecurityGroup(appDefinition, discovery);
|
|
213
|
+
|
|
214
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
215
|
+
expect(decision.physicalIds).toEqual(['sg-discovered-default']);
|
|
216
|
+
expect(decision.reason).toContain('discovered default security group');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should throw error when ownership=external but no IDs and no discovery', () => {
|
|
220
|
+
const appDefinition = {
|
|
221
|
+
vpc: {
|
|
222
|
+
ownership: { securityGroup: 'external' }
|
|
223
|
+
// No external.securityGroupIds provided
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const discovery = {
|
|
227
|
+
stackManaged: [],
|
|
228
|
+
external: [],
|
|
229
|
+
fromCloudFormation: false
|
|
230
|
+
// No defaultSecurityGroupId discovered
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
expect(() => resolver.resolveSecurityGroup(appDefinition, discovery)).toThrow(
|
|
234
|
+
/ownership='external' for securityGroup requires either/
|
|
235
|
+
);
|
|
168
236
|
});
|
|
169
237
|
|
|
170
238
|
it('should auto-resolve to STACK when FriggLambdaSecurityGroup in stack', () => {
|
|
@@ -186,7 +254,7 @@ describe('VpcResourceResolver', () => {
|
|
|
186
254
|
});
|
|
187
255
|
|
|
188
256
|
describe('resolveSubnets', () => {
|
|
189
|
-
it('should resolve to EXTERNAL with user-provided subnet IDs', () => {
|
|
257
|
+
it('should resolve to EXTERNAL with user-provided hardcoded subnet IDs', () => {
|
|
190
258
|
const appDefinition = {
|
|
191
259
|
vpc: {
|
|
192
260
|
ownership: { subnets: 'external' },
|
|
@@ -199,6 +267,48 @@ describe('VpcResourceResolver', () => {
|
|
|
199
267
|
|
|
200
268
|
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
201
269
|
expect(decision.physicalIds).toEqual(['subnet-1', 'subnet-2', 'subnet-3']);
|
|
270
|
+
expect(decision.reason).toContain('hardcoded');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should resolve to EXTERNAL using discovered subnets when no hardcoded IDs', () => {
|
|
274
|
+
const appDefinition = {
|
|
275
|
+
vpc: {
|
|
276
|
+
ownership: { subnets: 'external' }
|
|
277
|
+
// No external.subnetIds provided
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const discovery = {
|
|
281
|
+
stackManaged: [],
|
|
282
|
+
external: [],
|
|
283
|
+
fromCloudFormation: false,
|
|
284
|
+
privateSubnetId1: 'subnet-discovered-1',
|
|
285
|
+
privateSubnetId2: 'subnet-discovered-2'
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const decision = resolver.resolveSubnets(appDefinition, discovery);
|
|
289
|
+
|
|
290
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
291
|
+
expect(decision.physicalIds).toEqual(['subnet-discovered-1', 'subnet-discovered-2']);
|
|
292
|
+
expect(decision.reason).toContain('discovered subnets');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should throw error when ownership=external but no IDs and no discovery', () => {
|
|
296
|
+
const appDefinition = {
|
|
297
|
+
vpc: {
|
|
298
|
+
ownership: { subnets: 'external' }
|
|
299
|
+
// No external.subnetIds provided
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const discovery = {
|
|
303
|
+
stackManaged: [],
|
|
304
|
+
external: [],
|
|
305
|
+
fromCloudFormation: false
|
|
306
|
+
// No privateSubnetId1/2 discovered
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
expect(() => resolver.resolveSubnets(appDefinition, discovery)).toThrow(
|
|
310
|
+
/ownership='external' for subnets requires either/
|
|
311
|
+
);
|
|
202
312
|
});
|
|
203
313
|
|
|
204
314
|
it('should resolve to STACK when subnets found in stack', () => {
|
|
@@ -267,7 +377,7 @@ describe('VpcResourceResolver', () => {
|
|
|
267
377
|
expect(decision.reason).toContain('NAT Gateway disabled');
|
|
268
378
|
});
|
|
269
379
|
|
|
270
|
-
it('should resolve to EXTERNAL with user-provided ID', () => {
|
|
380
|
+
it('should resolve to EXTERNAL with user-provided hardcoded ID', () => {
|
|
271
381
|
const appDefinition = {
|
|
272
382
|
vpc: {
|
|
273
383
|
ownership: { natGateway: 'external' },
|
|
@@ -280,6 +390,47 @@ describe('VpcResourceResolver', () => {
|
|
|
280
390
|
|
|
281
391
|
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
282
392
|
expect(decision.physicalId).toBe('nat-external-123');
|
|
393
|
+
expect(decision.reason).toContain('hardcoded');
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('should resolve to EXTERNAL using discovered NAT when no hardcoded ID', () => {
|
|
397
|
+
const appDefinition = {
|
|
398
|
+
vpc: {
|
|
399
|
+
ownership: { natGateway: 'external' }
|
|
400
|
+
// No external.natGatewayId provided
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
const discovery = {
|
|
404
|
+
stackManaged: [],
|
|
405
|
+
external: [],
|
|
406
|
+
fromCloudFormation: false,
|
|
407
|
+
natGatewayId: 'nat-discovered-123'
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const decision = resolver.resolveNatGateway(appDefinition, discovery);
|
|
411
|
+
|
|
412
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
413
|
+
expect(decision.physicalId).toBe('nat-discovered-123');
|
|
414
|
+
expect(decision.reason).toContain('discovered NAT gateway');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('should throw error when ownership=external but no ID and no discovery', () => {
|
|
418
|
+
const appDefinition = {
|
|
419
|
+
vpc: {
|
|
420
|
+
ownership: { natGateway: 'external' }
|
|
421
|
+
// No external.natGatewayId provided
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
const discovery = {
|
|
425
|
+
stackManaged: [],
|
|
426
|
+
external: [],
|
|
427
|
+
fromCloudFormation: false
|
|
428
|
+
// No natGatewayId discovered
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
expect(() => resolver.resolveNatGateway(appDefinition, discovery)).toThrow(
|
|
432
|
+
/ownership='external' for NAT gateway requires either/
|
|
433
|
+
);
|
|
283
434
|
});
|
|
284
435
|
|
|
285
436
|
it('should auto-resolve to STACK when found in stack', () => {
|
|
@@ -355,7 +506,7 @@ describe('VpcResourceResolver', () => {
|
|
|
355
506
|
expect(decisions.dynamodb.ownership).toBe('stack'); // DynamoDB needed
|
|
356
507
|
});
|
|
357
508
|
|
|
358
|
-
it('should
|
|
509
|
+
it('should allow deletion of DynamoDB endpoint when not needed', () => {
|
|
359
510
|
const appDefinition = {
|
|
360
511
|
vpc: { ownership: { vpcEndpoints: 'auto' } },
|
|
361
512
|
database: { mongoDB: { enable: true } }, // Using MongoDB (DynamoDB not needed)
|
|
@@ -370,9 +521,9 @@ describe('VpcResourceResolver', () => {
|
|
|
370
521
|
|
|
371
522
|
const decisions = resolver.resolveVpcEndpoints(appDefinition, discovery);
|
|
372
523
|
|
|
373
|
-
// Should
|
|
374
|
-
expect(decisions.dynamodb.ownership).
|
|
375
|
-
expect(decisions.dynamodb.
|
|
524
|
+
// Should return null (allow CloudFormation to delete it since not needed)
|
|
525
|
+
expect(decisions.dynamodb.ownership).toBeNull();
|
|
526
|
+
expect(decisions.dynamodb.reason).toContain('MongoDB/PostgreSQL');
|
|
376
527
|
});
|
|
377
528
|
|
|
378
529
|
|
|
@@ -404,7 +555,8 @@ describe('VpcResourceResolver', () => {
|
|
|
404
555
|
dynamodb: 'vpce-ddb-456'
|
|
405
556
|
}
|
|
406
557
|
}
|
|
407
|
-
}
|
|
558
|
+
},
|
|
559
|
+
database: { dynamodb: { enable: true } } // Enable DynamoDB
|
|
408
560
|
};
|
|
409
561
|
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
410
562
|
|
|
@@ -418,7 +570,10 @@ describe('VpcResourceResolver', () => {
|
|
|
418
570
|
});
|
|
419
571
|
|
|
420
572
|
it('should auto-resolve to STACK when endpoints found in stack', () => {
|
|
421
|
-
const appDefinition = {
|
|
573
|
+
const appDefinition = {
|
|
574
|
+
vpc: { ownership: { vpcEndpoints: 'auto' } },
|
|
575
|
+
database: { dynamodb: { enable: true } } // Enable DynamoDB
|
|
576
|
+
};
|
|
422
577
|
const discovery = {
|
|
423
578
|
stackManaged: [
|
|
424
579
|
{ logicalId: 'FriggS3VPCEndpoint', physicalId: 'vpce-s3-stack', resourceType: 'AWS::EC2::VPCEndpoint' },
|
|
@@ -439,7 +594,8 @@ describe('VpcResourceResolver', () => {
|
|
|
439
594
|
it('should auto-resolve mixed: some in stack, some new', () => {
|
|
440
595
|
const appDefinition = {
|
|
441
596
|
vpc: { ownership: { vpcEndpoints: 'auto' } },
|
|
442
|
-
encryption: { fieldLevelEncryptionMethod: 'kms' } // Enable KMS endpoint
|
|
597
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' }, // Enable KMS endpoint
|
|
598
|
+
database: { dynamodb: { enable: true } } // Enable DynamoDB
|
|
443
599
|
};
|
|
444
600
|
const discovery = {
|
|
445
601
|
stackManaged: [
|
|
@@ -536,7 +692,11 @@ describe('VpcResourceResolver', () => {
|
|
|
536
692
|
describe('real-world scenarios', () => {
|
|
537
693
|
it('scenario: fresh deploy, no resources exist', () => {
|
|
538
694
|
const appDefinition = {
|
|
539
|
-
vpc: {
|
|
695
|
+
vpc: {
|
|
696
|
+
enable: true,
|
|
697
|
+
ownership: {},
|
|
698
|
+
management: 'create-new' // Explicitly allow VPC creation
|
|
699
|
+
}
|
|
540
700
|
};
|
|
541
701
|
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
542
702
|
|
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.490.
|
|
4
|
+
"version": "2.0.0--canary.490.a308628.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"@babel/eslint-parser": "^7.18.9",
|
|
17
17
|
"@babel/parser": "^7.25.3",
|
|
18
18
|
"@babel/traverse": "^7.25.3",
|
|
19
|
-
"@friggframework/core": "2.0.0--canary.490.
|
|
20
|
-
"@friggframework/schemas": "2.0.0--canary.490.
|
|
21
|
-
"@friggframework/test": "2.0.0--canary.490.
|
|
19
|
+
"@friggframework/core": "2.0.0--canary.490.a308628.0",
|
|
20
|
+
"@friggframework/schemas": "2.0.0--canary.490.a308628.0",
|
|
21
|
+
"@friggframework/test": "2.0.0--canary.490.a308628.0",
|
|
22
22
|
"@hapi/boom": "^10.0.1",
|
|
23
23
|
"@inquirer/prompts": "^5.3.8",
|
|
24
24
|
"axios": "^1.7.2",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"validate-npm-package-name": "^5.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@friggframework/eslint-config": "2.0.0--canary.490.
|
|
50
|
-
"@friggframework/prettier-config": "2.0.0--canary.490.
|
|
49
|
+
"@friggframework/eslint-config": "2.0.0--canary.490.a308628.0",
|
|
50
|
+
"@friggframework/prettier-config": "2.0.0--canary.490.a308628.0",
|
|
51
51
|
"aws-sdk-client-mock": "^4.1.0",
|
|
52
52
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
53
53
|
"jest": "^30.1.3",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "a308628470332edb561e569dc860fcc8f20b83ff"
|
|
83
83
|
}
|