@friggframework/devtools 2.0.0--canary.490.36b3031.0 → 2.0.0--canary.490.6e556a4.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.
@@ -1348,18 +1348,19 @@ 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
1351
+ describe('External VPC with stack-managed routing infrastructure pattern', () => {
1352
+ it('should correctly handle external VPC with stack-managed routing infrastructure', async () => {
1353
+ // This pattern occurs when VPC/subnets/NAT are external but routing (route tables,
1354
+ // VPC endpoints, security groups) are managed by CloudFormation stack
1354
1355
  const appDefinition = {
1355
1356
  vpc: { enable: true },
1356
1357
  encryption: { fieldLevelEncryptionMethod: 'kms' },
1357
1358
  };
1358
1359
 
1359
- // Actual Frontify discovery results (from production logs)
1360
+ // Discovery results from real-world production scenario
1360
1361
  const discoveredResources = {
1361
1362
  fromCloudFormationStack: true,
1362
- stackName: 'create-frigg-app-production',
1363
+ stackName: 'test-production-stack',
1363
1364
  existingLogicalIds: [
1364
1365
  'FriggLambdaSecurityGroup',
1365
1366
  'FriggLambdaRouteTable',
@@ -1447,6 +1448,122 @@ describe('VpcBuilder', () => {
1447
1448
  });
1448
1449
  });
1449
1450
 
1451
+ describe('convertFlatDiscoveryToStructured - VPC Endpoints from CloudFormation', () => {
1452
+ it('should add VPC endpoints to stackManaged when in existingLogicalIds', () => {
1453
+ const flatDiscovery = {
1454
+ fromCloudFormationStack: true,
1455
+ stackName: 'test-stack',
1456
+ existingLogicalIds: [
1457
+ 'FriggS3VPCEndpoint',
1458
+ 'FriggDynamoDBVPCEndpoint',
1459
+ 'FriggKMSVPCEndpoint'
1460
+ ],
1461
+ s3VpcEndpointId: 'vpce-s3-stack',
1462
+ dynamodbVpcEndpointId: 'vpce-ddb-stack',
1463
+ kmsVpcEndpointId: 'vpce-kms-stack'
1464
+ };
1465
+
1466
+ const result = vpcBuilder.convertFlatDiscoveryToStructured(flatDiscovery);
1467
+
1468
+ // VPC endpoints should be in stackManaged (not external)
1469
+ expect(result.stackManaged).toContainEqual(
1470
+ expect.objectContaining({
1471
+ logicalId: 'FriggS3VPCEndpoint',
1472
+ physicalId: 'vpce-s3-stack',
1473
+ resourceType: 'AWS::EC2::VPCEndpoint'
1474
+ })
1475
+ );
1476
+ expect(result.stackManaged).toContainEqual(
1477
+ expect.objectContaining({
1478
+ logicalId: 'FriggDynamoDBVPCEndpoint',
1479
+ physicalId: 'vpce-ddb-stack',
1480
+ resourceType: 'AWS::EC2::VPCEndpoint'
1481
+ })
1482
+ );
1483
+ expect(result.stackManaged).toContainEqual(
1484
+ expect.objectContaining({
1485
+ logicalId: 'FriggKMSVPCEndpoint',
1486
+ physicalId: 'vpce-kms-stack',
1487
+ resourceType: 'AWS::EC2::VPCEndpoint'
1488
+ })
1489
+ );
1490
+
1491
+ // Should NOT be in external array
1492
+ expect(result.external.some(r => r.physicalId === 'vpce-s3-stack')).toBe(false);
1493
+ expect(result.external.some(r => r.physicalId === 'vpce-ddb-stack')).toBe(false);
1494
+ expect(result.external.some(r => r.physicalId === 'vpce-kms-stack')).toBe(false);
1495
+ });
1496
+
1497
+ it('should add VPC endpoints to external when NOT in existingLogicalIds', () => {
1498
+ const flatDiscovery = {
1499
+ fromCloudFormationStack: false, // AWS API discovery
1500
+ s3VpcEndpointId: 'vpce-s3-external',
1501
+ dynamodbVpcEndpointId: 'vpce-ddb-external'
1502
+ };
1503
+
1504
+ const result = vpcBuilder.convertFlatDiscoveryToStructured(flatDiscovery);
1505
+
1506
+ // Should be in external (AWS discovery)
1507
+ expect(result.external).toContainEqual(
1508
+ expect.objectContaining({
1509
+ physicalId: 'vpce-s3-external',
1510
+ resourceType: 'AWS::EC2::VPCEndpoint',
1511
+ source: 'aws-discovery'
1512
+ })
1513
+ );
1514
+
1515
+ // Should NOT be in stackManaged
1516
+ expect(result.stackManaged.some(r => r.physicalId === 'vpce-s3-external')).toBe(false);
1517
+ });
1518
+
1519
+ it('should preserve existing VPC endpoints and only create missing ones', async () => {
1520
+ const appDefinition = {
1521
+ vpc: { enable: true },
1522
+ encryption: { fieldLevelEncryptionMethod: 'kms' },
1523
+ };
1524
+
1525
+ const discoveredResources = {
1526
+ fromCloudFormationStack: true,
1527
+ stackName: 'test-stack',
1528
+ existingLogicalIds: [
1529
+ 'FriggS3VPCEndpoint', // In stack
1530
+ 'FriggDynamoDBVPCEndpoint', // In stack
1531
+ 'FriggKMSVPCEndpoint' // In stack
1532
+ // SecretsManager and SQS NOT in stack (were deleted)
1533
+ ],
1534
+ defaultVpcId: 'vpc-123',
1535
+ privateSubnetId1: 'subnet-1',
1536
+ privateSubnetId2: 'subnet-2',
1537
+ lambdaSecurityGroupId: 'sg-123',
1538
+ routeTableId: 'rtb-123',
1539
+ // Endpoints in stack
1540
+ s3VpcEndpointId: 'vpce-s3-existing',
1541
+ dynamodbVpcEndpointId: 'vpce-ddb-existing',
1542
+ kmsVpcEndpointId: 'vpce-kms-existing'
1543
+ // secretsManagerVpcEndpointId and sqsVpcEndpointId NOT present
1544
+ };
1545
+
1546
+ const result = await vpcBuilder.build(appDefinition, discoveredResources);
1547
+
1548
+ // Existing endpoints MUST be in template (re-added)
1549
+ expect(result.resources.FriggS3VPCEndpoint).toBeDefined();
1550
+ expect(result.resources.FriggS3VPCEndpoint.Properties.VpcId).toBe('vpc-123');
1551
+
1552
+ expect(result.resources.FriggDynamoDBVPCEndpoint).toBeDefined();
1553
+ expect(result.resources.FriggDynamoDBVPCEndpoint.Properties.VpcId).toBe('vpc-123');
1554
+
1555
+ expect(result.resources.FriggKMSVPCEndpoint).toBeDefined();
1556
+ expect(result.resources.FriggKMSVPCEndpoint.Properties.VpcId).toBe('vpc-123');
1557
+
1558
+ // Missing endpoints should also be created
1559
+ expect(result.resources.FriggSecretsManagerVPCEndpoint).toBeDefined();
1560
+ expect(result.resources.FriggSQSVPCEndpoint).toBeDefined();
1561
+
1562
+ // VPC Endpoint Security Group should be created
1563
+ expect(result.resources.FriggVPCEndpointSecurityGroup).toBeDefined();
1564
+ });
1565
+ });
1566
+
1450
1567
  describe('convertFlatDiscoveryToStructured - CloudFormation query results', () => {
1451
1568
  it('should add VPC from CloudFormation query to external array', () => {
1452
1569
  const flatDiscovery = {
@@ -1539,10 +1656,10 @@ describe('VpcBuilder', () => {
1539
1656
  expect(result.external.some(r => r.physicalId === 'subnet-in-stack')).toBe(false);
1540
1657
  });
1541
1658
 
1542
- it('should handle Frontify pattern: stack resources + queried external references', () => {
1659
+ it('should handle external VPC pattern: stack resources + queried external references', () => {
1543
1660
  const flatDiscovery = {
1544
1661
  fromCloudFormationStack: true,
1545
- stackName: 'create-frigg-app-production',
1662
+ stackName: 'test-production-stack',
1546
1663
  existingLogicalIds: [
1547
1664
  'FriggLambdaSecurityGroup',
1548
1665
  'FriggLambdaRouteTable',
@@ -1554,14 +1671,14 @@ describe('VpcBuilder', () => {
1554
1671
  'FriggKMSVPCEndpoint'
1555
1672
  ],
1556
1673
  // Stack resources
1557
- lambdaSecurityGroupId: 'sg-01002240c6a446202',
1558
- routeTableId: 'rtb-08af43bbf0775602d',
1559
- s3VpcEndpointId: 'vpce-s3',
1674
+ lambdaSecurityGroupId: 'sg-stack-123',
1675
+ routeTableId: 'rtb-stack-456',
1676
+ s3VpcEndpointId: 'vpce-s3-stack',
1560
1677
  // External resources (discovered via queries)
1561
- defaultVpcId: 'vpc-0cd17c0e06cb28b28',
1562
- privateSubnetId1: 'subnet-034f6562dbbc16348',
1563
- privateSubnetId2: 'subnet-0b8be2b82aeb5cdec',
1564
- existingNatGatewayId: 'nat-022660c36a47e2d79'
1678
+ defaultVpcId: 'vpc-external-123',
1679
+ privateSubnetId1: 'subnet-external-1',
1680
+ privateSubnetId2: 'subnet-external-2',
1681
+ existingNatGatewayId: 'nat-external-789'
1565
1682
  };
1566
1683
 
1567
1684
  const result = vpcBuilder.convertFlatDiscoveryToStructured(flatDiscovery);
@@ -1569,19 +1686,19 @@ describe('VpcBuilder', () => {
1569
1686
  // Stack resources should be in stackManaged
1570
1687
  expect(result.stackManaged).toEqual(
1571
1688
  expect.arrayContaining([
1572
- expect.objectContaining({ logicalId: 'FriggLambdaSecurityGroup', physicalId: 'sg-01002240c6a446202' }),
1573
- expect.objectContaining({ logicalId: 'FriggLambdaRouteTable', physicalId: 'rtb-08af43bbf0775602d' }),
1574
- expect.objectContaining({ logicalId: 'FriggS3VPCEndpoint' })
1689
+ expect.objectContaining({ logicalId: 'FriggLambdaSecurityGroup', physicalId: 'sg-stack-123' }),
1690
+ expect.objectContaining({ logicalId: 'FriggLambdaRouteTable', physicalId: 'rtb-stack-456' }),
1691
+ expect.objectContaining({ logicalId: 'FriggS3VPCEndpoint', physicalId: 'vpce-s3-stack' })
1575
1692
  ])
1576
1693
  );
1577
1694
 
1578
1695
  // External resources should be in external array
1579
1696
  expect(result.external).toEqual(
1580
1697
  expect.arrayContaining([
1581
- expect.objectContaining({ physicalId: 'vpc-0cd17c0e06cb28b28', resourceType: 'AWS::EC2::VPC', source: 'cloudformation-query' }),
1582
- expect.objectContaining({ physicalId: 'subnet-034f6562dbbc16348', resourceType: 'AWS::EC2::Subnet', source: 'cloudformation-query' }),
1583
- expect.objectContaining({ physicalId: 'subnet-0b8be2b82aeb5cdec', resourceType: 'AWS::EC2::Subnet', source: 'cloudformation-query' }),
1584
- expect.objectContaining({ physicalId: 'nat-022660c36a47e2d79', resourceType: 'AWS::EC2::NatGateway', source: 'cloudformation-query' })
1698
+ expect.objectContaining({ physicalId: 'vpc-external-123', resourceType: 'AWS::EC2::VPC', source: 'cloudformation-query' }),
1699
+ expect.objectContaining({ physicalId: 'subnet-external-1', resourceType: 'AWS::EC2::Subnet', source: 'cloudformation-query' }),
1700
+ expect.objectContaining({ physicalId: 'subnet-external-2', resourceType: 'AWS::EC2::Subnet', source: 'cloudformation-query' }),
1701
+ expect.objectContaining({ physicalId: 'nat-external-789', resourceType: 'AWS::EC2::NatGateway', source: 'cloudformation-query' })
1585
1702
  ])
1586
1703
  );
1587
1704
  });
@@ -589,7 +589,7 @@ describe('CloudFormationDiscovery', () => {
589
589
 
590
590
  describe('External VPC with routing infrastructure pattern', () => {
591
591
  it('should discover routing resources when VPC is external', async () => {
592
- // This tests the Frontify pattern: external VPC/subnets/KMS,
592
+ // This tests the external VPC pattern: external VPC/subnets/KMS,
593
593
  // but stack creates routing infrastructure (route table, NAT route, VPC endpoints)
594
594
  const mockStack = {
595
595
  StackName: 'create-frigg-app-production',
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.36b3031.0",
4
+ "version": "2.0.0--canary.490.6e556a4.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.36b3031.0",
20
- "@friggframework/schemas": "2.0.0--canary.490.36b3031.0",
21
- "@friggframework/test": "2.0.0--canary.490.36b3031.0",
19
+ "@friggframework/core": "2.0.0--canary.490.6e556a4.0",
20
+ "@friggframework/schemas": "2.0.0--canary.490.6e556a4.0",
21
+ "@friggframework/test": "2.0.0--canary.490.6e556a4.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.36b3031.0",
50
- "@friggframework/prettier-config": "2.0.0--canary.490.36b3031.0",
49
+ "@friggframework/eslint-config": "2.0.0--canary.490.6e556a4.0",
50
+ "@friggframework/prettier-config": "2.0.0--canary.490.6e556a4.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": "36b30311e062560a65a75a864b880bff01a745e7"
82
+ "gitHead": "6e556a4ddd243fe9163916341b1d70c31dd86ca0"
83
83
  }