@friggframework/devtools 2.0.0--canary.461.849e166.0 → 2.0.0--canary.474.aa465e4.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/ARCHITECTURE.md +487 -0
- package/infrastructure/domains/database/aurora-builder.js +234 -57
- package/infrastructure/domains/database/aurora-builder.test.js +7 -2
- package/infrastructure/domains/database/aurora-resolver.js +210 -0
- package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
- package/infrastructure/domains/database/migration-builder.js +256 -215
- package/infrastructure/domains/database/migration-builder.test.js +5 -111
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/integration/integration-builder.js +258 -84
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/networking/vpc-builder.js +856 -135
- package/infrastructure/domains/networking/vpc-builder.test.js +10 -6
- package/infrastructure/domains/networking/vpc-resolver.js +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
- package/infrastructure/domains/security/kms-builder.js +179 -22
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +26 -1
- package/infrastructure/domains/shared/types/app-definition.js +205 -0
- package/infrastructure/domains/shared/types/discovery-result.js +106 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
- package/infrastructure/domains/shared/types/index.js +46 -0
- package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
- package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
- package/package.json +6 -6
- package/infrastructure/REFACTOR.md +0 -532
- package/infrastructure/TRANSFORMATION-VISUAL.md +0 -239
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aurora Resource Resolver Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the ownership resolution logic for Aurora resources.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const AuroraResourceResolver = require('./aurora-resolver');
|
|
8
|
+
const { ResourceOwnership } = require('../shared/types/resource-ownership');
|
|
9
|
+
|
|
10
|
+
describe('AuroraResourceResolver', () => {
|
|
11
|
+
let resolver;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
resolver = new AuroraResourceResolver();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('resolveCluster', () => {
|
|
18
|
+
it('should resolve to EXTERNAL with user-provided cluster identifier', () => {
|
|
19
|
+
const appDefinition = {
|
|
20
|
+
database: {
|
|
21
|
+
postgres: {
|
|
22
|
+
ownership: { cluster: 'external' },
|
|
23
|
+
external: { clusterIdentifier: 'prod-aurora-cluster' }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
28
|
+
|
|
29
|
+
const decision = resolver.resolveCluster(appDefinition, discovery);
|
|
30
|
+
|
|
31
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
32
|
+
expect(decision.physicalId).toBe('prod-aurora-cluster');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should resolve to STACK when cluster found in stack', () => {
|
|
36
|
+
const appDefinition = { database: { postgres: { ownership: { cluster: 'auto' } } } };
|
|
37
|
+
const discovery = {
|
|
38
|
+
stackManaged: [
|
|
39
|
+
{ logicalId: 'FriggAuroraCluster', physicalId: 'frigg-cluster-prod', resourceType: 'AWS::RDS::DBCluster' }
|
|
40
|
+
],
|
|
41
|
+
external: [],
|
|
42
|
+
fromCloudFormation: true
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const decision = resolver.resolveCluster(appDefinition, discovery);
|
|
46
|
+
|
|
47
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
48
|
+
expect(decision.physicalId).toBe('frigg-cluster-prod');
|
|
49
|
+
expect(decision.reason).toContain('Found FriggAuroraCluster in CloudFormation stack');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should auto-resolve to EXTERNAL when cluster found externally', () => {
|
|
53
|
+
const appDefinition = { database: { postgres: { ownership: { cluster: 'auto' } } } };
|
|
54
|
+
const discovery = {
|
|
55
|
+
stackManaged: [],
|
|
56
|
+
external: [
|
|
57
|
+
{ physicalId: 'shared-aurora-cluster', resourceType: 'AWS::RDS::DBCluster', source: 'aws-discovery' }
|
|
58
|
+
],
|
|
59
|
+
fromCloudFormation: false
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const decision = resolver.resolveCluster(appDefinition, discovery);
|
|
63
|
+
|
|
64
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
65
|
+
expect(decision.physicalId).toBe('shared-aurora-cluster');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should auto-resolve to STACK when not found (create new)', () => {
|
|
69
|
+
const appDefinition = { database: { postgres: { ownership: { cluster: 'auto' } } } };
|
|
70
|
+
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
71
|
+
|
|
72
|
+
const decision = resolver.resolveCluster(appDefinition, discovery);
|
|
73
|
+
|
|
74
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
75
|
+
expect(decision.physicalId).toBeFalsy(); // null or undefined
|
|
76
|
+
expect(decision.reason).toContain('No existing Aurora cluster');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('resolveInstance', () => {
|
|
81
|
+
it('should resolve to EXTERNAL with user-provided instance identifier', () => {
|
|
82
|
+
const appDefinition = {
|
|
83
|
+
database: {
|
|
84
|
+
postgres: {
|
|
85
|
+
ownership: { instance: 'external' },
|
|
86
|
+
external: { instanceIdentifier: 'prod-aurora-instance-1' }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
91
|
+
|
|
92
|
+
const decision = resolver.resolveInstance(appDefinition, discovery);
|
|
93
|
+
|
|
94
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
95
|
+
expect(decision.physicalId).toBe('prod-aurora-instance-1');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should resolve to STACK when instance found in stack', () => {
|
|
99
|
+
const appDefinition = { database: { postgres: { ownership: { instance: 'auto' } } } };
|
|
100
|
+
const discovery = {
|
|
101
|
+
stackManaged: [
|
|
102
|
+
{ logicalId: 'FriggAuroraInstance', physicalId: 'frigg-instance-1', resourceType: 'AWS::RDS::DBInstance' }
|
|
103
|
+
],
|
|
104
|
+
external: [],
|
|
105
|
+
fromCloudFormation: true
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const decision = resolver.resolveInstance(appDefinition, discovery);
|
|
109
|
+
|
|
110
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
111
|
+
expect(decision.physicalId).toBe('frigg-instance-1');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('resolveSubnetGroup', () => {
|
|
116
|
+
it('should resolve to EXTERNAL with user-provided subnet group name', () => {
|
|
117
|
+
const appDefinition = {
|
|
118
|
+
database: {
|
|
119
|
+
postgres: {
|
|
120
|
+
ownership: { subnetGroup: 'external' },
|
|
121
|
+
external: { subnetGroupName: 'prod-db-subnet-group' }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
126
|
+
|
|
127
|
+
const decision = resolver.resolveSubnetGroup(appDefinition, discovery);
|
|
128
|
+
|
|
129
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
130
|
+
expect(decision.physicalId).toBe('prod-db-subnet-group');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should resolve to STACK when subnet group found in stack', () => {
|
|
134
|
+
const appDefinition = { database: { postgres: { ownership: { subnetGroup: 'auto' } } } };
|
|
135
|
+
const discovery = {
|
|
136
|
+
stackManaged: [
|
|
137
|
+
{ logicalId: 'FriggDBSubnetGroup', physicalId: 'frigg-db-subnet-group', resourceType: 'AWS::RDS::DBSubnetGroup' }
|
|
138
|
+
],
|
|
139
|
+
external: [],
|
|
140
|
+
fromCloudFormation: true
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const decision = resolver.resolveSubnetGroup(appDefinition, discovery);
|
|
144
|
+
|
|
145
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
146
|
+
expect(decision.physicalId).toBe('frigg-db-subnet-group');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should always create subnet group for new deployments', () => {
|
|
150
|
+
const appDefinition = { database: { postgres: { ownership: { subnetGroup: 'auto' } } } };
|
|
151
|
+
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
152
|
+
|
|
153
|
+
const decision = resolver.resolveSubnetGroup(appDefinition, discovery);
|
|
154
|
+
|
|
155
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
156
|
+
expect(decision.physicalId).toBeFalsy(); // null or undefined
|
|
157
|
+
expect(decision.reason).toContain('No existing DB subnet group');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('resolveSecret', () => {
|
|
162
|
+
it('should resolve to EXTERNAL with user-provided secret ARN', () => {
|
|
163
|
+
const appDefinition = {
|
|
164
|
+
database: {
|
|
165
|
+
postgres: {
|
|
166
|
+
ownership: { secret: 'external' },
|
|
167
|
+
external: { secretArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:prod-db-creds' }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const discovery = { stackManaged: [], external: [], fromCloudFormation: false };
|
|
172
|
+
|
|
173
|
+
const decision = resolver.resolveSecret(appDefinition, discovery);
|
|
174
|
+
|
|
175
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
176
|
+
expect(decision.physicalId).toBe('arn:aws:secretsmanager:us-east-1:123456789012:secret:prod-db-creds');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should resolve to STACK when secret found in stack', () => {
|
|
180
|
+
const appDefinition = { database: { postgres: { ownership: { secret: 'auto' } } } };
|
|
181
|
+
const discovery = {
|
|
182
|
+
stackManaged: [
|
|
183
|
+
{ logicalId: 'FriggDBSecret', physicalId: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:frigg-db', resourceType: 'AWS::SecretsManager::Secret' }
|
|
184
|
+
],
|
|
185
|
+
external: [],
|
|
186
|
+
fromCloudFormation: true
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const decision = resolver.resolveSecret(appDefinition, discovery);
|
|
190
|
+
|
|
191
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
192
|
+
expect(decision.physicalId).toBe('arn:aws:secretsmanager:us-east-1:123456789012:secret:frigg-db');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('resolveAll', () => {
|
|
197
|
+
it('should resolve all Aurora resources at once', () => {
|
|
198
|
+
const appDefinition = {
|
|
199
|
+
database: {
|
|
200
|
+
postgres: {
|
|
201
|
+
enable: true,
|
|
202
|
+
ownership: {}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const discovery = {
|
|
207
|
+
stackManaged: [],
|
|
208
|
+
external: [],
|
|
209
|
+
fromCloudFormation: false
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const decisions = resolver.resolveAll(appDefinition, discovery);
|
|
213
|
+
|
|
214
|
+
expect(decisions.cluster).toBeDefined();
|
|
215
|
+
expect(decisions.instance).toBeDefined();
|
|
216
|
+
expect(decisions.subnetGroup).toBeDefined();
|
|
217
|
+
expect(decisions.secret).toBeDefined();
|
|
218
|
+
|
|
219
|
+
// All should be STACK (create new)
|
|
220
|
+
expect(decisions.cluster.ownership).toBe(ResourceOwnership.STACK);
|
|
221
|
+
expect(decisions.instance.ownership).toBe(ResourceOwnership.STACK);
|
|
222
|
+
expect(decisions.subnetGroup.ownership).toBe(ResourceOwnership.STACK);
|
|
223
|
+
expect(decisions.secret.ownership).toBe(ResourceOwnership.STACK);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should handle mixed ownership scenarios', () => {
|
|
227
|
+
const appDefinition = {
|
|
228
|
+
database: {
|
|
229
|
+
postgres: {
|
|
230
|
+
ownership: {
|
|
231
|
+
cluster: 'external',
|
|
232
|
+
instance: 'auto',
|
|
233
|
+
subnetGroup: 'stack',
|
|
234
|
+
secret: 'stack'
|
|
235
|
+
},
|
|
236
|
+
external: {
|
|
237
|
+
clusterIdentifier: 'shared-cluster'
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const discovery = {
|
|
243
|
+
stackManaged: [
|
|
244
|
+
{ logicalId: 'FriggDBSubnetGroup', physicalId: 'subnet-group-1', resourceType: 'AWS::RDS::DBSubnetGroup' },
|
|
245
|
+
{ logicalId: 'FriggDBSecret', physicalId: 'arn:aws:secret-1', resourceType: 'AWS::SecretsManager::Secret' }
|
|
246
|
+
],
|
|
247
|
+
external: [],
|
|
248
|
+
fromCloudFormation: true
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const decisions = resolver.resolveAll(appDefinition, discovery);
|
|
252
|
+
|
|
253
|
+
expect(decisions.cluster.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
254
|
+
expect(decisions.cluster.physicalId).toBe('shared-cluster');
|
|
255
|
+
expect(decisions.instance.ownership).toBe(ResourceOwnership.STACK); // Not found, create new
|
|
256
|
+
expect(decisions.subnetGroup.ownership).toBe(ResourceOwnership.STACK);
|
|
257
|
+
expect(decisions.subnetGroup.physicalId).toBe('subnet-group-1');
|
|
258
|
+
expect(decisions.secret.ownership).toBe(ResourceOwnership.STACK);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('real-world scenarios', () => {
|
|
263
|
+
it('scenario: fresh deploy, no Aurora exists', () => {
|
|
264
|
+
const appDefinition = {
|
|
265
|
+
database: { postgres: { enable: true, ownership: {} } }
|
|
266
|
+
};
|
|
267
|
+
const discovery = {
|
|
268
|
+
stackManaged: [],
|
|
269
|
+
external: [],
|
|
270
|
+
fromCloudFormation: false
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const decisions = resolver.resolveAll(appDefinition, discovery);
|
|
274
|
+
|
|
275
|
+
// All resources should be created in stack
|
|
276
|
+
expect(decisions.cluster.ownership).toBe(ResourceOwnership.STACK);
|
|
277
|
+
expect(decisions.cluster.physicalId).toBeFalsy(); // null or undefined
|
|
278
|
+
expect(decisions.instance.ownership).toBe(ResourceOwnership.STACK);
|
|
279
|
+
expect(decisions.subnetGroup.ownership).toBe(ResourceOwnership.STACK);
|
|
280
|
+
expect(decisions.secret.ownership).toBe(ResourceOwnership.STACK);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('scenario: redeploy existing stack with Aurora', () => {
|
|
284
|
+
const appDefinition = {
|
|
285
|
+
database: { postgres: { enable: true, ownership: {} } }
|
|
286
|
+
};
|
|
287
|
+
const discovery = {
|
|
288
|
+
stackManaged: [
|
|
289
|
+
{ logicalId: 'FriggAuroraCluster', physicalId: 'cluster-1', resourceType: 'AWS::RDS::DBCluster' },
|
|
290
|
+
{ logicalId: 'FriggAuroraInstance', physicalId: 'instance-1', resourceType: 'AWS::RDS::DBInstance' },
|
|
291
|
+
{ logicalId: 'FriggDBSubnetGroup', physicalId: 'subnet-group-1', resourceType: 'AWS::RDS::DBSubnetGroup' },
|
|
292
|
+
{ logicalId: 'FriggDBSecret', physicalId: 'arn:aws:secret-1', resourceType: 'AWS::SecretsManager::Secret' }
|
|
293
|
+
],
|
|
294
|
+
external: [],
|
|
295
|
+
fromCloudFormation: true,
|
|
296
|
+
stackName: 'frigg-production'
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const decisions = resolver.resolveAll(appDefinition, discovery);
|
|
300
|
+
|
|
301
|
+
// All resources in stack, should reuse with STACK ownership
|
|
302
|
+
expect(decisions.cluster.ownership).toBe(ResourceOwnership.STACK);
|
|
303
|
+
expect(decisions.cluster.physicalId).toBe('cluster-1');
|
|
304
|
+
expect(decisions.instance.ownership).toBe(ResourceOwnership.STACK);
|
|
305
|
+
expect(decisions.instance.physicalId).toBe('instance-1');
|
|
306
|
+
expect(decisions.subnetGroup.ownership).toBe(ResourceOwnership.STACK);
|
|
307
|
+
expect(decisions.secret.ownership).toBe(ResourceOwnership.STACK);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('scenario: use shared Aurora cluster with new stack resources', () => {
|
|
311
|
+
const appDefinition = {
|
|
312
|
+
database: {
|
|
313
|
+
postgres: {
|
|
314
|
+
enable: true,
|
|
315
|
+
ownership: {
|
|
316
|
+
cluster: 'external',
|
|
317
|
+
instance: 'external',
|
|
318
|
+
subnetGroup: 'auto',
|
|
319
|
+
secret: 'auto'
|
|
320
|
+
},
|
|
321
|
+
external: {
|
|
322
|
+
clusterIdentifier: 'shared-production-aurora',
|
|
323
|
+
instanceIdentifier: 'shared-production-aurora-instance-1'
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
const discovery = {
|
|
329
|
+
stackManaged: [],
|
|
330
|
+
external: [],
|
|
331
|
+
fromCloudFormation: false
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const decisions = resolver.resolveAll(appDefinition, discovery);
|
|
335
|
+
|
|
336
|
+
// Cluster and instance are external
|
|
337
|
+
expect(decisions.cluster.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
338
|
+
expect(decisions.cluster.physicalId).toBe('shared-production-aurora');
|
|
339
|
+
expect(decisions.instance.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
340
|
+
expect(decisions.instance.physicalId).toBe('shared-production-aurora-instance-1');
|
|
341
|
+
|
|
342
|
+
// Subnet group and secret are created in our stack
|
|
343
|
+
expect(decisions.subnetGroup.ownership).toBe(ResourceOwnership.STACK);
|
|
344
|
+
expect(decisions.secret.ownership).toBe(ResourceOwnership.STACK);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|