@friggframework/devtools 2.0.0--canary.461.77c8d12.0 → 2.0.0--canary.461.39e4094.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.
|
@@ -122,18 +122,21 @@ class CloudFormationDiscovery {
|
|
|
122
122
|
if (LogicalResourceId === 'FriggLambdaSecurityGroup' && ResourceType === 'AWS::EC2::SecurityGroup') {
|
|
123
123
|
discovered.securityGroupId = PhysicalResourceId;
|
|
124
124
|
console.log(` ✓ Found security group in stack: ${PhysicalResourceId}`);
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
|
|
126
|
+
// Query security group to get VPC ID (required because SG resource doesn't include VPC ID)
|
|
127
|
+
if (this.provider && this.provider.getEC2Client && !discovered.defaultVpcId) {
|
|
127
128
|
try {
|
|
128
|
-
console.log(` Querying
|
|
129
|
+
console.log(` Querying EC2 to get VPC ID from security group...`);
|
|
129
130
|
const { DescribeSecurityGroupsCommand } = require('@aws-sdk/client-ec2');
|
|
130
|
-
const
|
|
131
|
+
const ec2Client = this.provider.getEC2Client();
|
|
132
|
+
const sgDetails = await ec2Client.send(
|
|
131
133
|
new DescribeSecurityGroupsCommand({
|
|
132
134
|
GroupIds: [PhysicalResourceId]
|
|
133
135
|
})
|
|
134
136
|
);
|
|
137
|
+
|
|
135
138
|
if (sgDetails.SecurityGroups && sgDetails.SecurityGroups.length > 0) {
|
|
136
|
-
discovered.defaultVpcId = sgDetails.SecurityGroups[0].VpcId;
|
|
139
|
+
discovered.defaultVpcId = sgDetails.SecurityGroups[0].VpcId;
|
|
137
140
|
console.log(` ✓ Extracted VPC ID from security group: ${discovered.defaultVpcId}`);
|
|
138
141
|
} else {
|
|
139
142
|
console.warn(` ⚠️ Security group query returned no results`);
|
|
@@ -193,6 +196,12 @@ class CloudFormationDiscovery {
|
|
|
193
196
|
discovered.natGatewayId = PhysicalResourceId;
|
|
194
197
|
}
|
|
195
198
|
|
|
199
|
+
// VPC - direct extraction (primary method)
|
|
200
|
+
if (LogicalResourceId === 'FriggVPC' && ResourceType === 'AWS::EC2::VPC') {
|
|
201
|
+
discovered.defaultVpcId = PhysicalResourceId;
|
|
202
|
+
console.log(` ✓ Found VPC in stack: ${PhysicalResourceId}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
196
205
|
// KMS Key (alternative to output)
|
|
197
206
|
if (LogicalResourceId === 'FriggKMSKey' && ResourceType === 'AWS::KMS::Key') {
|
|
198
207
|
// Note: For KMS, we prefer the ARN from outputs, but this is a fallback
|
|
@@ -253,6 +253,30 @@ describe('CloudFormationDiscovery', () => {
|
|
|
253
253
|
});
|
|
254
254
|
});
|
|
255
255
|
|
|
256
|
+
it('should extract VPC directly from stack resources', async () => {
|
|
257
|
+
const mockStack = {
|
|
258
|
+
StackName: 'test-stack',
|
|
259
|
+
Outputs: [],
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const mockResources = [
|
|
263
|
+
{
|
|
264
|
+
LogicalResourceId: 'FriggVPC',
|
|
265
|
+
PhysicalResourceId: 'vpc-037ec55fe87aec1e7',
|
|
266
|
+
ResourceType: 'AWS::EC2::VPC',
|
|
267
|
+
},
|
|
268
|
+
];
|
|
269
|
+
|
|
270
|
+
mockProvider.describeStack.mockResolvedValue(mockStack);
|
|
271
|
+
mockProvider.listStackResources.mockResolvedValue(mockResources);
|
|
272
|
+
|
|
273
|
+
const result = await cfDiscovery.discoverFromStack('test-stack');
|
|
274
|
+
|
|
275
|
+
expect(result).toEqual({
|
|
276
|
+
defaultVpcId: 'vpc-037ec55fe87aec1e7',
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
256
280
|
it('should combine outputs and resources correctly', async () => {
|
|
257
281
|
const mockStack = {
|
|
258
282
|
StackName: 'test-stack',
|
|
@@ -85,19 +85,26 @@ async function gatherDiscoveredResources(appDefinition) {
|
|
|
85
85
|
const hasAuroraData = stackResources?.auroraClusterId;
|
|
86
86
|
const hasSomeUsefulData = hasVpcData || hasKmsData || hasAuroraData;
|
|
87
87
|
|
|
88
|
+
// Check if we're in isolated mode (each stage gets its own VPC/Aurora)
|
|
89
|
+
const isIsolatedMode = appDefinition.managementMode === 'managed' &&
|
|
90
|
+
appDefinition.vpcIsolation === 'isolated';
|
|
91
|
+
|
|
88
92
|
if (stackResources && hasSomeUsefulData) {
|
|
89
93
|
console.log(' ✓ Discovered resources from existing CloudFormation stack');
|
|
90
94
|
console.log('✅ Cloud resource discovery completed successfully!');
|
|
91
95
|
return stackResources;
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
// In isolated mode,
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
// In isolated mode, NEVER fall back to AWS discovery for VPC/Aurora
|
|
99
|
+
// These resources must be isolated per stage, so we either:
|
|
100
|
+
// 1. Use resources from THIS stage's CloudFormation stack (handled above)
|
|
101
|
+
// 2. Return empty to CREATE fresh isolated resources for this stage
|
|
102
|
+
if (isIsolatedMode) {
|
|
103
|
+
console.log(' ℹ Isolated mode: No CloudFormation stack or no VPC/Aurora in stack');
|
|
104
|
+
console.log(' ℹ Will create fresh isolated VPC/Aurora for this stage');
|
|
105
|
+
console.log(' ℹ Checking for shared KMS key...');
|
|
98
106
|
|
|
99
|
-
//
|
|
100
|
-
// Pass serviceName and stage to search for stage-specific alias
|
|
107
|
+
// KMS keys CAN be shared across stages (encryption keys are safe to reuse)
|
|
101
108
|
const kmsDiscovery = new KmsDiscovery(provider);
|
|
102
109
|
const kmsConfig = {
|
|
103
110
|
serviceName: appDefinition.name || 'create-frigg-app',
|
|
@@ -108,12 +115,12 @@ async function gatherDiscoveredResources(appDefinition) {
|
|
|
108
115
|
|
|
109
116
|
if (kmsResult?.defaultKmsKeyId) {
|
|
110
117
|
console.log(' ✓ Found shared KMS key (can be reused across stages)');
|
|
111
|
-
console.log('✅ Cloud resource discovery completed
|
|
118
|
+
console.log('✅ Cloud resource discovery completed - will create isolated VPC/Aurora!');
|
|
112
119
|
return kmsResult;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
console.log(' ℹ No existing KMS key found - will create new one');
|
|
116
|
-
console.log('✅ Cloud resource discovery completed
|
|
123
|
+
console.log('✅ Cloud resource discovery completed - will create fresh isolated resources!');
|
|
117
124
|
return {};
|
|
118
125
|
}
|
|
119
126
|
|
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.39e4094.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.39e4094.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.461.39e4094.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.39e4094.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.39e4094.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": "39e40947472c29e3847fa53dad03ab1354568e56"
|
|
74
74
|
}
|