@friggframework/devtools 2.0.0--canary.461.e5a72ea.0 → 2.0.0--canary.461.61382d8.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.
@@ -83,7 +83,7 @@ class AuroraBuilder extends InfrastructureBuilder {
83
83
  console.log(`\n[${this.name}] Configuring Aurora PostgreSQL...`);
84
84
 
85
85
  const dbConfig = appDefinition.database.postgres;
86
-
86
+
87
87
  // Normalize top-level managementMode
88
88
  const globalMode = appDefinition.managementMode || 'discover';
89
89
  const vpcIsolation = appDefinition.vpcIsolation || 'shared';
@@ -95,10 +95,10 @@ class AuroraBuilder extends InfrastructureBuilder {
95
95
  if (dbConfig.management) {
96
96
  console.log(` ⚠️ managementMode='managed' ignoring: database.postgres.management`);
97
97
  }
98
-
98
+
99
99
  // Clear granular option to prevent conflicts
100
100
  delete appDefinition.database.postgres.management;
101
-
101
+
102
102
  // Set management based on isolation strategy
103
103
  if (vpcIsolation === 'isolated') {
104
104
  management = 'managed'; // New VPC = new Aurora
@@ -88,7 +88,13 @@ class KmsBuilder extends InfrastructureBuilder {
88
88
  // Use discovered KMS key
89
89
  const kmsKeyId = discoveredResources.defaultKmsKeyId || '${env:AWS_DISCOVERY_KMS_KEY_ID}';
90
90
  console.log(` Using ${discoveredResources.defaultKmsKeyId ? 'discovered' : 'environment variable'} KMS key`);
91
- result.environment.KMS_KEY_ARN = kmsKeyId;
91
+
92
+ // Format as ARN if it's just a key ID (for IAM policies)
93
+ const kmsArn = kmsKeyId.startsWith('arn:')
94
+ ? kmsKeyId
95
+ : `arn:aws:kms:\${self:provider.region}:\${aws:accountId}:key/${kmsKeyId}`;
96
+
97
+ result.environment.KMS_KEY_ARN = kmsArn;
92
98
  }
93
99
 
94
100
  // Add IAM permissions for Lambda role
@@ -366,7 +366,8 @@ describe('KmsBuilder', () => {
366
366
 
367
367
  const result = await kmsBuilder.build(appDefinition, discoveredResources);
368
368
 
369
- expect(result.environment.KMS_KEY_ARN).toBe('${env:AWS_DISCOVERY_KMS_KEY_ID}');
369
+ // Should format env var as ARN for IAM policies
370
+ expect(result.environment.KMS_KEY_ARN).toBe('arn:aws:kms:${self:provider.region}:${aws:accountId}:key/${env:AWS_DISCOVERY_KMS_KEY_ID}');
370
371
  });
371
372
  });
372
373
  });
@@ -90,11 +90,22 @@ async function gatherDiscoveredResources(appDefinition) {
90
90
  return stackResources;
91
91
  }
92
92
 
93
- // In isolated mode, ONLY use CloudFormation discovery for this stage's stack
94
- // Do NOT fall back to AWS API discovery (which finds resources from other stages)
93
+ // In isolated mode, ONLY use CloudFormation discovery for VPC/Aurora
94
+ // But still discover KMS (encryption keys can be safely shared across stages)
95
95
  if (appDefinition.managementMode === 'managed' && appDefinition.vpcIsolation === 'isolated') {
96
- console.log(' ℹ Isolated mode: only discovering resources from this stage\'s stack');
97
- console.log(' ℹ No existing stack resources found - will create fresh infrastructure');
96
+ console.log(' ℹ Isolated mode: discovering KMS (shareable) but not VPC/Aurora (isolated)');
97
+
98
+ // Still run KMS discovery - encryption keys are safe to share
99
+ const kmsDiscovery = new KmsDiscovery(provider);
100
+ const kmsResult = await kmsDiscovery.discover();
101
+
102
+ if (kmsResult?.defaultKmsKeyId) {
103
+ console.log(' ✓ Found shared KMS key (can be reused across stages)');
104
+ console.log('✅ Cloud resource discovery completed successfully!');
105
+ return kmsResult;
106
+ }
107
+
108
+ console.log(' ℹ No existing resources found - will create fresh infrastructure');
98
109
  console.log('✅ Cloud resource discovery completed successfully!');
99
110
  return {};
100
111
  }
@@ -417,7 +417,7 @@ describe('Resource Discovery', () => {
417
417
  }));
418
418
  });
419
419
 
420
- it('should return empty results for isolated mode (prevents cross-stage contamination)', async () => {
420
+ it('should discover KMS but not VPC/Aurora in isolated mode', async () => {
421
421
  const appDefinition = {
422
422
  name: 'test-app',
423
423
  managementMode: 'managed',
@@ -427,18 +427,26 @@ describe('Resource Discovery', () => {
427
427
  };
428
428
 
429
429
  process.env.SLS_STAGE = 'dev';
430
+
431
+ // Mock KMS discovery returning a shared key
432
+ mockKmsDiscovery.discover.mockResolvedValue({
433
+ defaultKmsKeyId: 'shared-kms-key-123',
434
+ });
430
435
 
431
436
  const result = await gatherDiscoveredResources(appDefinition);
432
437
 
433
- // Should return empty (no discovery)
434
- expect(result).toEqual({});
438
+ // Should return KMS (shareable) but not VPC/Aurora (isolated)
439
+ expect(result).toEqual({
440
+ defaultKmsKeyId: 'shared-kms-key-123',
441
+ });
435
442
 
436
- // Should NOT call AWS API discovery
443
+ // Should call KMS discovery (shared) but NOT VPC/Aurora discovery (isolated)
444
+ expect(mockKmsDiscovery.discover).toHaveBeenCalled();
437
445
  expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
438
446
  expect(mockAuroraDiscovery.discover).not.toHaveBeenCalled();
439
447
  });
440
448
 
441
- it('should return empty in isolated mode even if stack exists (fresh creation)', async () => {
449
+ it('should return empty if no KMS found in isolated mode (fresh infrastructure)', async () => {
442
450
  const { CloudFormationDiscovery } = require('./cloudformation-discovery');
443
451
 
444
452
  // Mock that CF stack exists but we still want fresh resources
@@ -454,14 +462,18 @@ describe('Resource Discovery', () => {
454
462
  };
455
463
 
456
464
  process.env.SLS_STAGE = 'dev';
465
+
466
+ // Mock KMS discovery finding nothing
467
+ mockKmsDiscovery.discover.mockResolvedValue({});
457
468
 
458
469
  const result = await gatherDiscoveredResources(appDefinition);
459
470
 
460
- // In isolated mode, always return empty to force fresh creation
461
- // This prevents any cross-stage resource reuse
471
+ // Should return empty (no VPC/Aurora, and KMS not found)
472
+ // This will trigger fresh KMS creation
462
473
  expect(result).toEqual({});
463
474
 
464
- // Should NOT call AWS API discovery
475
+ // Should call KMS discovery but NOT VPC/Aurora
476
+ expect(mockKmsDiscovery.discover).toHaveBeenCalled();
465
477
  expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
466
478
  });
467
479
 
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.e5a72ea.0",
4
+ "version": "2.0.0--canary.461.61382d8.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.e5a72ea.0",
15
- "@friggframework/test": "2.0.0--canary.461.e5a72ea.0",
14
+ "@friggframework/schemas": "2.0.0--canary.461.61382d8.0",
15
+ "@friggframework/test": "2.0.0--canary.461.61382d8.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.e5a72ea.0",
38
- "@friggframework/prettier-config": "2.0.0--canary.461.e5a72ea.0",
37
+ "@friggframework/eslint-config": "2.0.0--canary.461.61382d8.0",
38
+ "@friggframework/prettier-config": "2.0.0--canary.461.61382d8.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": "e5a72eac2f310ebb36765fbc2e810ca850f2cd9f"
73
+ "gitHead": "61382d8a96346ed9732fbaf38b977e13e0a4471d"
74
74
  }