@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.47
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/infrastructure/ARCHITECTURE.md +487 -0
- package/infrastructure/HEALTH.md +468 -0
- package/infrastructure/README.md +51 -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 +1 -1
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-builder.js +809 -0
- package/infrastructure/domains/database/aurora-builder.test.js +950 -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 +695 -0
- package/infrastructure/domains/database/migration-builder.test.js +294 -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 +397 -0
- package/infrastructure/domains/integration/integration-builder.test.js +593 -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 +1829 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +1262 -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 +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -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/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +366 -0
- package/infrastructure/domains/security/kms-builder.test.js +374 -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/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 +375 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -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 +544 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -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.js +192 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
- package/infrastructure/domains/shared/types/app-definition.js +205 -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 +380 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -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 +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
- package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +87 -0
- package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
- package/infrastructure/scripts/build-prisma-layer.js +553 -0
- package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
- package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/cliIntegration.js +1 -1
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +11 -11
- package/frigg-cli/.eslintrc.js +0 -141
- package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
- package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
- package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
- package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
- package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
- package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
- package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
- package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
- package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
- package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
- package/frigg-cli/__tests__/utils/test-setup.js +0 -287
- package/frigg-cli/build-command/index.js +0 -65
- package/frigg-cli/db-setup-command/index.js +0 -193
- package/frigg-cli/deploy-command/index.js +0 -175
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
- package/frigg-cli/generate-command/azure-generator.js +0 -43
- package/frigg-cli/generate-command/gcp-generator.js +0 -47
- package/frigg-cli/generate-command/index.js +0 -332
- package/frigg-cli/generate-command/terraform-generator.js +0 -555
- package/frigg-cli/generate-iam-command.js +0 -118
- package/frigg-cli/index.js +0 -75
- package/frigg-cli/index.test.js +0 -158
- package/frigg-cli/init-command/backend-first-handler.js +0 -756
- package/frigg-cli/init-command/index.js +0 -93
- package/frigg-cli/init-command/template-handler.js +0 -143
- package/frigg-cli/install-command/backend-js.js +0 -33
- package/frigg-cli/install-command/commit-changes.js +0 -16
- package/frigg-cli/install-command/environment-variables.js +0 -127
- package/frigg-cli/install-command/environment-variables.test.js +0 -136
- package/frigg-cli/install-command/index.js +0 -54
- package/frigg-cli/install-command/install-package.js +0 -13
- package/frigg-cli/install-command/integration-file.js +0 -30
- package/frigg-cli/install-command/logger.js +0 -12
- package/frigg-cli/install-command/template.js +0 -90
- package/frigg-cli/install-command/validate-package.js +0 -75
- package/frigg-cli/jest.config.js +0 -124
- package/frigg-cli/package.json +0 -54
- package/frigg-cli/start-command/index.js +0 -149
- package/frigg-cli/start-command/start-command.test.js +0 -297
- package/frigg-cli/test/init-command.test.js +0 -180
- package/frigg-cli/test/npm-registry.test.js +0 -319
- package/frigg-cli/ui-command/index.js +0 -154
- package/frigg-cli/utils/app-resolver.js +0 -319
- package/frigg-cli/utils/backend-path.js +0 -25
- package/frigg-cli/utils/database-validator.js +0 -161
- package/frigg-cli/utils/error-messages.js +0 -257
- package/frigg-cli/utils/npm-registry.js +0 -167
- package/frigg-cli/utils/prisma-runner.js +0 -280
- package/frigg-cli/utils/process-manager.js +0 -199
- package/frigg-cli/utils/repo-detection.js +0 -405
- package/infrastructure/aws-discovery.js +0 -1176
- package/infrastructure/aws-discovery.test.js +0 -1220
- package/infrastructure/serverless-template.js +0 -2094
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Environment Variable Validator
|
|
3
|
+
*
|
|
4
|
+
* Tests validation of required environment variables
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { validateEnvironmentVariables } = require('./env-validator');
|
|
8
|
+
|
|
9
|
+
describe('Environment Validator', () => {
|
|
10
|
+
let originalEnv;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
originalEnv = { ...process.env };
|
|
14
|
+
// Clear test-related env vars
|
|
15
|
+
delete process.env.TEST_VAR_1;
|
|
16
|
+
delete process.env.TEST_VAR_2;
|
|
17
|
+
delete process.env.NODE_ENV;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
process.env = originalEnv;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('validateEnvironmentVariables()', () => {
|
|
25
|
+
it('should return empty results for app definition without environment', () => {
|
|
26
|
+
const appDefinition = {};
|
|
27
|
+
|
|
28
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
29
|
+
|
|
30
|
+
expect(result.valid).toEqual([]);
|
|
31
|
+
expect(result.missing).toEqual([]);
|
|
32
|
+
expect(result.warnings).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should validate present environment variables', () => {
|
|
36
|
+
process.env.TEST_VAR_1 = 'value1';
|
|
37
|
+
process.env.TEST_VAR_2 = 'value2';
|
|
38
|
+
|
|
39
|
+
const appDefinition = {
|
|
40
|
+
environment: {
|
|
41
|
+
TEST_VAR_1: true,
|
|
42
|
+
TEST_VAR_2: true,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
47
|
+
|
|
48
|
+
expect(result.valid).toEqual(['TEST_VAR_1', 'TEST_VAR_2']);
|
|
49
|
+
expect(result.missing).toEqual([]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should detect missing environment variables', () => {
|
|
53
|
+
process.env.TEST_VAR_1 = 'value1';
|
|
54
|
+
// TEST_VAR_2 not set
|
|
55
|
+
|
|
56
|
+
const appDefinition = {
|
|
57
|
+
environment: {
|
|
58
|
+
TEST_VAR_1: true,
|
|
59
|
+
TEST_VAR_2: true,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
64
|
+
|
|
65
|
+
expect(result.valid).toEqual(['TEST_VAR_1']);
|
|
66
|
+
expect(result.missing).toEqual(['TEST_VAR_2']);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should only validate variables with value true', () => {
|
|
70
|
+
process.env.TEST_VAR_1 = 'value1';
|
|
71
|
+
|
|
72
|
+
const appDefinition = {
|
|
73
|
+
environment: {
|
|
74
|
+
TEST_VAR_1: true,
|
|
75
|
+
TEST_VAR_2: false,
|
|
76
|
+
TEST_VAR_3: 'string-value',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
81
|
+
|
|
82
|
+
expect(result.valid).toEqual(['TEST_VAR_1']);
|
|
83
|
+
expect(result.missing).toEqual([]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should handle NODE_ENV specially with warning', () => {
|
|
87
|
+
// NODE_ENV not set
|
|
88
|
+
|
|
89
|
+
const appDefinition = {
|
|
90
|
+
environment: {
|
|
91
|
+
NODE_ENV: true,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
96
|
+
|
|
97
|
+
expect(result.missing).not.toContain('NODE_ENV');
|
|
98
|
+
expect(result.warnings).toContain('NODE_ENV not set, defaulting to "production"');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should not warn about NODE_ENV if it is set', () => {
|
|
102
|
+
process.env.NODE_ENV = 'development';
|
|
103
|
+
|
|
104
|
+
const appDefinition = {
|
|
105
|
+
environment: {
|
|
106
|
+
NODE_ENV: true,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
111
|
+
|
|
112
|
+
expect(result.valid).toContain('NODE_ENV');
|
|
113
|
+
expect(result.warnings).not.toContain('NODE_ENV not set, defaulting to "production"');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should warn about missing variables', () => {
|
|
117
|
+
const appDefinition = {
|
|
118
|
+
environment: {
|
|
119
|
+
MISSING_VAR_1: true,
|
|
120
|
+
MISSING_VAR_2: true,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
125
|
+
|
|
126
|
+
expect(result.missing).toEqual(['MISSING_VAR_1', 'MISSING_VAR_2']);
|
|
127
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should handle mixed valid and missing variables', () => {
|
|
131
|
+
process.env.VALID_VAR = 'value';
|
|
132
|
+
|
|
133
|
+
const appDefinition = {
|
|
134
|
+
environment: {
|
|
135
|
+
VALID_VAR: true,
|
|
136
|
+
MISSING_VAR: true,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
141
|
+
|
|
142
|
+
expect(result.valid).toEqual(['VALID_VAR']);
|
|
143
|
+
expect(result.missing).toEqual(['MISSING_VAR']);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should handle empty environment object', () => {
|
|
147
|
+
const appDefinition = {
|
|
148
|
+
environment: {},
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
152
|
+
|
|
153
|
+
expect(result.valid).toEqual([]);
|
|
154
|
+
expect(result.missing).toEqual([]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should handle environment variables with empty string values', () => {
|
|
158
|
+
process.env.TEST_VAR = '';
|
|
159
|
+
|
|
160
|
+
const appDefinition = {
|
|
161
|
+
environment: {
|
|
162
|
+
TEST_VAR: true,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const result = validateEnvironmentVariables(appDefinition);
|
|
167
|
+
|
|
168
|
+
// Empty string is still considered "present"
|
|
169
|
+
expect(result.valid).toContain('TEST_VAR');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* esbuild Configuration for Frigg Lambda Functions
|
|
3
|
+
*
|
|
4
|
+
* Optimized for AWS Lambda Node.js 22.x runtime with:
|
|
5
|
+
* - Tree-shaking for minimal bundle size
|
|
6
|
+
* - AWS SDK v3 externalization (provided by Lambda)
|
|
7
|
+
* - Prisma client externalization (in Lambda layer)
|
|
8
|
+
* - Source maps for debugging
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
bundle: true,
|
|
13
|
+
minify: true,
|
|
14
|
+
sourcemap: true,
|
|
15
|
+
target: 'node22', // AWS Lambda Node.js 22.x (latest supported)
|
|
16
|
+
platform: 'node',
|
|
17
|
+
format: 'cjs', // CommonJS for Lambda
|
|
18
|
+
mainFields: ['main', 'module'],
|
|
19
|
+
|
|
20
|
+
// External packages - not included in bundle
|
|
21
|
+
external: [
|
|
22
|
+
// AWS SDK v3 - provided by Lambda runtime
|
|
23
|
+
'@aws-sdk/*',
|
|
24
|
+
'aws-sdk', // Legacy v2 SDK
|
|
25
|
+
|
|
26
|
+
// Prisma - in Lambda layer
|
|
27
|
+
'@prisma/client',
|
|
28
|
+
'prisma',
|
|
29
|
+
'.prisma/*',
|
|
30
|
+
|
|
31
|
+
// Native modules
|
|
32
|
+
'sharp',
|
|
33
|
+
'canvas',
|
|
34
|
+
'sqlite3',
|
|
35
|
+
'pg-native',
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
// Package manager
|
|
39
|
+
packager: 'npm',
|
|
40
|
+
|
|
41
|
+
// Additional esbuild options
|
|
42
|
+
keepNames: true, // Preserve function names for debugging
|
|
43
|
+
metafile: true, // Generate build metadata
|
|
44
|
+
|
|
45
|
+
// Exclude patterns (for serverless-esbuild plugin)
|
|
46
|
+
exclude: [
|
|
47
|
+
'aws-sdk',
|
|
48
|
+
'@aws-sdk/*',
|
|
49
|
+
'@prisma/client',
|
|
50
|
+
'prisma',
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infrastructure Composer
|
|
3
|
+
*
|
|
4
|
+
* Application Layer - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Orchestrates the composition of serverless infrastructure definitions
|
|
7
|
+
* using domain builders and shared utilities.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Domain Builders
|
|
11
|
+
const { BuilderOrchestrator } = require('./domains/shared/builder-orchestrator');
|
|
12
|
+
const { VpcBuilder } = require('./domains/networking/vpc-builder');
|
|
13
|
+
const { KmsBuilder } = require('./domains/security/kms-builder');
|
|
14
|
+
const { AuroraBuilder } = require('./domains/database/aurora-builder');
|
|
15
|
+
const { MigrationBuilder } = require('./domains/database/migration-builder');
|
|
16
|
+
const { SsmBuilder } = require('./domains/parameters/ssm-builder');
|
|
17
|
+
const { WebsocketBuilder } = require('./domains/integration/websocket-builder');
|
|
18
|
+
const { IntegrationBuilder } = require('./domains/integration/integration-builder');
|
|
19
|
+
|
|
20
|
+
// Utilities
|
|
21
|
+
const { modifyHandlerPaths } = require('./domains/shared/utilities/handler-path-resolver');
|
|
22
|
+
const { createBaseDefinition } = require('./domains/shared/utilities/base-definition-factory');
|
|
23
|
+
const { ensurePrismaLayerExists } = require('./domains/shared/utilities/prisma-layer-manager');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Compose serverless definition using domain builders
|
|
27
|
+
*
|
|
28
|
+
* This is the main entry point that orchestrates all infrastructure building
|
|
29
|
+
* using the DDD/Hexagonal architecture pattern.
|
|
30
|
+
*/
|
|
31
|
+
const composeServerlessDefinition = async (AppDefinition) => {
|
|
32
|
+
console.log('🏗️ Composing serverless definition with domain builders...');
|
|
33
|
+
|
|
34
|
+
// Ensure Prisma layer exists (minimal, runtime only)
|
|
35
|
+
await ensurePrismaLayerExists(AppDefinition.database || {});
|
|
36
|
+
|
|
37
|
+
// Create orchestrator with all domain builders
|
|
38
|
+
const orchestrator = new BuilderOrchestrator([
|
|
39
|
+
new VpcBuilder(),
|
|
40
|
+
new KmsBuilder(),
|
|
41
|
+
new AuroraBuilder(),
|
|
42
|
+
new MigrationBuilder(), // Add migration infrastructure after Aurora
|
|
43
|
+
new SsmBuilder(),
|
|
44
|
+
new WebsocketBuilder(),
|
|
45
|
+
new IntegrationBuilder(),
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
// Build all infrastructure (orchestrator handles validation, dependencies, parallel execution)
|
|
49
|
+
// Builders automatically skip if shouldExecute() returns false (e.g., local mode)
|
|
50
|
+
const { merged, discoveredResources, appEnvironmentVars } =
|
|
51
|
+
await orchestrator.buildAll(AppDefinition);
|
|
52
|
+
|
|
53
|
+
// Create base definition with core functions
|
|
54
|
+
const definition = createBaseDefinition(
|
|
55
|
+
AppDefinition,
|
|
56
|
+
appEnvironmentVars,
|
|
57
|
+
discoveredResources
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Merge builder results into definition
|
|
61
|
+
Object.assign(definition.resources.Resources, merged.resources);
|
|
62
|
+
definition.provider.iamRoleStatements.push(...merged.iamStatements);
|
|
63
|
+
Object.assign(definition.provider.environment, merged.environment);
|
|
64
|
+
Object.assign(definition.functions, merged.functions);
|
|
65
|
+
|
|
66
|
+
if (merged.vpcConfig) {
|
|
67
|
+
definition.provider.vpc = merged.vpcConfig;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Add unique plugins (avoid duplicates)
|
|
71
|
+
merged.plugins.forEach(plugin => {
|
|
72
|
+
if (!definition.plugins.includes(plugin)) {
|
|
73
|
+
definition.plugins.push(plugin);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
Object.assign(definition.custom, merged.custom);
|
|
78
|
+
|
|
79
|
+
// Modify handler paths for offline mode
|
|
80
|
+
definition.functions = modifyHandlerPaths(definition.functions);
|
|
81
|
+
|
|
82
|
+
console.log('✅ Serverless definition composed successfully');
|
|
83
|
+
return definition;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = { composeServerlessDefinition };
|
|
87
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { composeServerlessDefinition } = require('./
|
|
1
|
+
const { composeServerlessDefinition } = require('./infrastructure-composer');
|
|
2
2
|
|
|
3
3
|
// Helper to build discovery responses with overridable fields
|
|
4
4
|
const createDiscoveryResponse = (overrides = {}) => ({
|
|
@@ -7,36 +7,36 @@ const createDiscoveryResponse = (overrides = {}) => ({
|
|
|
7
7
|
defaultSecurityGroupId: 'sg-123456',
|
|
8
8
|
privateSubnetId1: 'subnet-123456',
|
|
9
9
|
privateSubnetId2: 'subnet-789012',
|
|
10
|
-
publicSubnetId: 'subnet-public',
|
|
10
|
+
publicSubnetId: 'subnet-public', // Keep for backward compat
|
|
11
|
+
publicSubnetId1: 'subnet-public-1',
|
|
12
|
+
publicSubnetId2: 'subnet-public-2',
|
|
11
13
|
defaultRouteTableId: 'rtb-123456',
|
|
12
14
|
defaultKmsKeyId:
|
|
13
15
|
'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
|
|
14
16
|
existingNatGatewayId: 'nat-default123',
|
|
17
|
+
auroraClusterEndpoint: 'test-cluster.cluster-abc123.us-east-1.rds.amazonaws.com',
|
|
18
|
+
auroraPort: 5432,
|
|
19
|
+
auroraEngine: 'aurora-postgresql',
|
|
15
20
|
...overrides,
|
|
16
21
|
});
|
|
17
22
|
|
|
18
|
-
// Mock
|
|
19
|
-
jest.mock('./
|
|
23
|
+
// Mock resource discovery to prevent actual AWS calls
|
|
24
|
+
jest.mock('./domains/shared/resource-discovery', () => {
|
|
25
|
+
const originalModule = jest.requireActual('./domains/shared/resource-discovery');
|
|
20
26
|
return {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.fn()
|
|
24
|
-
.mockResolvedValue(createDiscoveryResponse()),
|
|
25
|
-
})),
|
|
27
|
+
...originalModule,
|
|
28
|
+
gatherDiscoveredResources: jest.fn().mockResolvedValue(createDiscoveryResponse()),
|
|
26
29
|
};
|
|
27
30
|
});
|
|
28
31
|
|
|
29
|
-
const {
|
|
32
|
+
const { gatherDiscoveredResources } = require('./domains/shared/resource-discovery');
|
|
30
33
|
|
|
31
34
|
describe('composeServerlessDefinition', () => {
|
|
32
35
|
let mockIntegration;
|
|
33
36
|
|
|
34
37
|
beforeEach(() => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.fn()
|
|
38
|
-
.mockResolvedValue(createDiscoveryResponse()),
|
|
39
|
-
}));
|
|
38
|
+
// Reset the mock to default behavior
|
|
39
|
+
gatherDiscoveredResources.mockResolvedValue(createDiscoveryResponse());
|
|
40
40
|
|
|
41
41
|
mockIntegration = {
|
|
42
42
|
Definition: {
|
|
@@ -52,7 +52,7 @@ describe('composeServerlessDefinition', () => {
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
afterEach(() => {
|
|
55
|
-
jest.
|
|
55
|
+
jest.clearAllMocks();
|
|
56
56
|
// Restore env
|
|
57
57
|
delete process.env.AWS_REGION;
|
|
58
58
|
delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
|
|
@@ -61,7 +61,7 @@ describe('composeServerlessDefinition', () => {
|
|
|
61
61
|
|
|
62
62
|
describe('AWS discovery gating', () => {
|
|
63
63
|
it('should skip AWS discovery when no features require it', async () => {
|
|
64
|
-
|
|
64
|
+
gatherDiscoveredResources.mockClear();
|
|
65
65
|
|
|
66
66
|
const appDefinition = {
|
|
67
67
|
integrations: [],
|
|
@@ -72,11 +72,11 @@ describe('composeServerlessDefinition', () => {
|
|
|
72
72
|
|
|
73
73
|
await composeServerlessDefinition(appDefinition);
|
|
74
74
|
|
|
75
|
-
expect(
|
|
75
|
+
expect(gatherDiscoveredResources).not.toHaveBeenCalled();
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('should run AWS discovery when VPC features are enabled', async () => {
|
|
79
|
-
|
|
79
|
+
gatherDiscoveredResources.mockClear();
|
|
80
80
|
|
|
81
81
|
const appDefinition = {
|
|
82
82
|
integrations: [],
|
|
@@ -85,11 +85,11 @@ describe('composeServerlessDefinition', () => {
|
|
|
85
85
|
|
|
86
86
|
await composeServerlessDefinition(appDefinition);
|
|
87
87
|
|
|
88
|
-
expect(
|
|
88
|
+
expect(gatherDiscoveredResources).toHaveBeenCalledTimes(1);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
it('should skip AWS discovery when FRIGG_SKIP_AWS_DISCOVERY is set to true', async () => {
|
|
92
|
-
|
|
92
|
+
gatherDiscoveredResources.mockClear();
|
|
93
93
|
process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
|
|
94
94
|
|
|
95
95
|
const appDefinition = {
|
|
@@ -101,11 +101,11 @@ describe('composeServerlessDefinition', () => {
|
|
|
101
101
|
|
|
102
102
|
await composeServerlessDefinition(appDefinition);
|
|
103
103
|
|
|
104
|
-
expect(
|
|
104
|
+
expect(gatherDiscoveredResources).not.toHaveBeenCalled();
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
it('should run AWS discovery when FRIGG_SKIP_AWS_DISCOVERY is not set', async () => {
|
|
108
|
-
|
|
108
|
+
gatherDiscoveredResources.mockClear();
|
|
109
109
|
delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
|
|
110
110
|
|
|
111
111
|
const appDefinition = {
|
|
@@ -115,7 +115,7 @@ describe('composeServerlessDefinition', () => {
|
|
|
115
115
|
|
|
116
116
|
await composeServerlessDefinition(appDefinition);
|
|
117
117
|
|
|
118
|
-
expect(
|
|
118
|
+
expect(gatherDiscoveredResources).toHaveBeenCalledTimes(1);
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
it('should skip VPC configuration when FRIGG_SKIP_AWS_DISCOVERY is true', async () => {
|
|
@@ -1762,6 +1762,97 @@ describe('composeServerlessDefinition', () => {
|
|
|
1762
1762
|
});
|
|
1763
1763
|
});
|
|
1764
1764
|
|
|
1765
|
+
describe('Database Migration Lambda', () => {
|
|
1766
|
+
it('should include dbMigrate function in all deployments', async () => {
|
|
1767
|
+
const appDefinition = {
|
|
1768
|
+
name: 'test-app',
|
|
1769
|
+
integrations: []
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1773
|
+
|
|
1774
|
+
// Check dbMigrate function exists
|
|
1775
|
+
expect(result.functions.dbMigrate).toBeDefined();
|
|
1776
|
+
expect(result.functions.dbMigrate.handler).toBe(
|
|
1777
|
+
'node_modules/@friggframework/core/handlers/workers/db-migration.handler'
|
|
1778
|
+
);
|
|
1779
|
+
});
|
|
1780
|
+
|
|
1781
|
+
it('should configure dbMigrate with correct settings', async () => {
|
|
1782
|
+
const appDefinition = {
|
|
1783
|
+
integrations: []
|
|
1784
|
+
};
|
|
1785
|
+
|
|
1786
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1787
|
+
|
|
1788
|
+
const dbMigrate = result.functions.dbMigrate;
|
|
1789
|
+
|
|
1790
|
+
// Check timeout (5 minutes for long migrations)
|
|
1791
|
+
expect(dbMigrate.timeout).toBe(300);
|
|
1792
|
+
|
|
1793
|
+
// Check memory allocation (extra for Prisma CLI)
|
|
1794
|
+
expect(dbMigrate.memorySize).toBe(512);
|
|
1795
|
+
|
|
1796
|
+
// Check description
|
|
1797
|
+
expect(dbMigrate.description).toContain('database migrations');
|
|
1798
|
+
expect(dbMigrate.description).toContain('Prisma');
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
it('should not have HTTP events (manual invocation only)', async () => {
|
|
1802
|
+
const appDefinition = {
|
|
1803
|
+
integrations: []
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1806
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1807
|
+
|
|
1808
|
+
const dbMigrate = result.functions.dbMigrate;
|
|
1809
|
+
|
|
1810
|
+
// Should have no events (manually invoked via AWS CLI)
|
|
1811
|
+
expect(dbMigrate.events).toBeUndefined();
|
|
1812
|
+
});
|
|
1813
|
+
|
|
1814
|
+
it('should include dbMigrate even with VPC enabled', async () => {
|
|
1815
|
+
const appDefinition = {
|
|
1816
|
+
vpc: {
|
|
1817
|
+
enable: true,
|
|
1818
|
+
management: 'discover'
|
|
1819
|
+
},
|
|
1820
|
+
integrations: []
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1824
|
+
|
|
1825
|
+
// dbMigrate should exist with VPC configuration
|
|
1826
|
+
expect(result.functions.dbMigrate).toBeDefined();
|
|
1827
|
+
|
|
1828
|
+
// Should have same VPC access as other functions
|
|
1829
|
+
expect(result.provider.vpc).toBeDefined();
|
|
1830
|
+
});
|
|
1831
|
+
|
|
1832
|
+
it('should include dbMigrate with database configuration', async () => {
|
|
1833
|
+
const appDefinition = {
|
|
1834
|
+
vpc: {
|
|
1835
|
+
enable: true,
|
|
1836
|
+
management: 'discover'
|
|
1837
|
+
},
|
|
1838
|
+
database: {
|
|
1839
|
+
postgres: {
|
|
1840
|
+
enable: true,
|
|
1841
|
+
management: 'discover'
|
|
1842
|
+
}
|
|
1843
|
+
},
|
|
1844
|
+
integrations: []
|
|
1845
|
+
};
|
|
1846
|
+
|
|
1847
|
+
const result = await composeServerlessDefinition(appDefinition);
|
|
1848
|
+
|
|
1849
|
+
// dbMigrate should exist alongside database configuration
|
|
1850
|
+
expect(result.functions.dbMigrate).toBeDefined();
|
|
1851
|
+
expect(result.provider.environment.DB_TYPE).toBe('postgresql');
|
|
1852
|
+
expect(result.provider.environment.DATABASE_URL).toBeDefined();
|
|
1853
|
+
});
|
|
1854
|
+
});
|
|
1855
|
+
|
|
1765
1856
|
describe('Edge Cases', () => {
|
|
1766
1857
|
it('should handle empty app definition', async () => {
|
|
1767
1858
|
const appDefinition = {};
|