@friggframework/devtools 2.0.0--canary.461.5767fa4.0 → 2.0.0--canary.461.0a68e4c.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/domains/database/migration-builder.js +1 -0
- package/infrastructure/domains/database/migration-builder.test.js +3 -0
- package/infrastructure/domains/networking/vpc-builder.js +44 -9
- package/infrastructure/domains/networking/vpc-builder.test.js +87 -0
- package/infrastructure/domains/shared/resource-discovery.js +3 -3
- package/infrastructure/domains/shared/resource-discovery.test.js +2 -2
- package/package.json +6 -6
|
@@ -288,6 +288,7 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
288
288
|
// Note: Serverless will merge this with provider.environment
|
|
289
289
|
},
|
|
290
290
|
events: [
|
|
291
|
+
{ httpApi: { path: '/db-migrate/status', method: 'GET' } },
|
|
291
292
|
{ httpApi: { path: '/db-migrate', method: 'POST' } },
|
|
292
293
|
{ httpApi: { path: '/db-migrate/{processId}', method: 'GET' } },
|
|
293
294
|
],
|
|
@@ -164,6 +164,9 @@ describe('MigrationBuilder', () => {
|
|
|
164
164
|
'node_modules/@friggframework/core/handlers/routers/db-migration.handler'
|
|
165
165
|
);
|
|
166
166
|
expect(result.functions.dbMigrationRouter.timeout).toBe(30);
|
|
167
|
+
expect(result.functions.dbMigrationRouter.events).toContainEqual({
|
|
168
|
+
httpApi: { path: '/db-migrate/status', method: 'GET' },
|
|
169
|
+
});
|
|
167
170
|
expect(result.functions.dbMigrationRouter.events).toContainEqual({
|
|
168
171
|
httpApi: { path: '/db-migrate', method: 'POST' },
|
|
169
172
|
});
|
|
@@ -463,8 +463,8 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
463
463
|
|
|
464
464
|
const subnetVpcId = vpcManagement === 'create-new' ? { Ref: 'FriggVPC' } : result.vpcId;
|
|
465
465
|
|
|
466
|
-
// Generate CIDRs
|
|
467
|
-
const cidrs = this.generateSubnetCidrs(vpcManagement);
|
|
466
|
+
// Generate CIDRs - pass discovered resources to avoid conflicts
|
|
467
|
+
const cidrs = this.generateSubnetCidrs(vpcManagement, discoveredResources);
|
|
468
468
|
|
|
469
469
|
// Private Subnet 1
|
|
470
470
|
result.resources.FriggPrivateSubnet1 = {
|
|
@@ -597,8 +597,9 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
597
597
|
|
|
598
598
|
/**
|
|
599
599
|
* Generate subnet CIDR blocks
|
|
600
|
+
* Finds available CIDRs that don't conflict with existing subnets
|
|
600
601
|
*/
|
|
601
|
-
generateSubnetCidrs(vpcManagement) {
|
|
602
|
+
generateSubnetCidrs(vpcManagement, discoveredResources) {
|
|
602
603
|
if (vpcManagement === 'create-new') {
|
|
603
604
|
// Use CloudFormation Fn::Cidr for dynamic generation
|
|
604
605
|
return {
|
|
@@ -608,13 +609,47 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
608
609
|
public2: { 'Fn::Select': [3, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }] },
|
|
609
610
|
};
|
|
610
611
|
} else {
|
|
611
|
-
//
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
612
|
+
// Find available CIDRs for existing VPC by checking existing subnets
|
|
613
|
+
const existingCidrs = new Set();
|
|
614
|
+
|
|
615
|
+
// Collect all existing subnet CIDRs
|
|
616
|
+
if (discoveredResources?.subnets) {
|
|
617
|
+
for (const subnet of discoveredResources.subnets) {
|
|
618
|
+
if (subnet.CidrBlock) {
|
|
619
|
+
existingCidrs.add(subnet.CidrBlock);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
console.log(` Found ${existingCidrs.size} existing subnet CIDRs in VPC`);
|
|
625
|
+
|
|
626
|
+
// Generate candidates in the default VPC range (172.31.0.0/16)
|
|
627
|
+
// Private subnets: 240-249, Public subnets: 250-255
|
|
628
|
+
const findAvailableCidr = (startOctet, endOctet) => {
|
|
629
|
+
for (let octet = startOctet; octet <= endOctet; octet++) {
|
|
630
|
+
const candidate = `172.31.${octet}.0/24`;
|
|
631
|
+
if (!existingCidrs.has(candidate)) {
|
|
632
|
+
existingCidrs.add(candidate); // Mark as used immediately
|
|
633
|
+
return candidate;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// Fallback if range exhausted
|
|
637
|
+
return `172.31.${startOctet}.0/24`;
|
|
617
638
|
};
|
|
639
|
+
|
|
640
|
+
const privateRange = { start: 240, end: 249 };
|
|
641
|
+
const publicRange = { start: 250, end: 255 };
|
|
642
|
+
|
|
643
|
+
const cidrs = {
|
|
644
|
+
private1: findAvailableCidr(privateRange.start, privateRange.end),
|
|
645
|
+
private2: findAvailableCidr(privateRange.start, privateRange.end),
|
|
646
|
+
public1: findAvailableCidr(publicRange.start, publicRange.end),
|
|
647
|
+
public2: findAvailableCidr(publicRange.start, publicRange.end),
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
console.log(` Using available CIDRs: ${Object.values(cidrs).join(', ')}`);
|
|
651
|
+
|
|
652
|
+
return cidrs;
|
|
618
653
|
}
|
|
619
654
|
}
|
|
620
655
|
|
|
@@ -983,6 +983,93 @@ describe('VpcBuilder', () => {
|
|
|
983
983
|
});
|
|
984
984
|
});
|
|
985
985
|
|
|
986
|
+
describe('generateSubnetCidrs()', () => {
|
|
987
|
+
it('should use CloudFormation Fn::Cidr for create-new mode', () => {
|
|
988
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('create-new', {});
|
|
989
|
+
|
|
990
|
+
expect(cidrs.private1).toEqual({
|
|
991
|
+
'Fn::Select': [0, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
992
|
+
});
|
|
993
|
+
expect(cidrs.private2).toEqual({
|
|
994
|
+
'Fn::Select': [1, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
995
|
+
});
|
|
996
|
+
expect(cidrs.public1).toEqual({
|
|
997
|
+
'Fn::Select': [2, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
998
|
+
});
|
|
999
|
+
expect(cidrs.public2).toEqual({
|
|
1000
|
+
'Fn::Select': [3, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
it('should use default static CIDRs when no existing subnets in VPC', () => {
|
|
1005
|
+
const discoveredResources = {
|
|
1006
|
+
subnets: []
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1010
|
+
|
|
1011
|
+
expect(cidrs.private1).toBe('172.31.240.0/24');
|
|
1012
|
+
expect(cidrs.private2).toBe('172.31.241.0/24');
|
|
1013
|
+
expect(cidrs.public1).toBe('172.31.250.0/24');
|
|
1014
|
+
expect(cidrs.public2).toBe('172.31.251.0/24');
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
it('should avoid CIDR conflicts with existing subnets', () => {
|
|
1018
|
+
const discoveredResources = {
|
|
1019
|
+
subnets: [
|
|
1020
|
+
{ CidrBlock: '172.31.240.0/24' }, // Conflicts with default private1
|
|
1021
|
+
{ CidrBlock: '172.31.241.0/24' }, // Conflicts with default private2
|
|
1022
|
+
{ CidrBlock: '172.31.0.0/20' }, // Default VPC subnet
|
|
1023
|
+
{ CidrBlock: '172.31.16.0/20' }, // Default VPC subnet
|
|
1024
|
+
]
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1028
|
+
|
|
1029
|
+
// Should skip 240 and 241 (already taken), use 242-243 for private, 250-251 for public
|
|
1030
|
+
expect(cidrs.private1).toBe('172.31.242.0/24');
|
|
1031
|
+
expect(cidrs.private2).toBe('172.31.243.0/24');
|
|
1032
|
+
expect(cidrs.public1).toBe('172.31.250.0/24'); // Public range starts at 250
|
|
1033
|
+
expect(cidrs.public2).toBe('172.31.251.0/24');
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
it('should find first available CIDR blocks when some in range are taken', () => {
|
|
1037
|
+
const discoveredResources = {
|
|
1038
|
+
subnets: [
|
|
1039
|
+
{ CidrBlock: '172.31.240.0/24' },
|
|
1040
|
+
{ CidrBlock: '172.31.242.0/24' },
|
|
1041
|
+
{ CidrBlock: '172.31.244.0/24' },
|
|
1042
|
+
]
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1046
|
+
|
|
1047
|
+
// Should use 241, 243 for private (filling gaps), 250, 251 for public
|
|
1048
|
+
expect(cidrs.private1).toBe('172.31.241.0/24');
|
|
1049
|
+
expect(cidrs.private2).toBe('172.31.243.0/24');
|
|
1050
|
+
expect(cidrs.public1).toBe('172.31.250.0/24'); // Public range starts at 250
|
|
1051
|
+
expect(cidrs.public2).toBe('172.31.251.0/24');
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
it('should handle missing discoveredResources gracefully', () => {
|
|
1055
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', null);
|
|
1056
|
+
|
|
1057
|
+
// Should fallback to default CIDRs
|
|
1058
|
+
expect(cidrs.private1).toBe('172.31.240.0/24');
|
|
1059
|
+
expect(cidrs.private2).toBe('172.31.241.0/24');
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
it('should handle discoveredResources without subnets array', () => {
|
|
1063
|
+
const discoveredResources = { vpcId: 'vpc-123' };
|
|
1064
|
+
|
|
1065
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1066
|
+
|
|
1067
|
+
// Should fallback to default CIDRs
|
|
1068
|
+
expect(cidrs.private1).toBe('172.31.240.0/24');
|
|
1069
|
+
expect(cidrs.private2).toBe('172.31.241.0/24');
|
|
1070
|
+
});
|
|
1071
|
+
});
|
|
1072
|
+
|
|
986
1073
|
describe('Outputs', () => {
|
|
987
1074
|
it.skip('should generate VPC ID output', async () => {
|
|
988
1075
|
const appDefinition = {
|
|
@@ -94,17 +94,17 @@ async function gatherDiscoveredResources(appDefinition) {
|
|
|
94
94
|
// But still discover KMS (encryption keys can be safely shared across stages)
|
|
95
95
|
if (appDefinition.managementMode === 'managed' && appDefinition.vpcIsolation === 'isolated') {
|
|
96
96
|
console.log(' ℹ Isolated mode: discovering KMS (shareable) but not VPC/Aurora (isolated)');
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
// Still run KMS discovery - encryption keys are safe to share
|
|
99
99
|
const kmsDiscovery = new KmsDiscovery(provider);
|
|
100
100
|
const kmsResult = await kmsDiscovery.discover();
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
if (kmsResult?.defaultKmsKeyId) {
|
|
103
103
|
console.log(' ✓ Found shared KMS key (can be reused across stages)');
|
|
104
104
|
console.log('✅ Cloud resource discovery completed successfully!');
|
|
105
105
|
return kmsResult;
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
console.log(' ℹ No existing resources found - will create fresh infrastructure');
|
|
109
109
|
console.log('✅ Cloud resource discovery completed successfully!');
|
|
110
110
|
return {};
|
|
@@ -427,7 +427,7 @@ describe('Resource Discovery', () => {
|
|
|
427
427
|
};
|
|
428
428
|
|
|
429
429
|
process.env.SLS_STAGE = 'dev';
|
|
430
|
-
|
|
430
|
+
|
|
431
431
|
// Mock KMS discovery returning a shared key
|
|
432
432
|
mockKmsDiscovery.discover.mockResolvedValue({
|
|
433
433
|
defaultKmsKeyId: 'shared-kms-key-123',
|
|
@@ -462,7 +462,7 @@ describe('Resource Discovery', () => {
|
|
|
462
462
|
};
|
|
463
463
|
|
|
464
464
|
process.env.SLS_STAGE = 'dev';
|
|
465
|
-
|
|
465
|
+
|
|
466
466
|
// Mock KMS discovery finding nothing
|
|
467
467
|
mockKmsDiscovery.discover.mockResolvedValue({});
|
|
468
468
|
|
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.461.
|
|
4
|
+
"version": "2.0.0--canary.461.0a68e4c.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@babel/eslint-parser": "^7.18.9",
|
|
12
12
|
"@babel/parser": "^7.25.3",
|
|
13
13
|
"@babel/traverse": "^7.25.3",
|
|
14
|
-
"@friggframework/schemas": "2.0.0--canary.461.
|
|
15
|
-
"@friggframework/test": "2.0.0--canary.461.
|
|
14
|
+
"@friggframework/schemas": "2.0.0--canary.461.0a68e4c.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.461.0a68e4c.0",
|
|
16
16
|
"@hapi/boom": "^10.0.1",
|
|
17
17
|
"@inquirer/prompts": "^5.3.8",
|
|
18
18
|
"axios": "^1.7.2",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"serverless-http": "^2.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@friggframework/eslint-config": "2.0.0--canary.461.
|
|
38
|
-
"@friggframework/prettier-config": "2.0.0--canary.461.
|
|
37
|
+
"@friggframework/eslint-config": "2.0.0--canary.461.0a68e4c.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.0a68e4c.0",
|
|
39
39
|
"aws-sdk-client-mock": "^4.1.0",
|
|
40
40
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
41
41
|
"jest": "^30.1.3",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "0a68e4cd99db73582144693112740ff3786d8e93"
|
|
74
74
|
}
|