@friggframework/devtools 2.0.0-next.10 → 2.0.0-next.101
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/README.md +1289 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +279 -0
- package/frigg-cli/__tests__/unit/commands/db-setup.test.js +649 -0
- package/frigg-cli/__tests__/unit/commands/deploy.test.js +320 -0
- package/frigg-cli/__tests__/unit/commands/doctor.test.js +309 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +400 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +346 -0
- package/frigg-cli/__tests__/unit/dependencies.test.js +74 -0
- package/frigg-cli/__tests__/unit/utils/database-validator.test.js +397 -0
- package/frigg-cli/__tests__/unit/utils/error-messages.test.js +345 -0
- package/frigg-cli/__tests__/unit/version-detection.test.js +171 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/prisma-mock.js +194 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +287 -0
- package/frigg-cli/auth-command/CLAUDE.md +293 -0
- package/frigg-cli/auth-command/README.md +450 -0
- package/frigg-cli/auth-command/api-key-flow.js +153 -0
- package/frigg-cli/auth-command/auth-tester.js +344 -0
- package/frigg-cli/auth-command/credential-storage.js +182 -0
- package/frigg-cli/auth-command/index.js +256 -0
- package/frigg-cli/auth-command/json-schema-form.js +67 -0
- package/frigg-cli/auth-command/module-loader.js +172 -0
- package/frigg-cli/auth-command/oauth-callback-server.js +431 -0
- package/frigg-cli/auth-command/oauth-flow.js +195 -0
- package/frigg-cli/auth-command/utils/browser.js +30 -0
- package/frigg-cli/build-command/index.js +45 -12
- package/frigg-cli/db-setup-command/index.js +246 -0
- package/frigg-cli/deploy-command/SPEC-DEPLOY-DRY-RUN.md +981 -0
- package/frigg-cli/deploy-command/index.js +295 -23
- package/frigg-cli/doctor-command/index.js +335 -0
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +301 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/generate-iam-command.js +118 -0
- package/frigg-cli/index.js +174 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/jest.config.js +124 -0
- package/frigg-cli/package.json +63 -0
- package/frigg-cli/repair-command/index.js +564 -0
- package/frigg-cli/start-command/index.js +118 -5
- package/frigg-cli/start-command/start-command.test.js +297 -0
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +16 -17
- package/frigg-cli/utils/database-validator.js +167 -0
- package/frigg-cli/utils/error-messages.js +329 -0
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/ARCHITECTURE.md +487 -0
- package/infrastructure/CLAUDE.md +481 -0
- package/infrastructure/HEALTH.md +468 -0
- package/infrastructure/README.md +522 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/__tests__/postgres-config.test.js +914 -0
- package/infrastructure/__tests__/template-generation.test.js +687 -0
- package/infrastructure/create-frigg-infrastructure.js +129 -20
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
- package/infrastructure/docs/PRE-DEPLOYMENT-HEALTH-CHECK-SPEC.md +1317 -0
- package/infrastructure/docs/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/docs/deployment-instructions.md +268 -0
- package/infrastructure/docs/generate-iam-command.md +278 -0
- package/infrastructure/docs/iam-policy-templates.md +193 -0
- package/infrastructure/domains/admin-scripts/admin-script-builder.js +330 -0
- package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +628 -0
- package/infrastructure/domains/admin-scripts/index.js +5 -0
- package/infrastructure/domains/database/aurora-builder.js +857 -0
- package/infrastructure/domains/database/aurora-builder.test.js +960 -0
- package/infrastructure/domains/database/aurora-discovery.js +87 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- package/infrastructure/domains/database/aurora-resolver.js +210 -0
- package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
- package/infrastructure/domains/database/migration-builder.js +715 -0
- package/infrastructure/domains/database/migration-builder.test.js +322 -0
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
- package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
- package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
- package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
- package/infrastructure/domains/health/application/ports/index.js +26 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
- package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
- package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
- package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
- package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
- package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
- package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
- package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
- package/infrastructure/domains/health/domain/entities/issue.js +299 -0
- package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
- package/infrastructure/domains/health/domain/entities/resource.js +159 -0
- package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
- package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
- package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
- package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
- package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
- package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
- package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
- package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
- package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
- package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
- package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
- package/infrastructure/domains/integration/integration-builder.js +596 -0
- package/infrastructure/domains/integration/integration-builder.test.js +939 -0
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-builder.js +2051 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +1960 -0
- package/infrastructure/domains/networking/vpc-discovery.js +177 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
- package/infrastructure/domains/networking/vpc-resolver.js +505 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +801 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/domains/scheduler/scheduler-builder.js +211 -0
- package/infrastructure/domains/security/iam-generator.js +816 -0
- package/infrastructure/domains/security/iam-generator.test.js +204 -0
- package/infrastructure/domains/security/kms-builder.js +415 -0
- package/infrastructure/domains/security/kms-builder.test.js +392 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +177 -0
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/security/templates/frigg-deployment-iam-stack.yaml +401 -0
- package/infrastructure/domains/security/templates/iam-policy-basic.json +218 -0
- package/infrastructure/domains/security/templates/iam-policy-full.json +288 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.js +681 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +1320 -0
- package/infrastructure/domains/shared/environment-builder.js +119 -0
- package/infrastructure/domains/shared/environment-builder.test.js +247 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +579 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +416 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.enhanced.test.js +306 -0
- package/infrastructure/domains/shared/resource-discovery.js +256 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +757 -0
- package/infrastructure/domains/shared/types/app-definition.js +225 -0
- package/infrastructure/domains/shared/types/discovery-result.js +106 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
- package/infrastructure/domains/shared/types/index.js +46 -0
- package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
- package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +418 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +291 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +159 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +444 -0
- package/infrastructure/domains/shared/validation/env-validator.js +78 -0
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/domains/shared/validation/plugin-validator.js +187 -0
- package/infrastructure/domains/shared/validation/plugin-validator.test.js +323 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +121 -0
- package/infrastructure/infrastructure-composer.test.js +1896 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/scripts/build-prisma-layer.js +701 -0
- package/infrastructure/scripts/build-prisma-layer.test.js +170 -0
- package/infrastructure/scripts/build-time-discovery.js +238 -0
- package/infrastructure/scripts/build-time-discovery.test.js +379 -0
- package/infrastructure/scripts/run-discovery.js +110 -0
- package/infrastructure/scripts/verify-prisma-layer.js +72 -0
- package/management-ui/README.md +203 -0
- package/package.json +47 -16
- package/test/index.js +2 -4
- package/test/mock-api.js +1 -3
- package/test/mock-integration.js +4 -14
- package/.eslintrc.json +0 -3
- package/CHANGELOG.md +0 -132
- package/infrastructure/serverless-template.js +0 -283
- package/infrastructure/webpack.config.js +0 -20
- package/test/auther-definition-tester.js +0 -125
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Frigg IAM Policy Templates
|
|
2
|
+
|
|
3
|
+
This directory contains IAM policy templates for deploying Frigg applications with the appropriate permissions.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
For immediate deployment, you have two ready-to-use IAM policy options:
|
|
8
|
+
|
|
9
|
+
### Option 1: Basic Policy (Recommended for getting started)
|
|
10
|
+
```bash
|
|
11
|
+
# Use the basic policy for core Frigg functionality
|
|
12
|
+
aws iam put-user-policy \
|
|
13
|
+
--user-name frigg-deployment-user \
|
|
14
|
+
--policy-name FriggBasicDeploymentPolicy \
|
|
15
|
+
--policy-document file://domains/security/templates/iam-policy-basic.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Includes permissions for:**
|
|
19
|
+
- ✅ AWS Discovery (finding your VPC, subnets, security groups)
|
|
20
|
+
- ✅ CloudFormation stacks (deploy/update Frigg applications)
|
|
21
|
+
- ✅ Lambda functions (create and manage serverless functions)
|
|
22
|
+
- ✅ Lambda EventSourceMappings (connect Lambda to SQS, SNS, Kinesis)
|
|
23
|
+
- ✅ API Gateway (HTTP endpoints for your integrations)
|
|
24
|
+
- ✅ SQS/SNS (message queues and notifications)
|
|
25
|
+
- ✅ S3 (deployment artifacts, including bucket tagging)
|
|
26
|
+
- ✅ CloudWatch/Logs (monitoring and logging)
|
|
27
|
+
- ✅ IAM roles (Lambda execution roles)
|
|
28
|
+
|
|
29
|
+
### Option 2: Full Policy (All features enabled)
|
|
30
|
+
```bash
|
|
31
|
+
# Use the full policy for advanced Frigg features
|
|
32
|
+
aws iam put-user-policy \
|
|
33
|
+
--user-name frigg-deployment-user \
|
|
34
|
+
--policy-name FriggFullDeploymentPolicy \
|
|
35
|
+
--policy-document file://domains/security/templates/iam-policy-full.json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Includes everything from Basic Policy PLUS:**
|
|
39
|
+
- ✅ **VPC Management** - Create route tables, NAT gateways, VPC endpoints
|
|
40
|
+
- ✅ **KMS Encryption** - Field-level encryption for sensitive data
|
|
41
|
+
- ✅ **SSM Parameter Store** - Secure configuration management
|
|
42
|
+
|
|
43
|
+
## When to Use Which Policy
|
|
44
|
+
|
|
45
|
+
### Use Basic Policy When:
|
|
46
|
+
- Getting started with Frigg
|
|
47
|
+
- Building simple integrations without VPC requirements
|
|
48
|
+
- You want minimal AWS permissions
|
|
49
|
+
- You're not handling sensitive data requiring encryption
|
|
50
|
+
|
|
51
|
+
### Use Full Policy When:
|
|
52
|
+
- You need VPC isolation for security/compliance
|
|
53
|
+
- You're handling sensitive data requiring KMS encryption
|
|
54
|
+
- You want to use SSM Parameter Store for configuration
|
|
55
|
+
- You're deploying production applications
|
|
56
|
+
|
|
57
|
+
## Current Issue Resolution
|
|
58
|
+
|
|
59
|
+
**If you're seeing the error:** `User is not authorized to perform: ec2:CreateRouteTable`
|
|
60
|
+
|
|
61
|
+
This means your current deployment user doesn't have VPC permissions. You have two options:
|
|
62
|
+
|
|
63
|
+
### Quick Fix: Apply Full Policy
|
|
64
|
+
```bash
|
|
65
|
+
aws iam put-user-policy \
|
|
66
|
+
--user-name frigg-deployment-user \
|
|
67
|
+
--policy-name FriggFullDeploymentPolicy \
|
|
68
|
+
--policy-document file://domains/security/templates/iam-policy-full.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Alternative: Update CloudFormation Stack
|
|
72
|
+
If you deployed using the CloudFormation template, update it with VPC support:
|
|
73
|
+
```bash
|
|
74
|
+
aws cloudformation update-stack \
|
|
75
|
+
--stack-name frigg-deployment-iam \
|
|
76
|
+
--template-body file://domains/security/templates/frigg-deployment-iam-stack.yaml \
|
|
77
|
+
--parameters ParameterKey=EnableVPCSupport,ParameterValue=true \
|
|
78
|
+
--capabilities CAPABILITY_IAM
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Using the IAM Generator
|
|
82
|
+
|
|
83
|
+
For custom policy generation based on your app definition:
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const { generateIAMPolicy, generateIAMCloudFormation, getFeatureSummary } = require('./iam-generator');
|
|
87
|
+
|
|
88
|
+
// Generate basic JSON policy
|
|
89
|
+
const basicPolicy = generateIAMPolicy('basic');
|
|
90
|
+
|
|
91
|
+
// Generate full JSON policy
|
|
92
|
+
const fullPolicy = generateIAMPolicy('full');
|
|
93
|
+
|
|
94
|
+
// Generate CloudFormation template with auto-detected features
|
|
95
|
+
const summary = getFeatureSummary(appDefinition);
|
|
96
|
+
const template = generateIAMCloudFormation({
|
|
97
|
+
appName: summary.appName,
|
|
98
|
+
features: summary.features,
|
|
99
|
+
userPrefix: 'frigg-deployment-user',
|
|
100
|
+
stackName: 'frigg-deployment-iam'
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Or manually specify features
|
|
104
|
+
const customTemplate = generateIAMCloudFormation({
|
|
105
|
+
appName: 'my-app',
|
|
106
|
+
features: {
|
|
107
|
+
vpc: true,
|
|
108
|
+
kms: true,
|
|
109
|
+
ssm: true,
|
|
110
|
+
websockets: false
|
|
111
|
+
},
|
|
112
|
+
userPrefix: 'my-deployment-user',
|
|
113
|
+
stackName: 'my-deployment-stack'
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Feature Detection
|
|
118
|
+
|
|
119
|
+
Use `getFeatureSummary(appDefinition)` to automatically detect features from your app definition:
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
const summary = getFeatureSummary(appDefinition);
|
|
123
|
+
// Returns: { appName, features: { core, vpc, kms, ssm, websockets }, integrationCount }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Security Best Practices
|
|
127
|
+
|
|
128
|
+
### Resource Scoping
|
|
129
|
+
Both policies are scoped to resources containing "frigg" in their names:
|
|
130
|
+
- ✅ `my-frigg-app-prod` (will work)
|
|
131
|
+
- ❌ `my-integration-app` (won't work - missing "frigg")
|
|
132
|
+
|
|
133
|
+
### Account-Specific Resources
|
|
134
|
+
Replace `*` with your AWS account ID for tighter security:
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"Resource": [
|
|
138
|
+
"arn:aws:lambda:us-east-1:123456789012:function:*frigg*"
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Environment-Specific Policies
|
|
144
|
+
Consider separate policies for different environments:
|
|
145
|
+
- `frigg-dev-policy` (full permissions for development)
|
|
146
|
+
- `frigg-prod-policy` (restricted permissions for production)
|
|
147
|
+
|
|
148
|
+
## Troubleshooting
|
|
149
|
+
|
|
150
|
+
### Common Permission Errors
|
|
151
|
+
|
|
152
|
+
1. **"ec2:CreateRouteTable" error** → Use Full Policy
|
|
153
|
+
2. **"kms:GenerateDataKey" error** → Enable KMS in your policy
|
|
154
|
+
3. **"ssm:GetParameter" error** → Enable SSM in your policy
|
|
155
|
+
4. **Lambda VPC errors** → Ensure VPC permissions are enabled
|
|
156
|
+
5. **"lambda:DeleteEventSourceMapping" error** → Update to latest policy (includes EventSourceMapping permissions)
|
|
157
|
+
6. **"ec2:DeleteVpcEndpoints" error** → Update IAM policy to use `ec2:DeleteVpcEndpoints` (plural) instead of `ec2:DeleteVpcEndpoint`
|
|
158
|
+
7. **"s3:PutBucketTagging" error** → Update to latest policy (includes S3 bucket tagging permissions)
|
|
159
|
+
|
|
160
|
+
### Validation
|
|
161
|
+
Test your policy by deploying a simple Frigg app:
|
|
162
|
+
```bash
|
|
163
|
+
npx create-frigg-app test-deployment
|
|
164
|
+
cd test-deployment
|
|
165
|
+
frigg deploy
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Policy Comparison
|
|
169
|
+
|
|
170
|
+
| Feature | Basic Policy | Full Policy | CloudFormation Template |
|
|
171
|
+
|---------|--------------|-------------|-------------------------|
|
|
172
|
+
| Core Deployment | ✅ | ✅ | ✅ |
|
|
173
|
+
| VPC Management | ❌ | ✅ | ✅ (conditional) |
|
|
174
|
+
| KMS Encryption | ❌ | ✅ | ✅ (conditional) |
|
|
175
|
+
| SSM Parameters | ❌ | ✅ | ✅ (conditional) |
|
|
176
|
+
| Format | JSON | JSON | YAML with parameters |
|
|
177
|
+
| Use Case | Getting started | Production ready | Infrastructure as Code |
|
|
178
|
+
|
|
179
|
+
## Files in this Directory
|
|
180
|
+
|
|
181
|
+
- `../domains/security/templates/iam-policy-basic.json` - Core Frigg permissions only (JSON format)
|
|
182
|
+
- `../domains/security/templates/iam-policy-full.json` - All features enabled (JSON format)
|
|
183
|
+
- `../domains/security/templates/frigg-deployment-iam-stack.yaml` - CloudFormation template with conditional parameters
|
|
184
|
+
- `../domains/security/iam-generator.js` - Programmatic policy generation with basic/full/auto modes
|
|
185
|
+
- This file (`iam-policy-templates.md`) - Quick start guide and usage examples
|
|
186
|
+
|
|
187
|
+
## Support
|
|
188
|
+
|
|
189
|
+
If you encounter permission issues:
|
|
190
|
+
1. Check the error message for the specific missing permission
|
|
191
|
+
2. Verify your resource names contain "frigg"
|
|
192
|
+
3. Consider upgrading from Basic to Full policy
|
|
193
|
+
4. Review the AWS-IAM-CREDENTIAL-NEEDS.md for detailed explanations
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Script Builder
|
|
3
|
+
*
|
|
4
|
+
* Domain Layer - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Responsible for:
|
|
7
|
+
* - Creating SQS queue for admin script execution
|
|
8
|
+
* - Creating Lambda function for script execution (worker)
|
|
9
|
+
* - Creating Lambda function for admin API routes (router)
|
|
10
|
+
* - Creating EventBridge Scheduler resources (Phase 2)
|
|
11
|
+
* - Creating IAM roles for scheduler to invoke Lambda
|
|
12
|
+
* - Granting the router/executor Lambdas IAM permission to send to the queue
|
|
13
|
+
* and (when scheduling is enabled) manage EventBridge schedules
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { InfrastructureBuilder, ValidationResult } = require('../shared/base-builder');
|
|
17
|
+
|
|
18
|
+
class AdminScriptBuilder extends InfrastructureBuilder {
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.name = 'AdminScriptBuilder';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
shouldExecute(appDefinition) {
|
|
25
|
+
return Array.isArray(appDefinition.adminScripts) && appDefinition.adminScripts.length > 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getDependencies() {
|
|
29
|
+
return []; // Can run independently
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
validate(appDefinition) {
|
|
33
|
+
const result = new ValidationResult();
|
|
34
|
+
|
|
35
|
+
if (!appDefinition.adminScripts) {
|
|
36
|
+
return result; // Not an error, just no scripts
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!Array.isArray(appDefinition.adminScripts)) {
|
|
40
|
+
result.addError('adminScripts must be an array');
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Validate each script
|
|
45
|
+
appDefinition.adminScripts.forEach((script, index) => {
|
|
46
|
+
if (!script?.Definition?.name) {
|
|
47
|
+
result.addError(`Admin script at index ${index} is missing Definition or name`);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async build(appDefinition, discoveredResources) {
|
|
55
|
+
console.log(`\n[${this.name}] Configuring admin scripts...`);
|
|
56
|
+
console.log(` Processing ${appDefinition.adminScripts.length} scripts...`);
|
|
57
|
+
|
|
58
|
+
const usePrismaLayer = appDefinition.usePrismaLambdaLayer !== false;
|
|
59
|
+
const adminConfig = appDefinition.admin || {};
|
|
60
|
+
|
|
61
|
+
const result = {
|
|
62
|
+
functions: {},
|
|
63
|
+
resources: {},
|
|
64
|
+
environment: {},
|
|
65
|
+
custom: {},
|
|
66
|
+
iamStatements: [],
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Create admin script queue
|
|
70
|
+
this.createAdminScriptQueue(result);
|
|
71
|
+
|
|
72
|
+
// Create Lambda function for script execution
|
|
73
|
+
this.createScriptExecutorFunction(appDefinition, result, usePrismaLayer);
|
|
74
|
+
|
|
75
|
+
// Create API routes for script management
|
|
76
|
+
this.createAdminScriptRoutes(appDefinition, result, usePrismaLayer);
|
|
77
|
+
|
|
78
|
+
// Phase 2: Create EventBridge Scheduler resources
|
|
79
|
+
if (adminConfig.enableScheduling) {
|
|
80
|
+
this.createSchedulerResources(appDefinition, result);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Log registered scripts
|
|
84
|
+
appDefinition.adminScripts.forEach(script => {
|
|
85
|
+
const name = script.Definition?.name || 'unknown';
|
|
86
|
+
console.log(` ✓ Registered: ${name}`);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log(`[${this.name}] ✅ Admin script configuration completed`);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
createAdminScriptQueue(result) {
|
|
94
|
+
result.resources.AdminScriptQueue = {
|
|
95
|
+
Type: 'AWS::SQS::Queue',
|
|
96
|
+
Properties: {
|
|
97
|
+
QueueName: '${self:service}-${self:provider.stage}-AdminScriptQueue',
|
|
98
|
+
MessageRetentionPeriod: 86400, // 1 day
|
|
99
|
+
VisibilityTimeout: 900, // 15 minutes (Lambda max)
|
|
100
|
+
RedrivePolicy: {
|
|
101
|
+
maxReceiveCount: 3,
|
|
102
|
+
deadLetterTargetArn: {
|
|
103
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
result.environment.ADMIN_SCRIPT_QUEUE_URL = { Ref: 'AdminScriptQueue' };
|
|
110
|
+
|
|
111
|
+
// The router enqueues async executions and scripts enqueue continuations
|
|
112
|
+
// via queueScript()/queueScriptBatch(). The base role's wildcard does not
|
|
113
|
+
// cover this queue's name, so grant SendMessage explicitly.
|
|
114
|
+
result.iamStatements.push({
|
|
115
|
+
Effect: 'Allow',
|
|
116
|
+
Action: [
|
|
117
|
+
'sqs:SendMessage',
|
|
118
|
+
'sqs:SendMessageBatch',
|
|
119
|
+
'sqs:GetQueueUrl',
|
|
120
|
+
'sqs:GetQueueAttributes',
|
|
121
|
+
],
|
|
122
|
+
Resource: { 'Fn::GetAtt': ['AdminScriptQueue', 'Arn'] },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
console.log(' ✓ Created AdminScriptQueue');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
createScriptExecutorFunction(appDefinition, result, usePrismaLayer) {
|
|
129
|
+
result.functions.adminScriptExecutor = {
|
|
130
|
+
handler: 'node_modules/@friggframework/admin-scripts/src/infrastructure/script-executor-handler.handler',
|
|
131
|
+
skipEsbuild: true,
|
|
132
|
+
package: this.skipEsbuildPackageConfig(appDefinition, usePrismaLayer),
|
|
133
|
+
...(usePrismaLayer && { layers: [{ Ref: 'PrismaLambdaLayer' }] }),
|
|
134
|
+
timeout: 900, // 15 minutes max
|
|
135
|
+
memorySize: 1024,
|
|
136
|
+
events: [
|
|
137
|
+
{
|
|
138
|
+
sqs: {
|
|
139
|
+
arn: { 'Fn::GetAtt': ['AdminScriptQueue', 'Arn'] },
|
|
140
|
+
batchSize: 1,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
console.log(' ✓ Created adminScriptExecutor function');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
createAdminScriptRoutes(appDefinition, result, usePrismaLayer) {
|
|
149
|
+
result.functions.adminScriptRouter = {
|
|
150
|
+
handler: 'node_modules/@friggframework/admin-scripts/src/infrastructure/admin-script-router.handler',
|
|
151
|
+
skipEsbuild: true,
|
|
152
|
+
package: this.skipEsbuildPackageConfig(appDefinition, usePrismaLayer),
|
|
153
|
+
...(usePrismaLayer && { layers: [{ Ref: 'PrismaLambdaLayer' }] }),
|
|
154
|
+
timeout: 30,
|
|
155
|
+
events: [
|
|
156
|
+
// List scripts
|
|
157
|
+
{ httpApi: { path: '/admin/scripts', method: 'GET' } },
|
|
158
|
+
// Get script details
|
|
159
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}', method: 'GET' } },
|
|
160
|
+
// Execute script (sync or async)
|
|
161
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}', method: 'POST' } },
|
|
162
|
+
// Validate script input (dry-run preview)
|
|
163
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}/validate', method: 'POST' } },
|
|
164
|
+
// List executions for a script
|
|
165
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}/executions', method: 'GET' } },
|
|
166
|
+
// Get a single execution
|
|
167
|
+
{
|
|
168
|
+
httpApi: {
|
|
169
|
+
path: '/admin/scripts/{scriptName}/executions/{executionId}',
|
|
170
|
+
method: 'GET',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
// Schedule management (Phase 2)
|
|
174
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}/schedule', method: 'GET' } },
|
|
175
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}/schedule', method: 'PUT' } },
|
|
176
|
+
{ httpApi: { path: '/admin/scripts/{scriptName}/schedule', method: 'DELETE' } },
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
console.log(' ✓ Created adminScriptRouter function');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Without this, the skipEsbuild functions package the whole node_modules
|
|
183
|
+
// closure (aws-sdk, Prisma, dev deps) and blow past Lambda's 250 MB limit.
|
|
184
|
+
// Mirrors the exclusions the framework's other node_modules handlers use.
|
|
185
|
+
skipEsbuildPackageConfig(appDefinition, usePrismaLayer) {
|
|
186
|
+
const tlsCAFile = appDefinition?.database?.documentDB?.tlsCAFile;
|
|
187
|
+
return {
|
|
188
|
+
include: [
|
|
189
|
+
// Handlers connect to the DB, so ship the DocumentDB CA cert.
|
|
190
|
+
...(tlsCAFile ? [tlsCAFile.replace(/^\.\//, '')] : []),
|
|
191
|
+
],
|
|
192
|
+
exclude: [
|
|
193
|
+
'node_modules/aws-sdk/**',
|
|
194
|
+
'node_modules/@aws-sdk/**',
|
|
195
|
+
...(usePrismaLayer
|
|
196
|
+
? [
|
|
197
|
+
'node_modules/@prisma/**',
|
|
198
|
+
'node_modules/.prisma/**',
|
|
199
|
+
'node_modules/prisma/**',
|
|
200
|
+
'node_modules/@friggframework/core/generated/**',
|
|
201
|
+
]
|
|
202
|
+
: []),
|
|
203
|
+
'node_modules/**/node_modules/**',
|
|
204
|
+
'node_modules/@friggframework/test/**',
|
|
205
|
+
'node_modules/@friggframework/eslint-config/**',
|
|
206
|
+
'node_modules/@friggframework/prettier-config/**',
|
|
207
|
+
'node_modules/jest/**',
|
|
208
|
+
'node_modules/prettier/**',
|
|
209
|
+
'node_modules/eslint/**',
|
|
210
|
+
'node_modules/esbuild/**',
|
|
211
|
+
'node_modules/@esbuild/**',
|
|
212
|
+
'node_modules/typescript/**',
|
|
213
|
+
'node_modules/webpack/**',
|
|
214
|
+
'node_modules/osls/**',
|
|
215
|
+
'node_modules/serverless-esbuild/**',
|
|
216
|
+
'node_modules/serverless-jetpack/**',
|
|
217
|
+
'node_modules/serverless-offline/**',
|
|
218
|
+
'node_modules/serverless-offline-sqs/**',
|
|
219
|
+
'node_modules/serverless-dotenv-plugin/**',
|
|
220
|
+
'node_modules/serverless-kms-grants/**',
|
|
221
|
+
// Never deploy secrets or the lockfile.
|
|
222
|
+
'.env',
|
|
223
|
+
'.env.*',
|
|
224
|
+
'**/.env',
|
|
225
|
+
'**/.env.*',
|
|
226
|
+
'.frigg-credentials.json',
|
|
227
|
+
'package-lock.json',
|
|
228
|
+
'test/**',
|
|
229
|
+
'layers/**',
|
|
230
|
+
'coverage/**',
|
|
231
|
+
'**/*.test.js',
|
|
232
|
+
'**/*.spec.js',
|
|
233
|
+
],
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
createSchedulerResources(appDefinition, result) {
|
|
238
|
+
// Constructed ARN, not Fn::GetAtt: a GetAtt edge to the executor closes a
|
|
239
|
+
// CloudFormation circular dependency via the shared Lambda execution role.
|
|
240
|
+
const executorArn = {
|
|
241
|
+
'Fn::Sub':
|
|
242
|
+
'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${self:service}-${self:provider.stage}-adminScriptExecutor',
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Create IAM role for EventBridge Scheduler
|
|
246
|
+
result.resources.AdminScriptSchedulerRole = {
|
|
247
|
+
Type: 'AWS::IAM::Role',
|
|
248
|
+
Properties: {
|
|
249
|
+
RoleName: '${self:service}-${self:provider.stage}-admin-script-scheduler',
|
|
250
|
+
AssumeRolePolicyDocument: {
|
|
251
|
+
Version: '2012-10-17',
|
|
252
|
+
Statement: [{
|
|
253
|
+
Effect: 'Allow',
|
|
254
|
+
Principal: { Service: 'scheduler.amazonaws.com' },
|
|
255
|
+
Action: 'sts:AssumeRole',
|
|
256
|
+
}],
|
|
257
|
+
},
|
|
258
|
+
Policies: [{
|
|
259
|
+
PolicyName: 'InvokeLambda',
|
|
260
|
+
PolicyDocument: {
|
|
261
|
+
Version: '2012-10-17',
|
|
262
|
+
Statement: [{
|
|
263
|
+
Effect: 'Allow',
|
|
264
|
+
Action: 'lambda:InvokeFunction',
|
|
265
|
+
Resource: executorArn,
|
|
266
|
+
}],
|
|
267
|
+
},
|
|
268
|
+
}],
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Create schedule group
|
|
273
|
+
result.resources.AdminScriptScheduleGroup = {
|
|
274
|
+
Type: 'AWS::Scheduler::ScheduleGroup',
|
|
275
|
+
Properties: {
|
|
276
|
+
Name: '${self:service}-${self:provider.stage}-admin-scripts',
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Router-scoped, not shared provider env. Two reasons: broadcasting the
|
|
281
|
+
// resource references to every function creates CloudFormation circular
|
|
282
|
+
// deps; and SCHEDULER_PROVIDER='aws' is only valid for the admin-script
|
|
283
|
+
// adapter (the router's sole consumer) — core's scheduler factory, used
|
|
284
|
+
// by integration Lambdas, rejects 'aws', so it must not leak app-wide.
|
|
285
|
+
result.functions.adminScriptRouter.environment = {
|
|
286
|
+
...(result.functions.adminScriptRouter.environment || {}),
|
|
287
|
+
SCHEDULER_PROVIDER: 'aws',
|
|
288
|
+
SCHEDULER_ROLE_ARN: {
|
|
289
|
+
'Fn::GetAtt': ['AdminScriptSchedulerRole', 'Arn'],
|
|
290
|
+
},
|
|
291
|
+
ADMIN_SCRIPT_SCHEDULE_GROUP: { Ref: 'AdminScriptScheduleGroup' },
|
|
292
|
+
ADMIN_SCRIPT_EXECUTOR_LAMBDA_ARN: executorArn,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// The router manages schedules through the AWS scheduler adapter, so it
|
|
296
|
+
// needs scheduler:* on this group plus iam:PassRole for the role it hands
|
|
297
|
+
// to EventBridge. (UpdateSchedule covers the upsert conflict path.)
|
|
298
|
+
result.iamStatements.push(
|
|
299
|
+
{
|
|
300
|
+
Effect: 'Allow',
|
|
301
|
+
Action: [
|
|
302
|
+
'scheduler:CreateSchedule',
|
|
303
|
+
'scheduler:UpdateSchedule',
|
|
304
|
+
'scheduler:DeleteSchedule',
|
|
305
|
+
'scheduler:GetSchedule',
|
|
306
|
+
],
|
|
307
|
+
Resource: {
|
|
308
|
+
'Fn::Sub': [
|
|
309
|
+
'arn:aws:scheduler:${AWS::Region}:${AWS::AccountId}:schedule/${GroupName}/*',
|
|
310
|
+
{ GroupName: { Ref: 'AdminScriptScheduleGroup' } },
|
|
311
|
+
],
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
Effect: 'Allow',
|
|
316
|
+
Action: ['iam:PassRole'],
|
|
317
|
+
Resource: { 'Fn::GetAtt': ['AdminScriptSchedulerRole', 'Arn'] },
|
|
318
|
+
Condition: {
|
|
319
|
+
StringEquals: {
|
|
320
|
+
'iam:PassedToService': 'scheduler.amazonaws.com',
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
console.log(' ✓ Created EventBridge Scheduler resources');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
module.exports = { AdminScriptBuilder };
|