@friggframework/devtools 2.0.0-next.36 → 2.0.0-next.38
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.
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +1 -1
- package/frigg-cli/generate-command/index.js +1 -1
- package/frigg-cli/init-command/backend-first-handler.js +1 -1
- package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +2 -2
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +1 -1
- package/infrastructure/GENERATE-IAM-DOCS.md +2 -2
- package/infrastructure/README.md +116 -105
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +4 -4
- package/infrastructure/__tests__/helpers/test-utils.js +1 -1
- package/infrastructure/aws-discovery.js +14 -12
- package/infrastructure/build-time-discovery.js +3 -3
- package/infrastructure/build-time-discovery.test.js +1 -1
- package/infrastructure/iam-generator.js +15 -3
- package/infrastructure/iam-generator.test.js +4 -4
- package/infrastructure/integration.test.js +7 -7
- package/infrastructure/run-discovery.js +4 -4
- package/infrastructure/serverless-template.js +102 -103
- package/infrastructure/serverless-template.test.js +241 -38
- package/package.json +7 -6
|
@@ -54,7 +54,7 @@ describe('Generate Command', () => {
|
|
|
54
54
|
// Mock app definition
|
|
55
55
|
jest.doMock(mockAppDefinitionPath, () => ({
|
|
56
56
|
vpc: { enable: true },
|
|
57
|
-
encryption: {
|
|
57
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
58
58
|
ssm: { enable: true },
|
|
59
59
|
websockets: { enable: false }
|
|
60
60
|
}), { virtual: true });
|
|
@@ -228,7 +228,7 @@ async function generateCommand(options = {}) {
|
|
|
228
228
|
function analyzeAppFeatures(appDefinition) {
|
|
229
229
|
const features = {
|
|
230
230
|
vpc: appDefinition.vpc?.enable === true,
|
|
231
|
-
kms: appDefinition.encryption?.
|
|
231
|
+
kms: appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms',
|
|
232
232
|
ssm: appDefinition.ssm?.enable === true,
|
|
233
233
|
websockets: appDefinition.websockets?.enable === true,
|
|
234
234
|
// Add more feature detection as needed
|
|
@@ -670,7 +670,7 @@ To integrate Frigg into your production application:
|
|
|
670
670
|
const appDefinition = {
|
|
671
671
|
integrations: [], // Will be populated based on selected integrations
|
|
672
672
|
user: { password: true },
|
|
673
|
-
encryption: {
|
|
673
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
674
674
|
vpc: { enable: true },
|
|
675
675
|
security: {
|
|
676
676
|
cors: {
|
|
@@ -9,7 +9,7 @@ AWS Discovery automatically finds your default AWS resources (VPC, subnets, secu
|
|
|
9
9
|
AWS Discovery runs automatically during `frigg build` and `frigg deploy` when your AppDefinition includes:
|
|
10
10
|
|
|
11
11
|
- `vpc.enable: true` - VPC support
|
|
12
|
-
- `encryption.
|
|
12
|
+
- `encryption.fieldLevelEncryptionMethod: 'kms'` - KMS encryption
|
|
13
13
|
- `ssm.enable: true` - SSM Parameter Store
|
|
14
14
|
|
|
15
15
|
## Fail-Fast Behavior
|
|
@@ -222,7 +222,7 @@ If you're stuck, try this recovery process:
|
|
|
222
222
|
// backend/index.js - temporarily disable problematic features
|
|
223
223
|
const appDefinition = {
|
|
224
224
|
vpc: { enable: false },
|
|
225
|
-
encryption: {
|
|
225
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
226
226
|
ssm: { enable: false }
|
|
227
227
|
};
|
|
228
228
|
```
|
|
@@ -354,7 +354,7 @@ Additional permissions needed when your app definition includes `vpc: { enable:
|
|
|
354
354
|
|
|
355
355
|
### KMS Support
|
|
356
356
|
|
|
357
|
-
Additional permissions needed when your app definition includes `encryption: {
|
|
357
|
+
Additional permissions needed when your app definition includes `encryption: { fieldLevelEncryptionMethod: 'kms' }`:
|
|
358
358
|
|
|
359
359
|
```json
|
|
360
360
|
{
|
|
@@ -58,7 +58,7 @@ The command analyzes your `backend/index.js` AppDefinition and generates IAM pol
|
|
|
58
58
|
- Route table and security group management
|
|
59
59
|
- Elastic IP allocation
|
|
60
60
|
|
|
61
|
-
#### KMS Encryption (`encryption.
|
|
61
|
+
#### KMS Encryption (`encryption.fieldLevelEncryptionMethod: 'kms'`)
|
|
62
62
|
|
|
63
63
|
- KMS key usage for Lambda and S3
|
|
64
64
|
- Data encryption and decryption permissions
|
|
@@ -85,7 +85,7 @@ const appDefinition = {
|
|
|
85
85
|
enable: true,
|
|
86
86
|
},
|
|
87
87
|
encryption: {
|
|
88
|
-
|
|
88
|
+
fieldLevelEncryptionMethod: 'kms',
|
|
89
89
|
},
|
|
90
90
|
ssm: {
|
|
91
91
|
enable: false,
|
package/infrastructure/README.md
CHANGED
|
@@ -27,7 +27,7 @@ infrastructure/
|
|
|
27
27
|
├── AWS-DISCOVERY-TROUBLESHOOTING.md # AWS discovery troubleshooting
|
|
28
28
|
├── DEPLOYMENT-INSTRUCTIONS.md # General deployment instructions
|
|
29
29
|
├── README-TESTING.md # Testing strategy documentation
|
|
30
|
-
├──
|
|
30
|
+
├──
|
|
31
31
|
├── cloudformation/ # CloudFormation templates
|
|
32
32
|
│ ├── monitoring-infrastructure.yaml # Enhanced monitoring (Phase 3)
|
|
33
33
|
│ ├── cdn-infrastructure.yaml # CDN and UI distribution (Phase 3)
|
|
@@ -60,71 +60,79 @@ infrastructure/
|
|
|
60
60
|
#### 1. Serverless Template Generator (`serverless-template.js`)
|
|
61
61
|
|
|
62
62
|
Generates complete serverless.yml configurations with:
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
63
|
+
|
|
64
|
+
- VPC configuration and resource discovery
|
|
65
|
+
- KMS encryption for field-level encryption
|
|
66
|
+
- SSM Parameter Store integration
|
|
67
|
+
- Integration-specific functions and queues
|
|
68
|
+
- WebSocket support for real-time features
|
|
68
69
|
|
|
69
70
|
#### 2. AWS Discovery (`aws-discovery.js`)
|
|
70
71
|
|
|
71
72
|
Automatically discovers existing AWS resources:
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
73
|
+
|
|
74
|
+
- Default VPC and security groups
|
|
75
|
+
- Private subnets for Lambda functions
|
|
76
|
+
- Customer-managed KMS keys
|
|
77
|
+
- Route tables for VPC endpoints
|
|
76
78
|
|
|
77
79
|
#### 3. Build-Time Discovery (`build-time-discovery.js`)
|
|
78
80
|
|
|
79
81
|
Integrates AWS discovery into the build process:
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
82
|
+
|
|
83
|
+
- Pre-build hook for serverless deployments
|
|
84
|
+
- Environment variable injection
|
|
85
|
+
- Template variable replacement
|
|
86
|
+
- Error handling and fallback values
|
|
84
87
|
|
|
85
88
|
### Phase 3 Infrastructure
|
|
86
89
|
|
|
87
90
|
#### 1. Enhanced Monitoring (`cloudformation/monitoring-infrastructure.yaml`)
|
|
88
91
|
|
|
89
92
|
Production-ready monitoring with:
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
93
|
+
|
|
94
|
+
- Code generation service monitoring
|
|
95
|
+
- UI distribution monitoring
|
|
96
|
+
- Advanced CloudWatch dashboards
|
|
97
|
+
- Custom metrics and alarms
|
|
94
98
|
|
|
95
99
|
#### 2. CDN Infrastructure (`cloudformation/cdn-infrastructure.yaml`)
|
|
96
100
|
|
|
97
101
|
CloudFront distribution for UI packages:
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
+
|
|
103
|
+
- S3 bucket for multi-framework UI packages
|
|
104
|
+
- CloudFront distribution with custom domains
|
|
105
|
+
- Lambda function for package deployment
|
|
106
|
+
- API Gateway for package management
|
|
102
107
|
|
|
103
108
|
#### 3. Code Generation Infrastructure (`cloudformation/codegen-infrastructure.yaml`)
|
|
104
109
|
|
|
105
110
|
Serverless code generation platform:
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
+
|
|
112
|
+
- SQS queue for generation requests
|
|
113
|
+
- Lambda function with AI/ML integration
|
|
114
|
+
- DynamoDB tracking table
|
|
115
|
+
- S3 storage for templates and generated code
|
|
116
|
+
- ElastiCache for template caching
|
|
111
117
|
|
|
112
118
|
#### 4. Advanced Alerting (`cloudformation/alerting-infrastructure.yaml`)
|
|
113
119
|
|
|
114
120
|
Multi-channel alerting system:
|
|
115
|
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
121
|
+
|
|
122
|
+
- Multiple SNS topics for alert severity levels
|
|
123
|
+
- Lambda function for alert processing
|
|
124
|
+
- PagerDuty and Slack integration
|
|
125
|
+
- Composite alarms for system health
|
|
126
|
+
- Advanced metrics collection
|
|
120
127
|
|
|
121
128
|
#### 5. Deployment Pipeline (`cloudformation/deployment-pipeline.yaml`)
|
|
122
129
|
|
|
123
130
|
CI/CD pipeline for automated deployments:
|
|
124
|
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
131
|
+
|
|
132
|
+
- CodePipeline with GitHub integration
|
|
133
|
+
- CodeBuild projects for backend and UI
|
|
134
|
+
- Multi-stage deployment workflow
|
|
135
|
+
- Integration testing and approval gates
|
|
128
136
|
|
|
129
137
|
## Configuration Options
|
|
130
138
|
|
|
@@ -135,7 +143,7 @@ const appDefinition = {
|
|
|
135
143
|
// Basic configuration
|
|
136
144
|
name: 'my-frigg-app',
|
|
137
145
|
provider: 'aws',
|
|
138
|
-
|
|
146
|
+
|
|
139
147
|
// VPC configuration
|
|
140
148
|
vpc: {
|
|
141
149
|
enable: true,
|
|
@@ -144,22 +152,23 @@ const appDefinition = {
|
|
|
144
152
|
subnetIds: [...], // Optional: custom subnets
|
|
145
153
|
enableVPCEndpoints: true // Optional: create VPC endpoints
|
|
146
154
|
},
|
|
147
|
-
|
|
155
|
+
|
|
148
156
|
// KMS encryption
|
|
149
157
|
encryption: {
|
|
150
|
-
|
|
158
|
+
fieldLevelEncryptionMethod: 'kms',
|
|
159
|
+
createResourceIfNoneFound: true
|
|
151
160
|
},
|
|
152
|
-
|
|
161
|
+
|
|
153
162
|
// SSM Parameter Store
|
|
154
163
|
ssm: {
|
|
155
164
|
enable: true
|
|
156
165
|
},
|
|
157
|
-
|
|
166
|
+
|
|
158
167
|
// WebSocket support (Phase 3)
|
|
159
168
|
websockets: {
|
|
160
169
|
enable: true
|
|
161
170
|
},
|
|
162
|
-
|
|
171
|
+
|
|
163
172
|
// Integrations
|
|
164
173
|
integrations: [
|
|
165
174
|
{ Definition: { name: 'hubspot' } },
|
|
@@ -195,10 +204,8 @@ SERVICE_NAME=my-frigg-app
|
|
|
195
204
|
const { composeServerlessDefinition } = require('./serverless-template');
|
|
196
205
|
|
|
197
206
|
const appDefinition = {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
{ Definition: { name: 'hubspot' } }
|
|
201
|
-
]
|
|
207
|
+
name: 'my-app',
|
|
208
|
+
integrations: [{ Definition: { name: 'hubspot' } }],
|
|
202
209
|
};
|
|
203
210
|
|
|
204
211
|
const serverlessConfig = await composeServerlessDefinition(appDefinition);
|
|
@@ -209,13 +216,11 @@ const serverlessConfig = await composeServerlessDefinition(appDefinition);
|
|
|
209
216
|
|
|
210
217
|
```javascript
|
|
211
218
|
const appDefinition = {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
{ Definition: { name: 'salesforce' } }
|
|
218
|
-
]
|
|
219
|
+
name: 'secure-app',
|
|
220
|
+
vpc: { enable: true },
|
|
221
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
222
|
+
ssm: { enable: true },
|
|
223
|
+
integrations: [{ Definition: { name: 'salesforce' } }],
|
|
219
224
|
};
|
|
220
225
|
|
|
221
226
|
const serverlessConfig = await composeServerlessDefinition(appDefinition);
|
|
@@ -225,12 +230,10 @@ const serverlessConfig = await composeServerlessDefinition(appDefinition);
|
|
|
225
230
|
|
|
226
231
|
```javascript
|
|
227
232
|
const appDefinition = {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
{ Definition: { name: 'slack' } }
|
|
233
|
-
]
|
|
233
|
+
name: 'realtime-app',
|
|
234
|
+
websockets: { enable: true },
|
|
235
|
+
vpc: { enable: true },
|
|
236
|
+
integrations: [{ Definition: { name: 'slack' } }],
|
|
234
237
|
};
|
|
235
238
|
|
|
236
239
|
const serverlessConfig = await composeServerlessDefinition(appDefinition);
|
|
@@ -259,19 +262,21 @@ npm test -- --watch
|
|
|
259
262
|
### Test Categories
|
|
260
263
|
|
|
261
264
|
1. **Unit Tests**: Test individual components
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
+
|
|
266
|
+
- AWS discovery utilities
|
|
267
|
+
- Serverless template generation
|
|
268
|
+
- IAM policy generation
|
|
265
269
|
|
|
266
270
|
2. **Integration Tests**: Test end-to-end workflows
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
271
|
+
|
|
272
|
+
- Complete discovery and template generation
|
|
273
|
+
- Plugin integration
|
|
274
|
+
- Phase 3 infrastructure validation
|
|
270
275
|
|
|
271
276
|
3. **Performance Tests**: Validate infrastructure limits
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
277
|
+
- CloudFormation template sizes
|
|
278
|
+
- Resource count limits
|
|
279
|
+
- Cross-stack dependencies
|
|
275
280
|
|
|
276
281
|
### Mock Data
|
|
277
282
|
|
|
@@ -279,11 +284,12 @@ Tests use mock AWS resources to avoid real AWS API calls:
|
|
|
279
284
|
|
|
280
285
|
```javascript
|
|
281
286
|
const mockAWSResources = {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
+
defaultVpcId: 'vpc-12345678',
|
|
288
|
+
defaultSecurityGroupId: 'sg-12345678',
|
|
289
|
+
privateSubnetId1: 'subnet-private-1',
|
|
290
|
+
privateSubnetId2: 'subnet-private-2',
|
|
291
|
+
defaultKmsKeyId:
|
|
292
|
+
'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
|
|
287
293
|
};
|
|
288
294
|
```
|
|
289
295
|
|
|
@@ -293,18 +299,18 @@ const mockAWSResources = {
|
|
|
293
299
|
|
|
294
300
|
The infrastructure requires specific IAM permissions for AWS resource discovery and deployment:
|
|
295
301
|
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
-
|
|
299
|
-
-
|
|
300
|
-
-
|
|
301
|
-
-
|
|
302
|
-
-
|
|
303
|
-
-
|
|
304
|
-
-
|
|
305
|
-
-
|
|
306
|
-
-
|
|
307
|
-
-
|
|
302
|
+
- **EC2**: Describe VPCs, subnets, security groups, route tables
|
|
303
|
+
- **KMS**: List keys, describe keys
|
|
304
|
+
- **STS**: Get caller identity
|
|
305
|
+
- **CloudFormation**: Full access for stack operations
|
|
306
|
+
- **Lambda**: Function management
|
|
307
|
+
- **API Gateway**: API management
|
|
308
|
+
- **S3**: Bucket and object operations (including tagging)
|
|
309
|
+
- **DynamoDB**: Table operations
|
|
310
|
+
- **SQS**: Queue operations
|
|
311
|
+
- **SNS**: Topic operations
|
|
312
|
+
- **CloudWatch**: Metrics and alarms
|
|
313
|
+
- **IAM**: Role and policy management
|
|
308
314
|
|
|
309
315
|
### Best Practices
|
|
310
316
|
|
|
@@ -348,6 +354,8 @@ serverless print
|
|
|
348
354
|
aws cloudformation validate-template --template-body file://template.json
|
|
349
355
|
```
|
|
350
356
|
|
|
357
|
+
- **Connectivity to external services (e.g., databases):** If your Lambda functions in a VPC cannot connect to external services, ensure that the `FriggLambdaSecurityGroup` has the correct **egress** rules to allow outbound traffic on the required ports (e.g., port 27017 for MongoDB).
|
|
358
|
+
|
|
351
359
|
#### Infrastructure Test Failures
|
|
352
360
|
|
|
353
361
|
```bash
|
|
@@ -364,19 +372,22 @@ npm run test:debug
|
|
|
364
372
|
### Performance Optimization
|
|
365
373
|
|
|
366
374
|
#### Lambda Cold Starts
|
|
367
|
-
|
|
368
|
-
-
|
|
369
|
-
-
|
|
375
|
+
|
|
376
|
+
- Use provisioned concurrency for critical functions
|
|
377
|
+
- Optimize function size and dependencies
|
|
378
|
+
- Monitor cold start metrics
|
|
370
379
|
|
|
371
380
|
#### VPC Performance
|
|
372
|
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
381
|
+
|
|
382
|
+
- Use VPC endpoints to reduce NAT Gateway costs
|
|
383
|
+
- Monitor ENI creation/deletion times
|
|
384
|
+
- Consider Lambda@Edge for global distribution
|
|
375
385
|
|
|
376
386
|
#### Cost Optimization
|
|
377
|
-
|
|
378
|
-
-
|
|
379
|
-
-
|
|
387
|
+
|
|
388
|
+
- Use S3 Intelligent Tiering
|
|
389
|
+
- Configure CloudWatch log retention
|
|
390
|
+
- Monitor and alert on unexpected usage
|
|
380
391
|
|
|
381
392
|
## Contributing
|
|
382
393
|
|
|
@@ -405,17 +416,17 @@ npm run test:debug
|
|
|
405
416
|
|
|
406
417
|
## Support
|
|
407
418
|
|
|
408
|
-
-
|
|
409
|
-
-
|
|
410
|
-
-
|
|
411
|
-
-
|
|
412
|
-
-
|
|
419
|
+
- **Documentation**: See `PHASE3-DEPLOYMENT-GUIDE.md` for detailed deployment instructions
|
|
420
|
+
- **Testing**: See `README-TESTING.md` for testing strategy
|
|
421
|
+
- **Troubleshooting**: See `AWS-DISCOVERY-TROUBLESHOOTING.md` for common issues
|
|
422
|
+
- **Issues**: Create GitHub issues for bugs and feature requests
|
|
423
|
+
- **Discussions**: Use GitHub Discussions for questions and ideas
|
|
413
424
|
|
|
414
425
|
## Related Documentation
|
|
415
426
|
|
|
416
|
-
-
|
|
417
|
-
-
|
|
418
|
-
-
|
|
419
|
-
-
|
|
420
|
-
-
|
|
421
|
-
-
|
|
427
|
+
- [Phase 3 Deployment Guide](./PHASE3-DEPLOYMENT-GUIDE.md)
|
|
428
|
+
- [Testing Strategy](./README-TESTING.md)
|
|
429
|
+
- [AWS Discovery Troubleshooting](./AWS-DISCOVERY-TROUBLESHOOTING.md)
|
|
430
|
+
- [IAM Policy Templates](./IAM-POLICY-TEMPLATES.md)
|
|
431
|
+
- [VPC Configuration](./VPC-CONFIGURATION.md)
|
|
432
|
+
- [WebSocket Configuration](./WEBSOCKET-CONFIGURATION.md)
|
|
@@ -151,7 +151,7 @@ const mockAppDefinitions = {
|
|
|
151
151
|
|
|
152
152
|
kmsOnly: {
|
|
153
153
|
name: 'kms-test-app',
|
|
154
|
-
encryption: {
|
|
154
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
155
155
|
integrations: []
|
|
156
156
|
},
|
|
157
157
|
|
|
@@ -164,7 +164,7 @@ const mockAppDefinitions = {
|
|
|
164
164
|
allFeatures: {
|
|
165
165
|
name: 'full-feature-app',
|
|
166
166
|
vpc: { enable: true },
|
|
167
|
-
encryption: {
|
|
167
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
168
168
|
ssm: { enable: true },
|
|
169
169
|
integrations: [{
|
|
170
170
|
Definition: {
|
|
@@ -281,7 +281,7 @@ const mockEnvironmentVariables = {
|
|
|
281
281
|
AWS_DISCOVERY_SUBNET_ID_1: mockSubnets[0].SubnetId,
|
|
282
282
|
AWS_DISCOVERY_SUBNET_ID_2: mockSubnets[1].SubnetId,
|
|
283
283
|
AWS_DISCOVERY_ROUTE_TABLE_ID: mockRouteTables[0].RouteTableId,
|
|
284
|
-
AWS_DISCOVERY_KMS_KEY_ID:
|
|
284
|
+
AWS_DISCOVERY_KMS_KEY_ID:mockKmsKeyMetadata.Arn
|
|
285
285
|
};
|
|
286
286
|
|
|
287
287
|
// Fallback environment variables for error scenarios
|
|
@@ -291,7 +291,7 @@ const mockFallbackEnvironmentVariables = {
|
|
|
291
291
|
AWS_DISCOVERY_SUBNET_ID_1: 'subnet-fallback-1',
|
|
292
292
|
AWS_DISCOVERY_SUBNET_ID_2: 'subnet-fallback-2',
|
|
293
293
|
AWS_DISCOVERY_ROUTE_TABLE_ID: 'rtb-fallback',
|
|
294
|
-
AWS_DISCOVERY_KMS_KEY_ID:
|
|
294
|
+
AWS_DISCOVERY_KMS_KEY_ID:'arn:aws:kms:*:*:key/*'
|
|
295
295
|
};
|
|
296
296
|
|
|
297
297
|
// Mock AWS SDK responses
|
|
@@ -115,7 +115,7 @@ function createMockAppDefinition(features = {}, integrations = []) {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
if (features.kms) {
|
|
118
|
-
appDefinition.encryption = {
|
|
118
|
+
appDefinition.encryption = { fieldLevelEncryptionMethod: 'kms' };
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
if (features.ssm) {
|
|
@@ -453,18 +453,16 @@ class AWSDiscovery {
|
|
|
453
453
|
|
|
454
454
|
/**
|
|
455
455
|
* Find the default KMS key for the account
|
|
456
|
-
* @returns {Promise<string>} KMS key ARN or
|
|
456
|
+
* @returns {Promise<string|null>} KMS key ARN or null if no key found
|
|
457
457
|
*/
|
|
458
458
|
async findDefaultKmsKey() {
|
|
459
459
|
try {
|
|
460
|
-
// First try to find a key with alias/aws/lambda
|
|
461
460
|
const command = new ListKeysCommand({});
|
|
462
461
|
const response = await this.kmsClient.send(command);
|
|
463
462
|
|
|
464
463
|
if (!response.Keys || response.Keys.length === 0) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
return `arn:aws:kms:${this.region}:${accountId}:key/*`;
|
|
464
|
+
console.log('No KMS keys found in account');
|
|
465
|
+
return null;
|
|
468
466
|
}
|
|
469
467
|
|
|
470
468
|
// Look for customer managed keys first
|
|
@@ -476,21 +474,21 @@ class AWSDiscovery {
|
|
|
476
474
|
if (keyDetails.KeyMetadata &&
|
|
477
475
|
keyDetails.KeyMetadata.KeyManager === 'CUSTOMER' &&
|
|
478
476
|
keyDetails.KeyMetadata.KeyState === 'Enabled') {
|
|
477
|
+
console.log(`Found customer managed KMS key: ${keyDetails.KeyMetadata.Arn}`);
|
|
479
478
|
return keyDetails.KeyMetadata.Arn;
|
|
480
479
|
}
|
|
481
480
|
} catch (error) {
|
|
482
481
|
// Continue to next key if we can't describe this one
|
|
482
|
+
console.warn(`Could not describe key ${key.KeyId}:`, error.message);
|
|
483
483
|
continue;
|
|
484
484
|
}
|
|
485
485
|
}
|
|
486
486
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
return `arn:aws:kms:${this.region}:${accountId}:key/*`;
|
|
487
|
+
console.log('No customer managed KMS keys found');
|
|
488
|
+
return null;
|
|
490
489
|
} catch (error) {
|
|
491
490
|
console.error('Error finding default KMS key:', error);
|
|
492
|
-
|
|
493
|
-
return '*';
|
|
491
|
+
return null;
|
|
494
492
|
}
|
|
495
493
|
}
|
|
496
494
|
|
|
@@ -503,7 +501,7 @@ class AWSDiscovery {
|
|
|
503
501
|
* @returns {string} return.privateSubnetId2 - Second private subnet ID
|
|
504
502
|
* @returns {string} return.publicSubnetId - Public subnet ID for NAT Gateway
|
|
505
503
|
* @returns {string} return.privateRouteTableId - Private route table ID
|
|
506
|
-
* @returns {string} return.defaultKmsKeyId - Default KMS key ARN
|
|
504
|
+
* @returns {string|null} return.defaultKmsKeyId - Default KMS key ARN or null if not found
|
|
507
505
|
* @throws {Error} If resource discovery fails
|
|
508
506
|
*/
|
|
509
507
|
async discoverResources() {
|
|
@@ -526,7 +524,11 @@ class AWSDiscovery {
|
|
|
526
524
|
console.log(`Found route table: ${routeTable.RouteTableId}`);
|
|
527
525
|
|
|
528
526
|
const kmsKeyArn = await this.findDefaultKmsKey();
|
|
529
|
-
|
|
527
|
+
if (kmsKeyArn) {
|
|
528
|
+
console.log(`Found KMS key: ${kmsKeyArn}`);
|
|
529
|
+
} else {
|
|
530
|
+
console.log('No KMS key found');
|
|
531
|
+
}
|
|
530
532
|
|
|
531
533
|
// Try to find existing NAT Gateway
|
|
532
534
|
const existingNatGateway = await this.findExistingNatGateway(vpc.VpcId);
|
|
@@ -137,8 +137,8 @@ class BuildTimeDiscovery {
|
|
|
137
137
|
console.log('Running pre-build AWS discovery hook...');
|
|
138
138
|
|
|
139
139
|
// Only run discovery if VPC, KMS, or SSM features are enabled
|
|
140
|
-
const needsDiscovery = appDefinition.vpc?.enable ||
|
|
141
|
-
appDefinition.encryption?.
|
|
140
|
+
const needsDiscovery = appDefinition.vpc?.enable ||
|
|
141
|
+
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms' ||
|
|
142
142
|
appDefinition.ssm?.enable;
|
|
143
143
|
|
|
144
144
|
if (!needsDiscovery) {
|
|
@@ -159,7 +159,7 @@ class BuildTimeDiscovery {
|
|
|
159
159
|
AWS_DISCOVERY_SUBNET_ID_2: resources.privateSubnetId2,
|
|
160
160
|
AWS_DISCOVERY_PUBLIC_SUBNET_ID: resources.publicSubnetId,
|
|
161
161
|
AWS_DISCOVERY_ROUTE_TABLE_ID: resources.privateRouteTableId,
|
|
162
|
-
AWS_DISCOVERY_KMS_KEY_ID: resources.defaultKmsKeyId
|
|
162
|
+
AWS_DISCOVERY_KMS_KEY_ID: resources.defaultKmsKeyId // Keep consistent naming convention (even though it's an ARN)
|
|
163
163
|
};
|
|
164
164
|
|
|
165
165
|
// Set environment variables for serverless to use
|
|
@@ -250,7 +250,7 @@ describe('BuildTimeDiscovery', () => {
|
|
|
250
250
|
|
|
251
251
|
it('should run discovery when KMS is enabled', async () => {
|
|
252
252
|
const appDefinition = {
|
|
253
|
-
encryption: {
|
|
253
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
254
254
|
integrations: []
|
|
255
255
|
};
|
|
256
256
|
|
|
@@ -35,7 +35,7 @@ function generateIAMCloudFormation(appDefinition, options = {}) {
|
|
|
35
35
|
vpc: appDefinition.vpc?.enable === true,
|
|
36
36
|
kms:
|
|
37
37
|
appDefinition.encryption
|
|
38
|
-
?.
|
|
38
|
+
?.fieldLevelEncryptionMethod === 'kms',
|
|
39
39
|
ssm: appDefinition.ssm?.enable === true,
|
|
40
40
|
websockets: appDefinition.websockets?.enable === true,
|
|
41
41
|
};
|
|
@@ -605,6 +605,19 @@ function generateIAMCloudFormation(appDefinition, options = {}) {
|
|
|
605
605
|
},
|
|
606
606
|
},
|
|
607
607
|
},
|
|
608
|
+
{
|
|
609
|
+
Sid: 'FriggKMSManagement',
|
|
610
|
+
Effect: 'Allow',
|
|
611
|
+
Action: [
|
|
612
|
+
'kms:CreateKey',
|
|
613
|
+
'kms:PutKeyPolicy',
|
|
614
|
+
'kms:EnableKeyRotation',
|
|
615
|
+
'kms:TagResource',
|
|
616
|
+
'kms:UntagResource',
|
|
617
|
+
'kms:ListResourceTags',
|
|
618
|
+
],
|
|
619
|
+
Resource: '*',
|
|
620
|
+
},
|
|
608
621
|
],
|
|
609
622
|
},
|
|
610
623
|
},
|
|
@@ -724,8 +737,7 @@ function getFeatureSummary(appDefinition) {
|
|
|
724
737
|
core: true, // Always enabled
|
|
725
738
|
vpc: appDefinition.vpc?.enable === true,
|
|
726
739
|
kms:
|
|
727
|
-
appDefinition.encryption?.
|
|
728
|
-
true,
|
|
740
|
+
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms',
|
|
729
741
|
ssm: appDefinition.ssm?.enable === true,
|
|
730
742
|
websockets: appDefinition.websockets?.enable === true,
|
|
731
743
|
};
|
|
@@ -7,7 +7,7 @@ describe('IAM Generator', () => {
|
|
|
7
7
|
name: 'test-app',
|
|
8
8
|
integrations: ['Integration1', 'Integration2'],
|
|
9
9
|
vpc: { enable: true },
|
|
10
|
-
encryption: {
|
|
10
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
11
11
|
ssm: { enable: true },
|
|
12
12
|
websockets: { enable: true }
|
|
13
13
|
};
|
|
@@ -46,7 +46,7 @@ describe('IAM Generator', () => {
|
|
|
46
46
|
name: 'test-app',
|
|
47
47
|
integrations: [],
|
|
48
48
|
vpc: { enable: false },
|
|
49
|
-
encryption: {
|
|
49
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
50
50
|
ssm: { enable: false },
|
|
51
51
|
websockets: { enable: false }
|
|
52
52
|
};
|
|
@@ -77,7 +77,7 @@ describe('IAM Generator', () => {
|
|
|
77
77
|
const appDefinition = {
|
|
78
78
|
name: 'test-app',
|
|
79
79
|
integrations: [],
|
|
80
|
-
encryption: {
|
|
80
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' }
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
const yaml = generateIAMCloudFormation(appDefinition);
|
|
@@ -106,7 +106,7 @@ describe('IAM Generator', () => {
|
|
|
106
106
|
name: 'test-app',
|
|
107
107
|
integrations: [],
|
|
108
108
|
vpc: { enable: true },
|
|
109
|
-
encryption: {
|
|
109
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
110
110
|
ssm: { enable: true }
|
|
111
111
|
};
|
|
112
112
|
|