@friggframework/devtools 2.0.0--canary.428.4968614.0 → 2.0.0--canary.428.2b9210c.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.
|
@@ -670,7 +670,7 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
670
670
|
vpcResources.FriggVPCEndpointSecurityGroup = {
|
|
671
671
|
Type: 'AWS::EC2::SecurityGroup',
|
|
672
672
|
Properties: {
|
|
673
|
-
GroupDescription: 'Security group for Frigg VPC Endpoints',
|
|
673
|
+
GroupDescription: 'Security group for Frigg VPC Endpoints - allows HTTPS from Lambda functions',
|
|
674
674
|
VpcId: { Ref: 'FriggVPC' },
|
|
675
675
|
SecurityGroupIngress: [
|
|
676
676
|
{
|
|
@@ -680,7 +680,15 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
680
680
|
SourceSecurityGroupId: {
|
|
681
681
|
Ref: 'FriggLambdaSecurityGroup',
|
|
682
682
|
},
|
|
683
|
-
Description: 'HTTPS from Lambda',
|
|
683
|
+
Description: 'HTTPS from Lambda security group',
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
// Also allow from VPC CIDR as fallback
|
|
687
|
+
IpProtocol: 'tcp',
|
|
688
|
+
FromPort: 443,
|
|
689
|
+
ToPort: 443,
|
|
690
|
+
CidrIp: AppDefinition.vpc.cidrBlock || '10.0.0.0/16',
|
|
691
|
+
Description: 'HTTPS from VPC CIDR (fallback)',
|
|
684
692
|
},
|
|
685
693
|
],
|
|
686
694
|
Tags: [
|
|
@@ -704,6 +712,10 @@ const createVPCInfrastructure = (AppDefinition) => {
|
|
|
704
712
|
Key: 'Type',
|
|
705
713
|
Value: 'VPCEndpoint',
|
|
706
714
|
},
|
|
715
|
+
{
|
|
716
|
+
Key: 'Purpose',
|
|
717
|
+
Value: 'Allow Lambda functions to access VPC endpoints',
|
|
718
|
+
},
|
|
707
719
|
],
|
|
708
720
|
},
|
|
709
721
|
};
|
|
@@ -1668,6 +1680,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1668
1680
|
if (!useExistingEip) {
|
|
1669
1681
|
definition.resources.Resources.FriggNATGatewayEIP = {
|
|
1670
1682
|
Type: 'AWS::EC2::EIP',
|
|
1683
|
+
DeletionPolicy: 'Retain', // Prevent accidental deletion
|
|
1684
|
+
UpdateReplacePolicy: 'Retain', // Prevent replacement during updates
|
|
1671
1685
|
Properties: {
|
|
1672
1686
|
Domain: 'vpc',
|
|
1673
1687
|
Tags: [
|
|
@@ -1796,6 +1810,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1796
1810
|
// Create NAT Gateway only if not reusing existing one
|
|
1797
1811
|
definition.resources.Resources.FriggNATGateway = {
|
|
1798
1812
|
Type: 'AWS::EC2::NatGateway',
|
|
1813
|
+
DeletionPolicy: 'Retain', // Prevent accidental deletion
|
|
1814
|
+
UpdateReplacePolicy: 'Retain', // Prevent replacement during updates
|
|
1799
1815
|
Properties: {
|
|
1800
1816
|
AllocationId: useExistingEip ?
|
|
1801
1817
|
discoveredResources.existingElasticIpAllocationId :
|
|
@@ -1892,11 +1908,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1892
1908
|
}
|
|
1893
1909
|
}
|
|
1894
1910
|
|
|
1895
|
-
//
|
|
1896
|
-
//
|
|
1897
|
-
// This
|
|
1911
|
+
// ALWAYS create the route table resource in CloudFormation for consistency
|
|
1912
|
+
// Use DeletionPolicy: Retain to prevent deletion when removed from template
|
|
1913
|
+
// This ensures CloudFormation maintains consistent state management
|
|
1914
|
+
console.log('Setting up route table for Lambda subnets');
|
|
1915
|
+
|
|
1898
1916
|
definition.resources.Resources.FriggLambdaRouteTable = {
|
|
1899
1917
|
Type: 'AWS::EC2::RouteTable',
|
|
1918
|
+
DeletionPolicy: 'Retain', // Critical: Prevents deletion when resource is removed
|
|
1919
|
+
UpdateReplacePolicy: 'Retain', // Prevents replacement during stack updates
|
|
1900
1920
|
Properties: {
|
|
1901
1921
|
VpcId: discoveredResources.defaultVpcId || {
|
|
1902
1922
|
Ref: 'FriggVPC',
|
|
@@ -1910,10 +1930,21 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1910
1930
|
Key: 'ManagedBy',
|
|
1911
1931
|
Value: 'Frigg',
|
|
1912
1932
|
},
|
|
1933
|
+
{
|
|
1934
|
+
Key: 'Environment',
|
|
1935
|
+
Value: '${self:provider.stage}',
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
Key: 'Service',
|
|
1939
|
+
Value: '${self:service}',
|
|
1940
|
+
},
|
|
1913
1941
|
],
|
|
1914
1942
|
},
|
|
1915
1943
|
};
|
|
1916
1944
|
|
|
1945
|
+
// Always use CloudFormation reference for consistency
|
|
1946
|
+
const routeTableId = { Ref: 'FriggLambdaRouteTable' };
|
|
1947
|
+
|
|
1917
1948
|
// Determine which NAT Gateway ID to use for routing
|
|
1918
1949
|
let natGatewayIdForRoute;
|
|
1919
1950
|
|
|
@@ -1944,13 +1975,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1944
1975
|
);
|
|
1945
1976
|
}
|
|
1946
1977
|
|
|
1947
|
-
//
|
|
1978
|
+
// ALWAYS create/update NAT route if we have a NAT Gateway
|
|
1979
|
+
// This ensures routes are always correct even if NAT Gateway changes
|
|
1948
1980
|
if (natGatewayIdForRoute) {
|
|
1949
|
-
console.log(`
|
|
1981
|
+
console.log(`Configuring NAT route: 0.0.0.0/0 → ${natGatewayIdForRoute}`);
|
|
1950
1982
|
definition.resources.Resources.FriggNATRoute = {
|
|
1951
1983
|
Type: 'AWS::EC2::Route',
|
|
1984
|
+
DependsOn: 'FriggLambdaRouteTable',
|
|
1952
1985
|
Properties: {
|
|
1953
|
-
RouteTableId:
|
|
1986
|
+
RouteTableId: routeTableId,
|
|
1954
1987
|
DestinationCidrBlock: '0.0.0.0/0',
|
|
1955
1988
|
NatGatewayId: natGatewayIdForRoute,
|
|
1956
1989
|
},
|
|
@@ -1967,13 +2000,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1967
2000
|
// CloudFormation will automatically disassociate from old route table first
|
|
1968
2001
|
}
|
|
1969
2002
|
|
|
2003
|
+
// ALWAYS create subnet associations to ensure correct routing
|
|
2004
|
+
// CloudFormation will handle existing associations gracefully
|
|
1970
2005
|
// Only create associations for discovered subnets (not for Refs)
|
|
1971
2006
|
if (typeof vpcConfig.subnetIds[0] === 'string') {
|
|
1972
2007
|
definition.resources.Resources.FriggSubnet1RouteAssociation = {
|
|
1973
2008
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1974
2009
|
Properties: {
|
|
1975
2010
|
SubnetId: vpcConfig.subnetIds[0],
|
|
1976
|
-
RouteTableId:
|
|
2011
|
+
RouteTableId: routeTableId,
|
|
1977
2012
|
},
|
|
1978
2013
|
DependsOn: 'FriggLambdaRouteTable',
|
|
1979
2014
|
};
|
|
@@ -1984,7 +2019,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1984
2019
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1985
2020
|
Properties: {
|
|
1986
2021
|
SubnetId: vpcConfig.subnetIds[1],
|
|
1987
|
-
RouteTableId:
|
|
2022
|
+
RouteTableId: routeTableId,
|
|
1988
2023
|
},
|
|
1989
2024
|
DependsOn: 'FriggLambdaRouteTable',
|
|
1990
2025
|
};
|
|
@@ -1996,7 +2031,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
1996
2031
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
1997
2032
|
Properties: {
|
|
1998
2033
|
SubnetId: vpcConfig.subnetIds[0],
|
|
1999
|
-
RouteTableId:
|
|
2034
|
+
RouteTableId: routeTableId,
|
|
2000
2035
|
},
|
|
2001
2036
|
DependsOn: ['FriggLambdaRouteTable', vpcConfig.subnetIds[0].Ref],
|
|
2002
2037
|
};
|
|
@@ -2007,13 +2042,14 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
2007
2042
|
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
2008
2043
|
Properties: {
|
|
2009
2044
|
SubnetId: vpcConfig.subnetIds[1],
|
|
2010
|
-
RouteTableId:
|
|
2045
|
+
RouteTableId: routeTableId,
|
|
2011
2046
|
},
|
|
2012
2047
|
DependsOn: ['FriggLambdaRouteTable', vpcConfig.subnetIds[1].Ref],
|
|
2013
2048
|
};
|
|
2014
2049
|
}
|
|
2015
2050
|
|
|
2016
|
-
// Add VPC endpoints for AWS service optimization
|
|
2051
|
+
// Add VPC endpoints for AWS service optimization
|
|
2052
|
+
// ALWAYS create these to ensure Lambda functions have optimized access to AWS services
|
|
2017
2053
|
if (AppDefinition.vpc.enableVPCEndpoints !== false) {
|
|
2018
2054
|
definition.resources.Resources.VPCEndpointS3 = {
|
|
2019
2055
|
Type: 'AWS::EC2::VPCEndpoint',
|
|
@@ -2022,7 +2058,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
2022
2058
|
ServiceName:
|
|
2023
2059
|
'com.amazonaws.${self:provider.region}.s3',
|
|
2024
2060
|
VpcEndpointType: 'Gateway',
|
|
2025
|
-
RouteTableIds: [
|
|
2061
|
+
RouteTableIds: [routeTableId],
|
|
2026
2062
|
},
|
|
2027
2063
|
};
|
|
2028
2064
|
|
|
@@ -2033,15 +2069,15 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
2033
2069
|
ServiceName:
|
|
2034
2070
|
'com.amazonaws.${self:provider.region}.dynamodb',
|
|
2035
2071
|
VpcEndpointType: 'Gateway',
|
|
2036
|
-
RouteTableIds: [
|
|
2072
|
+
RouteTableIds: [routeTableId],
|
|
2037
2073
|
},
|
|
2038
2074
|
};
|
|
2075
|
+
}
|
|
2039
2076
|
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
) {
|
|
2077
|
+
// Add KMS VPC endpoint if using KMS encryption
|
|
2078
|
+
if (
|
|
2079
|
+
AppDefinition.encryption?.fieldLevelEncryptionMethod === 'kms'
|
|
2080
|
+
) {
|
|
2045
2081
|
// Validate we have VPC CIDR for security group configuration
|
|
2046
2082
|
if (!discoveredResources.vpcCidr) {
|
|
2047
2083
|
console.warn(
|
|
@@ -2054,28 +2090,80 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
2054
2090
|
!definition.resources.Resources
|
|
2055
2091
|
.VPCEndpointSecurityGroup
|
|
2056
2092
|
) {
|
|
2093
|
+
// Build ingress rules based on what we have
|
|
2094
|
+
const vpcEndpointIngressRules = [];
|
|
2095
|
+
|
|
2096
|
+
// CRITICAL: Allow from Lambda's security group (preferred method)
|
|
2097
|
+
if (vpcConfig.securityGroupIds && vpcConfig.securityGroupIds.length > 0) {
|
|
2098
|
+
// If we have the Lambda security group, reference it directly
|
|
2099
|
+
const lambdaSgId = vpcConfig.securityGroupIds[0];
|
|
2100
|
+
if (typeof lambdaSgId === 'string') {
|
|
2101
|
+
// It's a discovered security group ID
|
|
2102
|
+
vpcEndpointIngressRules.push({
|
|
2103
|
+
IpProtocol: 'tcp',
|
|
2104
|
+
FromPort: 443,
|
|
2105
|
+
ToPort: 443,
|
|
2106
|
+
SourceSecurityGroupId: lambdaSgId,
|
|
2107
|
+
Description: 'HTTPS from Lambda security group',
|
|
2108
|
+
});
|
|
2109
|
+
} else if (lambdaSgId && lambdaSgId.Ref) {
|
|
2110
|
+
// It's a CloudFormation reference
|
|
2111
|
+
vpcEndpointIngressRules.push({
|
|
2112
|
+
IpProtocol: 'tcp',
|
|
2113
|
+
FromPort: 443,
|
|
2114
|
+
ToPort: 443,
|
|
2115
|
+
SourceSecurityGroupId: lambdaSgId,
|
|
2116
|
+
Description: 'HTTPS from Lambda security group',
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// Fallback: If we don't have Lambda SG, use VPC CIDR
|
|
2122
|
+
if (vpcEndpointIngressRules.length === 0 && discoveredResources.vpcCidr) {
|
|
2123
|
+
vpcEndpointIngressRules.push({
|
|
2124
|
+
IpProtocol: 'tcp',
|
|
2125
|
+
FromPort: 443,
|
|
2126
|
+
ToPort: 443,
|
|
2127
|
+
CidrIp: discoveredResources.vpcCidr,
|
|
2128
|
+
Description: 'HTTPS from VPC CIDR (fallback)',
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
// Last resort: Allow from common private IP ranges
|
|
2133
|
+
if (vpcEndpointIngressRules.length === 0) {
|
|
2134
|
+
console.warn(
|
|
2135
|
+
'⚠️ WARNING: No Lambda security group or VPC CIDR found. Using default private IP ranges.'
|
|
2136
|
+
);
|
|
2137
|
+
vpcEndpointIngressRules.push({
|
|
2138
|
+
IpProtocol: 'tcp',
|
|
2139
|
+
FromPort: 443,
|
|
2140
|
+
ToPort: 443,
|
|
2141
|
+
CidrIp: '172.31.0.0/16', // Default VPC CIDR
|
|
2142
|
+
Description: 'HTTPS from default VPC range',
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2057
2146
|
definition.resources.Resources.VPCEndpointSecurityGroup =
|
|
2058
2147
|
{
|
|
2059
2148
|
Type: 'AWS::EC2::SecurityGroup',
|
|
2060
2149
|
Properties: {
|
|
2061
2150
|
GroupDescription:
|
|
2062
|
-
'Security group for VPC endpoints',
|
|
2151
|
+
'Security group for VPC endpoints - allows HTTPS from Lambda functions',
|
|
2063
2152
|
VpcId: discoveredResources.defaultVpcId,
|
|
2064
|
-
SecurityGroupIngress:
|
|
2065
|
-
? [
|
|
2066
|
-
{
|
|
2067
|
-
IpProtocol: 'tcp',
|
|
2068
|
-
FromPort: 443,
|
|
2069
|
-
ToPort: 443,
|
|
2070
|
-
CidrIp: discoveredResources.vpcCidr, // Use discovered VPC CIDR
|
|
2071
|
-
},
|
|
2072
|
-
]
|
|
2073
|
-
: [], // Empty array if no VPC CIDR discovered
|
|
2153
|
+
SecurityGroupIngress: vpcEndpointIngressRules,
|
|
2074
2154
|
Tags: [
|
|
2075
2155
|
{
|
|
2076
2156
|
Key: 'Name',
|
|
2077
2157
|
Value: '${self:service}-${self:provider.stage}-vpc-endpoints-sg',
|
|
2078
2158
|
},
|
|
2159
|
+
{
|
|
2160
|
+
Key: 'ManagedBy',
|
|
2161
|
+
Value: 'Frigg',
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
Key: 'Purpose',
|
|
2165
|
+
Value: 'Allow Lambda functions to access VPC endpoints',
|
|
2166
|
+
},
|
|
2079
2167
|
],
|
|
2080
2168
|
},
|
|
2081
2169
|
};
|
|
@@ -2117,7 +2205,6 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
2117
2205
|
}
|
|
2118
2206
|
}
|
|
2119
2207
|
}
|
|
2120
|
-
}
|
|
2121
2208
|
|
|
2122
2209
|
// SSM Parameter Store Configuration based on App Definition
|
|
2123
2210
|
if (AppDefinition.ssm?.enable === true) {
|
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
const { composeServerlessDefinition } = require('./serverless-template');
|
|
2
2
|
|
|
3
|
+
// Helper to build discovery responses with overridable fields
|
|
4
|
+
const createDiscoveryResponse = (overrides = {}) => ({
|
|
5
|
+
defaultVpcId: 'vpc-123456',
|
|
6
|
+
vpcCidr: '172.31.0.0/16', // Provide VPC CIDR so security group fallbacks can be tested
|
|
7
|
+
defaultSecurityGroupId: 'sg-123456',
|
|
8
|
+
privateSubnetId1: 'subnet-123456',
|
|
9
|
+
privateSubnetId2: 'subnet-789012',
|
|
10
|
+
publicSubnetId: 'subnet-public',
|
|
11
|
+
defaultRouteTableId: 'rtb-123456',
|
|
12
|
+
defaultKmsKeyId:
|
|
13
|
+
'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
|
|
14
|
+
existingNatGatewayId: 'nat-default123',
|
|
15
|
+
...overrides,
|
|
16
|
+
});
|
|
17
|
+
|
|
3
18
|
// Mock AWS Discovery to prevent actual AWS calls
|
|
4
19
|
jest.mock('./aws-discovery', () => {
|
|
5
20
|
return {
|
|
6
|
-
AWSDiscovery: jest.fn().mockImplementation(() => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
defaultSecurityGroupId: 'sg-123456',
|
|
12
|
-
privateSubnetId1: 'subnet-123456',
|
|
13
|
-
privateSubnetId2: 'subnet-789012',
|
|
14
|
-
publicSubnetId: 'subnet-public',
|
|
15
|
-
defaultRouteTableId: 'rtb-123456',
|
|
16
|
-
defaultKmsKeyId: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
|
|
17
|
-
existingNatGatewayId: 'nat-default123' // Add default NAT Gateway for discover mode
|
|
18
|
-
})
|
|
19
|
-
};
|
|
20
|
-
})
|
|
21
|
+
AWSDiscovery: jest.fn().mockImplementation(() => ({
|
|
22
|
+
discoverResources: jest
|
|
23
|
+
.fn()
|
|
24
|
+
.mockResolvedValue(createDiscoveryResponse()),
|
|
25
|
+
})),
|
|
21
26
|
};
|
|
22
27
|
});
|
|
23
28
|
|
|
29
|
+
const { AWSDiscovery } = require('./aws-discovery');
|
|
30
|
+
|
|
24
31
|
describe('composeServerlessDefinition', () => {
|
|
25
32
|
let mockIntegration;
|
|
26
33
|
|
|
27
34
|
beforeEach(() => {
|
|
35
|
+
AWSDiscovery.mockImplementation(() => ({
|
|
36
|
+
discoverResources: jest
|
|
37
|
+
.fn()
|
|
38
|
+
.mockResolvedValue(createDiscoveryResponse()),
|
|
39
|
+
}));
|
|
40
|
+
|
|
28
41
|
mockIntegration = {
|
|
29
42
|
Definition: {
|
|
30
43
|
name: 'testIntegration'
|
|
@@ -344,6 +357,137 @@ describe('composeServerlessDefinition', () => {
|
|
|
344
357
|
expect(result.resources.Resources.VPCEndpointS3.Properties.VpcId).toBe('vpc-123456');
|
|
345
358
|
});
|
|
346
359
|
|
|
360
|
+
it('should allow Lambda security group access for VPC endpoints when security group is discovered', async () => {
|
|
361
|
+
const appDefinition = {
|
|
362
|
+
vpc: {
|
|
363
|
+
enable: true,
|
|
364
|
+
management: 'discover'
|
|
365
|
+
},
|
|
366
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
367
|
+
integrations: []
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
371
|
+
const endpointSg = result.resources.Resources.VPCEndpointSecurityGroup;
|
|
372
|
+
|
|
373
|
+
expect(endpointSg).toBeDefined();
|
|
374
|
+
expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
|
|
375
|
+
{
|
|
376
|
+
IpProtocol: 'tcp',
|
|
377
|
+
FromPort: 443,
|
|
378
|
+
ToPort: 443,
|
|
379
|
+
SourceSecurityGroupId: 'sg-123456',
|
|
380
|
+
Description: 'HTTPS from Lambda security group'
|
|
381
|
+
}
|
|
382
|
+
]);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('should fall back to VPC CIDR when Lambda security group identifier cannot be resolved', async () => {
|
|
386
|
+
AWSDiscovery.mockImplementation(() => ({
|
|
387
|
+
discoverResources: jest
|
|
388
|
+
.fn()
|
|
389
|
+
.mockResolvedValue(createDiscoveryResponse()),
|
|
390
|
+
}));
|
|
391
|
+
|
|
392
|
+
const appDefinition = {
|
|
393
|
+
vpc: {
|
|
394
|
+
enable: true,
|
|
395
|
+
management: 'discover',
|
|
396
|
+
securityGroupIds: [
|
|
397
|
+
{
|
|
398
|
+
'Fn::ImportValue': 'shared-lambda-security-group',
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
},
|
|
402
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
403
|
+
integrations: [],
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
407
|
+
const endpointSg = result.resources.Resources.VPCEndpointSecurityGroup;
|
|
408
|
+
|
|
409
|
+
expect(endpointSg).toBeDefined();
|
|
410
|
+
expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
|
|
411
|
+
{
|
|
412
|
+
IpProtocol: 'tcp',
|
|
413
|
+
FromPort: 443,
|
|
414
|
+
ToPort: 443,
|
|
415
|
+
CidrIp: '172.31.0.0/16',
|
|
416
|
+
Description: 'HTTPS from VPC CIDR (fallback)',
|
|
417
|
+
},
|
|
418
|
+
]);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('should fall back to default private ranges when neither Lambda security group nor VPC CIDR is available', async () => {
|
|
422
|
+
AWSDiscovery.mockImplementation(() => ({
|
|
423
|
+
discoverResources: jest
|
|
424
|
+
.fn()
|
|
425
|
+
.mockResolvedValue(
|
|
426
|
+
createDiscoveryResponse({ vpcCidr: null })
|
|
427
|
+
),
|
|
428
|
+
}));
|
|
429
|
+
|
|
430
|
+
const appDefinition = {
|
|
431
|
+
vpc: {
|
|
432
|
+
enable: true,
|
|
433
|
+
management: 'discover',
|
|
434
|
+
securityGroupIds: [
|
|
435
|
+
{
|
|
436
|
+
'Fn::ImportValue': 'shared-lambda-security-group',
|
|
437
|
+
},
|
|
438
|
+
],
|
|
439
|
+
},
|
|
440
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
441
|
+
integrations: [],
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
445
|
+
const endpointSg = result.resources.Resources.VPCEndpointSecurityGroup;
|
|
446
|
+
|
|
447
|
+
expect(endpointSg).toBeDefined();
|
|
448
|
+
expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
|
|
449
|
+
{
|
|
450
|
+
IpProtocol: 'tcp',
|
|
451
|
+
FromPort: 443,
|
|
452
|
+
ToPort: 443,
|
|
453
|
+
CidrIp: '172.31.0.0/16',
|
|
454
|
+
Description: 'HTTPS from default VPC range',
|
|
455
|
+
},
|
|
456
|
+
]);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('should reference the Lambda security group when creating a new VPC', async () => {
|
|
460
|
+
const appDefinition = {
|
|
461
|
+
vpc: {
|
|
462
|
+
enable: true,
|
|
463
|
+
management: 'create-new'
|
|
464
|
+
},
|
|
465
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
466
|
+
integrations: []
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
470
|
+
const endpointSg = result.resources.Resources.FriggVPCEndpointSecurityGroup;
|
|
471
|
+
|
|
472
|
+
expect(endpointSg).toBeDefined();
|
|
473
|
+
expect(endpointSg.Properties.SecurityGroupIngress).toEqual([
|
|
474
|
+
{
|
|
475
|
+
IpProtocol: 'tcp',
|
|
476
|
+
FromPort: 443,
|
|
477
|
+
ToPort: 443,
|
|
478
|
+
SourceSecurityGroupId: { Ref: 'FriggLambdaSecurityGroup' },
|
|
479
|
+
Description: 'HTTPS from Lambda security group'
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
IpProtocol: 'tcp',
|
|
483
|
+
FromPort: 443,
|
|
484
|
+
ToPort: 443,
|
|
485
|
+
CidrIp: '10.0.0.0/16',
|
|
486
|
+
Description: 'HTTPS from VPC CIDR (fallback)'
|
|
487
|
+
}
|
|
488
|
+
]);
|
|
489
|
+
});
|
|
490
|
+
|
|
347
491
|
it('should not add VPC configuration when vpc.enable is false', async () => {
|
|
348
492
|
const appDefinition = {
|
|
349
493
|
vpc: { enable: false },
|
|
@@ -1326,4 +1470,4 @@ describe('composeServerlessDefinition', () => {
|
|
|
1326
1470
|
await expect(composeServerlessDefinition(appDefinition)).rejects.toThrow('Invalid integration: missing Definition or name');
|
|
1327
1471
|
});
|
|
1328
1472
|
});
|
|
1329
|
-
});
|
|
1473
|
+
});
|
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.428.
|
|
4
|
+
"version": "2.0.0--canary.428.2b9210c.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"@babel/eslint-parser": "^7.18.9",
|
|
10
10
|
"@babel/parser": "^7.25.3",
|
|
11
11
|
"@babel/traverse": "^7.25.3",
|
|
12
|
-
"@friggframework/schemas": "2.0.0--canary.428.
|
|
13
|
-
"@friggframework/test": "2.0.0--canary.428.
|
|
12
|
+
"@friggframework/schemas": "2.0.0--canary.428.2b9210c.0",
|
|
13
|
+
"@friggframework/test": "2.0.0--canary.428.2b9210c.0",
|
|
14
14
|
"@hapi/boom": "^10.0.1",
|
|
15
15
|
"@inquirer/prompts": "^5.3.8",
|
|
16
16
|
"axios": "^1.7.2",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"serverless-http": "^2.7.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@friggframework/eslint-config": "2.0.0--canary.428.
|
|
36
|
-
"@friggframework/prettier-config": "2.0.0--canary.428.
|
|
35
|
+
"@friggframework/eslint-config": "2.0.0--canary.428.2b9210c.0",
|
|
36
|
+
"@friggframework/prettier-config": "2.0.0--canary.428.2b9210c.0",
|
|
37
37
|
"aws-sdk-client-mock": "^4.1.0",
|
|
38
38
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
39
39
|
"jest": "^30.1.3",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"publishConfig": {
|
|
69
69
|
"access": "public"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "2b9210c7401ddd6baacac247aff11e3f73fcb315"
|
|
72
72
|
}
|