@friggframework/devtools 2.0.0--canary.490.a6abe40.0 → 2.0.0--canary.490.36b3031.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.
@@ -577,11 +577,10 @@ class VpcBuilder extends InfrastructureBuilder {
577
577
  * Build VPC based on ownership decision
578
578
  *
579
579
  * For STACK ownership: ALWAYS add definitions to template.
580
- * CloudFormation idempotency ensures existing resources aren't recreated.
581
580
  */
582
581
  buildVpcFromDecision(decision, appDefinition, result) {
583
582
  if (decision.ownership === ResourceOwnership.STACK) {
584
- // For STACK ownership: ALWAYS create definitions (CloudFormation idempotency)
583
+ // For STACK ownership: ALWAYS create definitions
585
584
  if (decision.physicalId) {
586
585
  console.log(` → Adding VPC definition to template (existing: ${decision.physicalId})`);
587
586
  } else {
@@ -1348,6 +1348,105 @@ describe('VpcBuilder', () => {
1348
1348
  });
1349
1349
  });
1350
1350
 
1351
+ describe('Full Frontify deployment pattern integration test', () => {
1352
+ it('should correctly handle Frontify production scenario: external VPC + stack routing', async () => {
1353
+ // This test replicates the EXACT Frontify production deployment scenario
1354
+ const appDefinition = {
1355
+ vpc: { enable: true },
1356
+ encryption: { fieldLevelEncryptionMethod: 'kms' },
1357
+ };
1358
+
1359
+ // Actual Frontify discovery results (from production logs)
1360
+ const discoveredResources = {
1361
+ fromCloudFormationStack: true,
1362
+ stackName: 'create-frigg-app-production',
1363
+ existingLogicalIds: [
1364
+ 'FriggLambdaSecurityGroup',
1365
+ 'FriggLambdaRouteTable',
1366
+ 'FriggPrivateRoute',
1367
+ 'FriggPrivateSubnet1RouteTableAssociation',
1368
+ 'FriggPrivateSubnet2RouteTableAssociation',
1369
+ 'FriggS3VPCEndpoint',
1370
+ 'FriggDynamoDBVPCEndpoint',
1371
+ 'FriggKMSVPCEndpoint'
1372
+ ],
1373
+ // Stack resources (from CloudFormation)
1374
+ lambdaSecurityGroupId: 'sg-01002240c6a446202',
1375
+ routeTableId: 'rtb-08af43bbf0775602d',
1376
+ s3VpcEndpointId: 'vpce-0d1ecb2c53ce9b4b8',
1377
+ dynamodbVpcEndpointId: 'vpce-0fb749b207f1020b0',
1378
+ kmsVpcEndpointId: 'vpce-0e38c25155b86de22',
1379
+ // External resources (discovered via queries)
1380
+ defaultVpcId: 'vpc-0cd17c0e06cb28b28',
1381
+ privateSubnetId1: 'subnet-034f6562dbbc16348',
1382
+ privateSubnetId2: 'subnet-0b8be2b82aeb5cdec',
1383
+ existingNatGatewayId: 'nat-022660c36a47e2d79'
1384
+ };
1385
+
1386
+ const result = await vpcBuilder.build(appDefinition, discoveredResources);
1387
+
1388
+ // === ASSERTIONS: Template Structure ===
1389
+
1390
+ // 1. VPC should be external (not in template)
1391
+ expect(result.resources.FriggVPC).toBeUndefined();
1392
+ expect(result.vpcId).toBe('vpc-0cd17c0e06cb28b28');
1393
+
1394
+ // 2. Security Group MUST be in template (stack-managed)
1395
+ expect(result.resources.FriggLambdaSecurityGroup).toBeDefined();
1396
+ expect(result.resources.FriggLambdaSecurityGroup.Type).toBe('AWS::EC2::SecurityGroup');
1397
+ expect(result.vpcConfig.securityGroupIds).toEqual([{ Ref: 'FriggLambdaSecurityGroup' }]);
1398
+
1399
+ // 3. Subnets should be external (use hardcoded IDs, not in template)
1400
+ expect(result.resources.FriggPrivateSubnet1).toBeUndefined();
1401
+ expect(result.resources.FriggPrivateSubnet2).toBeUndefined();
1402
+ expect(result.vpcConfig.subnetIds).toEqual([
1403
+ 'subnet-034f6562dbbc16348',
1404
+ 'subnet-0b8be2b82aeb5cdec'
1405
+ ]);
1406
+
1407
+ // 4. NAT Gateway should be external (not in template)
1408
+ expect(result.resources.FriggNATGateway).toBeUndefined();
1409
+ expect(result.resources.FriggNATGatewayEIP).toBeUndefined();
1410
+ expect(result.natGatewayId).toBe('nat-022660c36a47e2d79');
1411
+
1412
+ // 5. Route table MUST be in template (stack-managed)
1413
+ expect(result.resources.FriggLambdaRouteTable).toBeDefined();
1414
+ expect(result.resources.FriggLambdaRouteTable.Type).toBe('AWS::EC2::RouteTable');
1415
+
1416
+ // 6. Route table associations MUST be in template
1417
+ expect(result.resources.FriggPrivateSubnet1RouteTableAssociation).toBeDefined();
1418
+ expect(result.resources.FriggPrivateSubnet2RouteTableAssociation).toBeDefined();
1419
+
1420
+ // 7. VPC Endpoints MUST be in template (stack-managed, prevents deletion)
1421
+ expect(result.resources.FriggS3VPCEndpoint).toBeDefined();
1422
+ expect(result.resources.FriggS3VPCEndpoint.Properties.VpcEndpointType).toBe('Gateway');
1423
+
1424
+ expect(result.resources.FriggDynamoDBVPCEndpoint).toBeDefined();
1425
+ expect(result.resources.FriggDynamoDBVPCEndpoint.Properties.VpcEndpointType).toBe('Gateway');
1426
+
1427
+ expect(result.resources.FriggKMSVPCEndpoint).toBeDefined();
1428
+ expect(result.resources.FriggKMSVPCEndpoint.Properties.VpcEndpointType).toBe('Interface');
1429
+
1430
+ // 8. VPC Endpoint Security Group needed for interface endpoints
1431
+ expect(result.resources.FriggVPCEndpointSecurityGroup).toBeDefined();
1432
+
1433
+ // === ASSERTIONS: Resource Count ===
1434
+ const resourceKeys = Object.keys(result.resources);
1435
+ const friggResources = resourceKeys.filter(k => k.startsWith('Frigg') || k.startsWith('VPC'));
1436
+
1437
+ // Should have routing infrastructure + endpoints + security groups
1438
+ // NOT full VPC (no FriggVPC, FriggPrivateSubnet1/2, FriggNATGateway)
1439
+ expect(friggResources).toContain('FriggLambdaSecurityGroup');
1440
+ expect(friggResources).toContain('FriggLambdaRouteTable');
1441
+ expect(friggResources).toContain('FriggS3VPCEndpoint');
1442
+ expect(friggResources).toContain('FriggDynamoDBVPCEndpoint');
1443
+ expect(friggResources).toContain('FriggKMSVPCEndpoint');
1444
+ expect(friggResources).not.toContain('FriggVPC');
1445
+ expect(friggResources).not.toContain('FriggPrivateSubnet1');
1446
+ expect(friggResources).not.toContain('FriggNATGateway');
1447
+ });
1448
+ });
1449
+
1351
1450
  describe('convertFlatDiscoveryToStructured - CloudFormation query results', () => {
1352
1451
  it('should add VPC from CloudFormation query to external array', () => {
1353
1452
  const flatDiscovery = {
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.a6abe40.0",
4
+ "version": "2.0.0--canary.490.36b3031.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.a6abe40.0",
20
- "@friggframework/schemas": "2.0.0--canary.490.a6abe40.0",
21
- "@friggframework/test": "2.0.0--canary.490.a6abe40.0",
19
+ "@friggframework/core": "2.0.0--canary.490.36b3031.0",
20
+ "@friggframework/schemas": "2.0.0--canary.490.36b3031.0",
21
+ "@friggframework/test": "2.0.0--canary.490.36b3031.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.a6abe40.0",
50
- "@friggframework/prettier-config": "2.0.0--canary.490.a6abe40.0",
49
+ "@friggframework/eslint-config": "2.0.0--canary.490.36b3031.0",
50
+ "@friggframework/prettier-config": "2.0.0--canary.490.36b3031.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": "a6abe40b6a1d1a48bc28accdf401e2583e73c60c"
82
+ "gitHead": "36b30311e062560a65a75a864b880bff01a745e7"
83
83
  }