@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.46
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 +633 -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,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Provider Factory
|
|
3
|
+
*
|
|
4
|
+
* Factory Pattern - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Creates appropriate cloud provider adapter instances based on configuration.
|
|
7
|
+
* This enables runtime provider selection and makes it easy to add new providers.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { CloudProviderAdapter } = require('./cloud-provider-adapter');
|
|
11
|
+
const { AWSProviderAdapter } = require('./aws-provider-adapter');
|
|
12
|
+
|
|
13
|
+
class CloudProviderFactory {
|
|
14
|
+
/**
|
|
15
|
+
* Create cloud provider adapter instance
|
|
16
|
+
*
|
|
17
|
+
* @param {string} providerName - Provider name ('aws', 'gcp', 'azure')
|
|
18
|
+
* @param {string} region - Provider region
|
|
19
|
+
* @param {Object} [credentials] - Optional credential configuration
|
|
20
|
+
* @returns {CloudProviderAdapter} Provider adapter instance
|
|
21
|
+
* @throws {Error} If provider is not supported
|
|
22
|
+
*/
|
|
23
|
+
static create(providerName, region, credentials = {}) {
|
|
24
|
+
const normalizedProvider = (providerName || 'aws').toLowerCase();
|
|
25
|
+
|
|
26
|
+
switch (normalizedProvider) {
|
|
27
|
+
case 'aws':
|
|
28
|
+
return new AWSProviderAdapter(region, credentials);
|
|
29
|
+
|
|
30
|
+
case 'gcp':
|
|
31
|
+
case 'google':
|
|
32
|
+
throw new Error(
|
|
33
|
+
'GCP provider not yet implemented. ' +
|
|
34
|
+
'AWS is currently the only supported cloud provider. ' +
|
|
35
|
+
'GCP support is planned for future releases.'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
case 'azure':
|
|
39
|
+
case 'microsoft':
|
|
40
|
+
throw new Error(
|
|
41
|
+
'Azure provider not yet implemented. ' +
|
|
42
|
+
'AWS is currently the only supported cloud provider. ' +
|
|
43
|
+
'Azure support is planned for future releases.'
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
default:
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Unknown cloud provider: "${providerName}". ` +
|
|
49
|
+
`Supported providers: aws (gcp and azure coming soon)`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get list of supported providers
|
|
56
|
+
*
|
|
57
|
+
* @returns {Array<Object>} List of provider metadata
|
|
58
|
+
*/
|
|
59
|
+
static getSupportedProviders() {
|
|
60
|
+
return [
|
|
61
|
+
{
|
|
62
|
+
name: 'aws',
|
|
63
|
+
displayName: 'Amazon Web Services',
|
|
64
|
+
status: 'available',
|
|
65
|
+
description: 'AWS cloud provider with support for Lambda, VPC, RDS, KMS, etc.',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'gcp',
|
|
69
|
+
displayName: 'Google Cloud Platform',
|
|
70
|
+
status: 'planned',
|
|
71
|
+
description: 'GCP cloud provider support coming soon',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'azure',
|
|
75
|
+
displayName: 'Microsoft Azure',
|
|
76
|
+
status: 'planned',
|
|
77
|
+
description: 'Azure cloud provider support coming soon',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if a provider is supported
|
|
84
|
+
*
|
|
85
|
+
* @param {string} providerName - Provider name to check
|
|
86
|
+
* @returns {boolean} True if provider is supported
|
|
87
|
+
*/
|
|
88
|
+
static isSupported(providerName) {
|
|
89
|
+
const normalized = (providerName || '').toLowerCase();
|
|
90
|
+
return ['aws', 'gcp', 'google', 'azure', 'microsoft'].includes(normalized);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check if a provider is available (implemented)
|
|
95
|
+
*
|
|
96
|
+
* @param {string} providerName - Provider name to check
|
|
97
|
+
* @returns {boolean} True if provider is implemented
|
|
98
|
+
*/
|
|
99
|
+
static isAvailable(providerName) {
|
|
100
|
+
const normalized = (providerName || '').toLowerCase();
|
|
101
|
+
return normalized === 'aws';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
CloudProviderFactory,
|
|
107
|
+
};
|
|
108
|
+
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CloudProviderFactory
|
|
3
|
+
*
|
|
4
|
+
* Verifies provider instantiation, error handling, and factory patterns
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { CloudProviderFactory } = require('./provider-factory');
|
|
8
|
+
const { AWSProviderAdapter } = require('./aws-provider-adapter');
|
|
9
|
+
|
|
10
|
+
describe('CloudProviderFactory', () => {
|
|
11
|
+
describe('create()', () => {
|
|
12
|
+
it('should create AWS provider when provider is "aws"', () => {
|
|
13
|
+
const provider = CloudProviderFactory.create('aws', 'us-east-1');
|
|
14
|
+
|
|
15
|
+
expect(provider).toBeInstanceOf(AWSProviderAdapter);
|
|
16
|
+
expect(provider.getName()).toBe('aws');
|
|
17
|
+
expect(provider.region).toBe('us-east-1');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should default to AWS provider when no provider specified', () => {
|
|
21
|
+
const provider = CloudProviderFactory.create(null, 'us-west-2');
|
|
22
|
+
|
|
23
|
+
expect(provider).toBeInstanceOf(AWSProviderAdapter);
|
|
24
|
+
expect(provider.region).toBe('us-west-2');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should be case-insensitive for provider names', () => {
|
|
28
|
+
const provider = CloudProviderFactory.create('AWS', 'eu-west-1');
|
|
29
|
+
|
|
30
|
+
expect(provider).toBeInstanceOf(AWSProviderAdapter);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should throw error for GCP (not yet implemented)', () => {
|
|
34
|
+
expect(() => {
|
|
35
|
+
CloudProviderFactory.create('gcp', 'us-central1');
|
|
36
|
+
}).toThrow('GCP provider not yet implemented');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should throw error for Azure (not yet implemented)', () => {
|
|
40
|
+
expect(() => {
|
|
41
|
+
CloudProviderFactory.create('azure', 'eastus');
|
|
42
|
+
}).toThrow('Azure provider not yet implemented');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should handle "google" alias for GCP', () => {
|
|
46
|
+
expect(() => {
|
|
47
|
+
CloudProviderFactory.create('google', 'us-central1');
|
|
48
|
+
}).toThrow('GCP provider not yet implemented');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should handle "microsoft" alias for Azure', () => {
|
|
52
|
+
expect(() => {
|
|
53
|
+
CloudProviderFactory.create('microsoft', 'eastus');
|
|
54
|
+
}).toThrow('Azure provider not yet implemented');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should throw error for unknown provider', () => {
|
|
58
|
+
expect(() => {
|
|
59
|
+
CloudProviderFactory.create('unknown-cloud', 'region-1');
|
|
60
|
+
}).toThrow('Unknown cloud provider: "unknown-cloud"');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should pass credentials to provider', () => {
|
|
64
|
+
const credentials = {
|
|
65
|
+
accessKeyId: 'test-key',
|
|
66
|
+
secretAccessKey: 'test-secret',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const provider = CloudProviderFactory.create('aws', 'us-east-1', credentials);
|
|
70
|
+
|
|
71
|
+
expect(provider.credentials).toEqual(credentials);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('getSupportedProviders()', () => {
|
|
76
|
+
it('should return list of supported providers', () => {
|
|
77
|
+
const providers = CloudProviderFactory.getSupportedProviders();
|
|
78
|
+
|
|
79
|
+
expect(Array.isArray(providers)).toBe(true);
|
|
80
|
+
expect(providers.length).toBeGreaterThanOrEqual(3);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should include AWS as available', () => {
|
|
84
|
+
const providers = CloudProviderFactory.getSupportedProviders();
|
|
85
|
+
const aws = providers.find(p => p.name === 'aws');
|
|
86
|
+
|
|
87
|
+
expect(aws).toBeDefined();
|
|
88
|
+
expect(aws.status).toBe('available');
|
|
89
|
+
expect(aws.displayName).toBe('Amazon Web Services');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should include GCP as planned', () => {
|
|
93
|
+
const providers = CloudProviderFactory.getSupportedProviders();
|
|
94
|
+
const gcp = providers.find(p => p.name === 'gcp');
|
|
95
|
+
|
|
96
|
+
expect(gcp).toBeDefined();
|
|
97
|
+
expect(gcp.status).toBe('planned');
|
|
98
|
+
expect(gcp.displayName).toBe('Google Cloud Platform');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should include Azure as planned', () => {
|
|
102
|
+
const providers = CloudProviderFactory.getSupportedProviders();
|
|
103
|
+
const azure = providers.find(p => p.name === 'azure');
|
|
104
|
+
|
|
105
|
+
expect(azure).toBeDefined();
|
|
106
|
+
expect(azure.status).toBe('planned');
|
|
107
|
+
expect(azure.displayName).toBe('Microsoft Azure');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('isSupported()', () => {
|
|
112
|
+
it('should return true for aws', () => {
|
|
113
|
+
expect(CloudProviderFactory.isSupported('aws')).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should return true for gcp', () => {
|
|
117
|
+
expect(CloudProviderFactory.isSupported('gcp')).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should return true for azure', () => {
|
|
121
|
+
expect(CloudProviderFactory.isSupported('azure')).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should return true for google (gcp alias)', () => {
|
|
125
|
+
expect(CloudProviderFactory.isSupported('google')).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should return true for microsoft (azure alias)', () => {
|
|
129
|
+
expect(CloudProviderFactory.isSupported('microsoft')).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should return false for unknown provider', () => {
|
|
133
|
+
expect(CloudProviderFactory.isSupported('unknown')).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should be case-insensitive', () => {
|
|
137
|
+
expect(CloudProviderFactory.isSupported('AWS')).toBe(true);
|
|
138
|
+
expect(CloudProviderFactory.isSupported('GCP')).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should handle null/undefined gracefully', () => {
|
|
142
|
+
expect(CloudProviderFactory.isSupported(null)).toBe(false);
|
|
143
|
+
expect(CloudProviderFactory.isSupported(undefined)).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('isAvailable()', () => {
|
|
148
|
+
it('should return true only for aws', () => {
|
|
149
|
+
expect(CloudProviderFactory.isAvailable('aws')).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should return false for gcp (not yet implemented)', () => {
|
|
153
|
+
expect(CloudProviderFactory.isAvailable('gcp')).toBe(false);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should return false for azure (not yet implemented)', () => {
|
|
157
|
+
expect(CloudProviderFactory.isAvailable('azure')).toBe(false);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should return false for unknown provider', () => {
|
|
161
|
+
expect(CloudProviderFactory.isAvailable('unknown')).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should be case-insensitive', () => {
|
|
165
|
+
expect(CloudProviderFactory.isAvailable('AWS')).toBe(true);
|
|
166
|
+
expect(CloudProviderFactory.isAvailable('GCP')).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Domain Service - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Orchestrates discovery of cloud resources (VPC, databases, encryption keys, etc.)
|
|
7
|
+
* using the cloud provider abstraction layer and domain-specific discovery services.
|
|
8
|
+
*
|
|
9
|
+
* This service is cloud-agnostic and delegates to provider-specific implementations.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { CloudProviderFactory } = require('./providers/provider-factory');
|
|
13
|
+
const { CloudFormationDiscovery } = require('./cloudformation-discovery');
|
|
14
|
+
const { VpcDiscovery } = require('../networking/vpc-discovery');
|
|
15
|
+
const { KmsDiscovery } = require('../security/kms-discovery');
|
|
16
|
+
const { AuroraDiscovery } = require('../database/aurora-discovery');
|
|
17
|
+
const { SsmDiscovery } = require('../parameters/ssm-discovery');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Determine if AWS discovery should run
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} appDefinition - Application definition
|
|
23
|
+
* @returns {boolean} True if discovery is needed
|
|
24
|
+
*/
|
|
25
|
+
function shouldRunDiscovery(appDefinition) {
|
|
26
|
+
console.log(
|
|
27
|
+
'⚙️ Checking FRIGG_SKIP_AWS_DISCOVERY:',
|
|
28
|
+
process.env.FRIGG_SKIP_AWS_DISCOVERY
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (process.env.FRIGG_SKIP_AWS_DISCOVERY === 'true') {
|
|
32
|
+
console.log(
|
|
33
|
+
'⚙️ Skipping AWS discovery because FRIGG_SKIP_AWS_DISCOVERY is set.'
|
|
34
|
+
);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
appDefinition.vpc?.enable === true ||
|
|
40
|
+
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms' ||
|
|
41
|
+
appDefinition.ssm?.enable === true ||
|
|
42
|
+
appDefinition.database?.postgres?.enable === true
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Gather discovered cloud resources
|
|
48
|
+
*
|
|
49
|
+
* Uses cloud provider abstraction to discover resources in a provider-agnostic way.
|
|
50
|
+
*
|
|
51
|
+
* @param {Object} appDefinition - Application definition
|
|
52
|
+
* @returns {Promise<Object>} Discovered cloud resources
|
|
53
|
+
*/
|
|
54
|
+
async function gatherDiscoveredResources(appDefinition) {
|
|
55
|
+
if (!shouldRunDiscovery(appDefinition)) {
|
|
56
|
+
console.log('⚙️ Skipping cloud resource discovery (not required for this configuration)');
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('🔍 Running cloud resource discovery...');
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Get cloud provider (defaults to AWS, can be overridden via env var)
|
|
64
|
+
const providerName = process.env.CLOUD_PROVIDER || appDefinition.provider || 'aws';
|
|
65
|
+
const region = process.env.AWS_REGION || 'us-east-1';
|
|
66
|
+
|
|
67
|
+
console.log(` Provider: ${providerName}`);
|
|
68
|
+
console.log(` Region: ${region}`);
|
|
69
|
+
|
|
70
|
+
// Create provider adapter
|
|
71
|
+
const provider = CloudProviderFactory.create(providerName, region);
|
|
72
|
+
|
|
73
|
+
// Build discovery configuration
|
|
74
|
+
const stage = process.env.SLS_STAGE || 'dev';
|
|
75
|
+
const stackName = `${appDefinition.name || 'create-frigg-app'}-${stage}`;
|
|
76
|
+
const serviceName = appDefinition.name || 'create-frigg-app';
|
|
77
|
+
|
|
78
|
+
// Try CloudFormation-first discovery
|
|
79
|
+
const cfDiscovery = new CloudFormationDiscovery(provider, { serviceName, stage });
|
|
80
|
+
const stackResources = await cfDiscovery.discoverFromStack(stackName);
|
|
81
|
+
|
|
82
|
+
// Validate CF discovery results - only use if contains useful data
|
|
83
|
+
const hasVpcData = stackResources?.defaultVpcId;
|
|
84
|
+
const hasKmsData = stackResources?.defaultKmsKeyId;
|
|
85
|
+
const hasAuroraData = stackResources?.auroraClusterId;
|
|
86
|
+
const hasSomeUsefulData = hasVpcData || hasKmsData || hasAuroraData;
|
|
87
|
+
|
|
88
|
+
// Check if we're in isolated mode (each stage gets its own VPC/Aurora)
|
|
89
|
+
const isIsolatedMode = appDefinition.managementMode === 'managed' &&
|
|
90
|
+
appDefinition.vpcIsolation === 'isolated';
|
|
91
|
+
|
|
92
|
+
if (stackResources && hasSomeUsefulData) {
|
|
93
|
+
console.log(' ✓ Discovered resources from existing CloudFormation stack');
|
|
94
|
+
console.log('✅ Cloud resource discovery completed successfully!');
|
|
95
|
+
return stackResources;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// In isolated mode, NEVER fall back to AWS discovery for VPC/Aurora
|
|
99
|
+
// These resources must be isolated per stage, so we either:
|
|
100
|
+
// 1. Use resources from THIS stage's CloudFormation stack (handled above)
|
|
101
|
+
// 2. Return empty to CREATE fresh isolated resources for this stage
|
|
102
|
+
if (isIsolatedMode) {
|
|
103
|
+
console.log(' ℹ Isolated mode: No CloudFormation stack or no VPC/Aurora in stack');
|
|
104
|
+
console.log(' ℹ Will create fresh isolated VPC/Aurora for this stage');
|
|
105
|
+
console.log(' ℹ Checking for shared KMS key...');
|
|
106
|
+
|
|
107
|
+
// KMS keys CAN be shared across stages (encryption keys are safe to reuse)
|
|
108
|
+
const kmsDiscovery = new KmsDiscovery(provider);
|
|
109
|
+
const kmsConfig = {
|
|
110
|
+
serviceName: appDefinition.name || 'create-frigg-app',
|
|
111
|
+
stage,
|
|
112
|
+
keyAlias: `alias/${appDefinition.name || 'create-frigg-app'}-${stage}-frigg-kms`,
|
|
113
|
+
};
|
|
114
|
+
const kmsResult = await kmsDiscovery.discover(kmsConfig);
|
|
115
|
+
|
|
116
|
+
if (kmsResult?.defaultKmsKeyId) {
|
|
117
|
+
console.log(' ✓ Found shared KMS key (can be reused across stages)');
|
|
118
|
+
console.log('✅ Cloud resource discovery completed - will create isolated VPC/Aurora!');
|
|
119
|
+
return kmsResult;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(' ℹ No existing KMS key found - will create new one');
|
|
123
|
+
console.log('✅ Cloud resource discovery completed - will create fresh isolated resources!');
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Fallback to AWS API discovery (fresh deployment, stack not found, or stack has no useful data)
|
|
128
|
+
if (stackResources && !hasSomeUsefulData) {
|
|
129
|
+
console.log(' ℹ Stack found but contains no usable resources - running AWS API discovery...');
|
|
130
|
+
} else {
|
|
131
|
+
console.log(' ℹ No stack found - running AWS API discovery...');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Create domain discovery services with provider
|
|
135
|
+
const vpcDiscovery = new VpcDiscovery(provider);
|
|
136
|
+
const kmsDiscovery = new KmsDiscovery(provider);
|
|
137
|
+
const auroraDiscovery = new AuroraDiscovery(provider);
|
|
138
|
+
const ssmDiscovery = new SsmDiscovery(provider);
|
|
139
|
+
|
|
140
|
+
const config = {
|
|
141
|
+
serviceName: appDefinition.name || 'create-frigg-app',
|
|
142
|
+
stage,
|
|
143
|
+
vpcId: appDefinition.vpc?.vpcId,
|
|
144
|
+
databaseId: appDefinition.database?.postgres?.clusterId ||
|
|
145
|
+
appDefinition.database?.postgres?.instanceId,
|
|
146
|
+
keyAlias: appDefinition.encryption?.keyAlias,
|
|
147
|
+
includeSecrets: true,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Run discoveries in parallel for better performance
|
|
151
|
+
const [vpcResources, kmsResources, dbResources, ssmResources] =
|
|
152
|
+
await Promise.all([
|
|
153
|
+
appDefinition.vpc?.enable ? vpcDiscovery.discover(config) : Promise.resolve({}),
|
|
154
|
+
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms'
|
|
155
|
+
? kmsDiscovery.discover(config)
|
|
156
|
+
: Promise.resolve({}),
|
|
157
|
+
appDefinition.database?.postgres?.enable
|
|
158
|
+
? auroraDiscovery.discover(config)
|
|
159
|
+
: Promise.resolve({}),
|
|
160
|
+
appDefinition.ssm?.enable
|
|
161
|
+
? ssmDiscovery.discover(config)
|
|
162
|
+
: Promise.resolve({}),
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
// Aggregate results
|
|
166
|
+
const discoveredResources = {
|
|
167
|
+
...vpcResources,
|
|
168
|
+
...kmsResources,
|
|
169
|
+
...dbResources,
|
|
170
|
+
...ssmResources,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
console.log('✅ Cloud resource discovery completed successfully!');
|
|
174
|
+
|
|
175
|
+
return discoveredResources;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('❌ Cloud resource discovery failed:', error.message);
|
|
178
|
+
console.error('Stack:', error.stack);
|
|
179
|
+
|
|
180
|
+
// Don't fail the build - return empty resources and let validation handle it
|
|
181
|
+
console.warn(
|
|
182
|
+
'⚠️ Continuing with empty discovered resources. This may cause deployment issues if resources are required.'
|
|
183
|
+
);
|
|
184
|
+
return {};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = {
|
|
189
|
+
shouldRunDiscovery,
|
|
190
|
+
gatherDiscoveredResources,
|
|
191
|
+
};
|
|
192
|
+
|