@friggframework/devtools 2.0.0-next.44 → 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 -2074
- /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,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aurora Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Domain Service - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Discovers Aurora/RDS database resources using the cloud provider adapter.
|
|
7
|
+
* Adds domain-specific validation and connection string generation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
class AuroraDiscovery {
|
|
11
|
+
/**
|
|
12
|
+
* @param {CloudProviderAdapter} provider - Cloud provider adapter instance
|
|
13
|
+
*/
|
|
14
|
+
constructor(provider) {
|
|
15
|
+
this.provider = provider;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Discover Aurora/RDS database resources
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} config - Discovery configuration
|
|
22
|
+
* @param {string} [config.databaseId] - Specific database cluster/instance ID
|
|
23
|
+
* @param {string} [config.serviceName] - Service name for filtering
|
|
24
|
+
* @param {string} [config.stage] - Deployment stage
|
|
25
|
+
* @returns {Promise<Object>} Discovered database resources
|
|
26
|
+
*/
|
|
27
|
+
async discover(config) {
|
|
28
|
+
console.log('🔍 Discovering Aurora/RDS databases...');
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const rawResources = await this.provider.discoverDatabase(config);
|
|
32
|
+
|
|
33
|
+
const result = {
|
|
34
|
+
auroraClusterEndpoint: null,
|
|
35
|
+
auroraPort: null,
|
|
36
|
+
auroraEngine: null,
|
|
37
|
+
databaseEndpoint: null,
|
|
38
|
+
databasePort: null,
|
|
39
|
+
databaseEngine: null,
|
|
40
|
+
clusters: rawResources.clusters,
|
|
41
|
+
instances: rawResources.instances,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Set discovered endpoint
|
|
45
|
+
if (rawResources.endpoint) {
|
|
46
|
+
result.auroraClusterEndpoint = rawResources.endpoint;
|
|
47
|
+
result.databaseEndpoint = rawResources.endpoint;
|
|
48
|
+
result.auroraPort = rawResources.port || 5432;
|
|
49
|
+
result.databasePort = rawResources.port || 5432;
|
|
50
|
+
result.auroraEngine = rawResources.engine || 'aurora-postgresql';
|
|
51
|
+
result.databaseEngine = rawResources.engine || 'aurora-postgresql';
|
|
52
|
+
|
|
53
|
+
// Capture security group IDs
|
|
54
|
+
if (rawResources.securityGroupIds && rawResources.securityGroupIds.length > 0) {
|
|
55
|
+
result.auroraSecurityGroupId = rawResources.securityGroupIds[0]; // Use first security group
|
|
56
|
+
console.log(` ✓ Found security group: ${result.auroraSecurityGroupId}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(` ✓ Found database: ${result.auroraClusterEndpoint}:${result.auroraPort}`);
|
|
60
|
+
console.log(` ✓ Engine: ${result.auroraEngine}`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log(' ℹ No database found');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Look for associated secrets in Secrets Manager
|
|
66
|
+
// This would be discovered via the provider's discoverParameters method
|
|
67
|
+
// with includeSecrets flag if needed
|
|
68
|
+
|
|
69
|
+
return result;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(' ✗ Database discovery failed:', error.message);
|
|
72
|
+
return {
|
|
73
|
+
auroraClusterEndpoint: null,
|
|
74
|
+
auroraPort: null,
|
|
75
|
+
auroraEngine: null,
|
|
76
|
+
databaseEndpoint: null,
|
|
77
|
+
databasePort: null,
|
|
78
|
+
databaseEngine: null,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
AuroraDiscovery,
|
|
86
|
+
};
|
|
87
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Aurora Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Tests Aurora/RDS database discovery with mocked cloud provider
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { AuroraDiscovery } = require('./aurora-discovery');
|
|
8
|
+
|
|
9
|
+
describe('AuroraDiscovery', () => {
|
|
10
|
+
let mockProvider;
|
|
11
|
+
let auroraDiscovery;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
mockProvider = {
|
|
15
|
+
discoverDatabase: jest.fn(),
|
|
16
|
+
getName: jest.fn().mockReturnValue('aws'),
|
|
17
|
+
};
|
|
18
|
+
auroraDiscovery = new AuroraDiscovery(mockProvider);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('discover()', () => {
|
|
22
|
+
it('should delegate to provider and transform results', async () => {
|
|
23
|
+
const mockProviderResponse = {
|
|
24
|
+
clusters: [
|
|
25
|
+
{
|
|
26
|
+
DBClusterIdentifier: 'aurora-cluster-1',
|
|
27
|
+
Endpoint: 'aurora-cluster-1.cluster-xyz.us-east-1.rds.amazonaws.com',
|
|
28
|
+
Port: 5432,
|
|
29
|
+
Engine: 'aurora-postgresql',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
instances: [],
|
|
33
|
+
endpoint: 'aurora-cluster-1.cluster-xyz.us-east-1.rds.amazonaws.com',
|
|
34
|
+
port: 5432,
|
|
35
|
+
engine: 'aurora-postgresql',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
mockProvider.discoverDatabase.mockResolvedValue(mockProviderResponse);
|
|
39
|
+
|
|
40
|
+
const result = await auroraDiscovery.discover({});
|
|
41
|
+
|
|
42
|
+
expect(mockProvider.discoverDatabase).toHaveBeenCalledWith({});
|
|
43
|
+
expect(result.auroraClusterEndpoint).toBe('aurora-cluster-1.cluster-xyz.us-east-1.rds.amazonaws.com');
|
|
44
|
+
expect(result.databaseEndpoint).toBe('aurora-cluster-1.cluster-xyz.us-east-1.rds.amazonaws.com');
|
|
45
|
+
expect(result.auroraPort).toBe(5432);
|
|
46
|
+
expect(result.databasePort).toBe(5432);
|
|
47
|
+
expect(result.auroraEngine).toBe('aurora-postgresql');
|
|
48
|
+
expect(result.databaseEngine).toBe('aurora-postgresql');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should handle no database found', async () => {
|
|
52
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
53
|
+
clusters: [],
|
|
54
|
+
instances: [],
|
|
55
|
+
endpoint: null,
|
|
56
|
+
port: null,
|
|
57
|
+
engine: null,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const result = await auroraDiscovery.discover({});
|
|
61
|
+
|
|
62
|
+
expect(result.auroraClusterEndpoint).toBeNull();
|
|
63
|
+
expect(result.databaseEndpoint).toBeNull();
|
|
64
|
+
expect(result.auroraPort).toBeNull();
|
|
65
|
+
expect(result.databasePort).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should default to port 5432 if not specified', async () => {
|
|
69
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
70
|
+
clusters: [],
|
|
71
|
+
instances: [],
|
|
72
|
+
endpoint: 'db.example.com',
|
|
73
|
+
port: null,
|
|
74
|
+
engine: 'aurora-postgresql',
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const result = await auroraDiscovery.discover({});
|
|
78
|
+
|
|
79
|
+
expect(result.auroraPort).toBe(5432);
|
|
80
|
+
expect(result.databasePort).toBe(5432);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should default to aurora-postgresql engine if not specified', async () => {
|
|
84
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
85
|
+
clusters: [],
|
|
86
|
+
instances: [],
|
|
87
|
+
endpoint: 'db.example.com',
|
|
88
|
+
port: 5432,
|
|
89
|
+
engine: null,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const result = await auroraDiscovery.discover({});
|
|
93
|
+
|
|
94
|
+
expect(result.auroraEngine).toBe('aurora-postgresql');
|
|
95
|
+
expect(result.databaseEngine).toBe('aurora-postgresql');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should handle MySQL Aurora', async () => {
|
|
99
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
100
|
+
clusters: [],
|
|
101
|
+
instances: [],
|
|
102
|
+
endpoint: 'mysql-cluster.example.com',
|
|
103
|
+
port: 3306,
|
|
104
|
+
engine: 'aurora-mysql',
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const result = await auroraDiscovery.discover({});
|
|
108
|
+
|
|
109
|
+
expect(result.auroraPort).toBe(3306);
|
|
110
|
+
expect(result.auroraEngine).toBe('aurora-mysql');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should pass config to provider', async () => {
|
|
114
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
115
|
+
clusters: [],
|
|
116
|
+
instances: [],
|
|
117
|
+
endpoint: null,
|
|
118
|
+
port: null,
|
|
119
|
+
engine: null,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const config = {
|
|
123
|
+
databaseId: 'my-cluster',
|
|
124
|
+
serviceName: 'test-service',
|
|
125
|
+
stage: 'prod',
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
await auroraDiscovery.discover(config);
|
|
129
|
+
|
|
130
|
+
expect(mockProvider.discoverDatabase).toHaveBeenCalledWith(config);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should handle discovery errors gracefully', async () => {
|
|
134
|
+
mockProvider.discoverDatabase.mockRejectedValue(new Error('RDS API Error'));
|
|
135
|
+
|
|
136
|
+
const result = await auroraDiscovery.discover({});
|
|
137
|
+
|
|
138
|
+
expect(result.auroraClusterEndpoint).toBeNull();
|
|
139
|
+
expect(result.auroraPort).toBeNull();
|
|
140
|
+
expect(result.auroraEngine).toBeNull();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should preserve cluster and instance lists for reference', async () => {
|
|
144
|
+
const mockClusters = [
|
|
145
|
+
{ DBClusterIdentifier: 'cluster-1', Endpoint: 'endpoint-1' },
|
|
146
|
+
{ DBClusterIdentifier: 'cluster-2', Endpoint: 'endpoint-2' },
|
|
147
|
+
];
|
|
148
|
+
const mockInstances = [
|
|
149
|
+
{ DBInstanceIdentifier: 'instance-1' },
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
153
|
+
clusters: mockClusters,
|
|
154
|
+
instances: mockInstances,
|
|
155
|
+
endpoint: 'endpoint-1',
|
|
156
|
+
port: 5432,
|
|
157
|
+
engine: 'aurora-postgresql',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const result = await auroraDiscovery.discover({});
|
|
161
|
+
|
|
162
|
+
expect(result.clusters).toEqual(mockClusters);
|
|
163
|
+
expect(result.instances).toEqual(mockInstances);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should handle RDS instances (non-Aurora)', async () => {
|
|
167
|
+
mockProvider.discoverDatabase.mockResolvedValue({
|
|
168
|
+
clusters: [],
|
|
169
|
+
instances: [
|
|
170
|
+
{
|
|
171
|
+
DBInstanceIdentifier: 'rds-instance',
|
|
172
|
+
Endpoint: { Address: 'rds.example.com', Port: 5432 },
|
|
173
|
+
Engine: 'postgres',
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
endpoint: 'rds.example.com',
|
|
177
|
+
port: 5432,
|
|
178
|
+
engine: 'postgres',
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const result = await auroraDiscovery.discover({});
|
|
182
|
+
|
|
183
|
+
expect(result.databaseEndpoint).toBe('rds.example.com');
|
|
184
|
+
expect(result.databaseEngine).toBe('postgres');
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aurora Resource Resolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves ownership for Aurora PostgreSQL resources following the ownership-based architecture.
|
|
5
|
+
*
|
|
6
|
+
* Resources managed:
|
|
7
|
+
* - Aurora Cluster (RDS::DBCluster)
|
|
8
|
+
* - Aurora Instance (RDS::DBInstance)
|
|
9
|
+
* - DB Subnet Group (RDS::DBSubnetGroup)
|
|
10
|
+
* - DB Secret (SecretsManager::Secret)
|
|
11
|
+
*
|
|
12
|
+
* Ownership types:
|
|
13
|
+
* - STACK: Resource defined in our CloudFormation template (use Refs)
|
|
14
|
+
* - EXTERNAL: Resource outside our stack (use physical IDs)
|
|
15
|
+
* - AUTO: System decides based on discovery
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const BaseResourceResolver = require('../shared/base-resolver');
|
|
19
|
+
const { ResourceOwnership } = require('../shared/types/resource-ownership');
|
|
20
|
+
|
|
21
|
+
class AuroraResourceResolver extends BaseResourceResolver {
|
|
22
|
+
/**
|
|
23
|
+
* Resolve Aurora Cluster ownership
|
|
24
|
+
* @param {Object} appDefinition - App definition
|
|
25
|
+
* @param {Object} discovery - Discovery result
|
|
26
|
+
* @returns {Object} Resource decision
|
|
27
|
+
*/
|
|
28
|
+
resolveCluster(appDefinition, discovery) {
|
|
29
|
+
const userIntent = appDefinition.database?.postgres?.ownership?.cluster || 'auto';
|
|
30
|
+
|
|
31
|
+
// Explicit external - use provided cluster identifier
|
|
32
|
+
if (userIntent === 'external') {
|
|
33
|
+
this.requireExternalIds(
|
|
34
|
+
appDefinition.database?.postgres?.external?.clusterIdentifier,
|
|
35
|
+
'clusterIdentifier'
|
|
36
|
+
);
|
|
37
|
+
return this.createExternalDecision(
|
|
38
|
+
appDefinition.database.postgres.external.clusterIdentifier,
|
|
39
|
+
'User specified ownership=external for Aurora cluster'
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// For stack or auto: check if cluster exists in stack
|
|
44
|
+
const inStack = this.findInStack('FriggAuroraCluster', discovery);
|
|
45
|
+
|
|
46
|
+
if (inStack) {
|
|
47
|
+
return this.createStackDecision(
|
|
48
|
+
inStack.physicalId,
|
|
49
|
+
'Found FriggAuroraCluster in CloudFormation stack'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Check for external cluster
|
|
54
|
+
const external = this.findExternal('AWS::RDS::DBCluster', discovery);
|
|
55
|
+
if (external && userIntent === 'auto') {
|
|
56
|
+
return this.createExternalDecision(
|
|
57
|
+
external.physicalId,
|
|
58
|
+
'Found external Aurora cluster via discovery'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Create new cluster in stack
|
|
63
|
+
return this.createStackDecision(
|
|
64
|
+
null,
|
|
65
|
+
'No existing Aurora cluster - will create in stack'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolve Aurora Instance ownership
|
|
71
|
+
* @param {Object} appDefinition - App definition
|
|
72
|
+
* @param {Object} discovery - Discovery result
|
|
73
|
+
* @returns {Object} Resource decision
|
|
74
|
+
*/
|
|
75
|
+
resolveInstance(appDefinition, discovery) {
|
|
76
|
+
const userIntent = appDefinition.database?.postgres?.ownership?.instance || 'auto';
|
|
77
|
+
|
|
78
|
+
// Explicit external
|
|
79
|
+
if (userIntent === 'external') {
|
|
80
|
+
this.requireExternalIds(
|
|
81
|
+
appDefinition.database?.postgres?.external?.instanceIdentifier,
|
|
82
|
+
'instanceIdentifier'
|
|
83
|
+
);
|
|
84
|
+
return this.createExternalDecision(
|
|
85
|
+
appDefinition.database.postgres.external.instanceIdentifier,
|
|
86
|
+
'User specified ownership=external for Aurora instance'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check if instance exists in stack
|
|
91
|
+
const inStack = this.findInStack('FriggAuroraInstance', discovery);
|
|
92
|
+
|
|
93
|
+
if (inStack) {
|
|
94
|
+
return this.createStackDecision(
|
|
95
|
+
inStack.physicalId,
|
|
96
|
+
'Found FriggAuroraInstance in CloudFormation stack'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Check for external instance
|
|
101
|
+
const external = this.findExternal('AWS::RDS::DBInstance', discovery);
|
|
102
|
+
if (external && userIntent === 'auto') {
|
|
103
|
+
return this.createExternalDecision(
|
|
104
|
+
external.physicalId,
|
|
105
|
+
'Found external Aurora instance via discovery'
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Create new instance in stack
|
|
110
|
+
return this.createStackDecision(
|
|
111
|
+
null,
|
|
112
|
+
'No existing Aurora instance - will create in stack'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Resolve DB Subnet Group ownership
|
|
118
|
+
* @param {Object} appDefinition - App definition
|
|
119
|
+
* @param {Object} discovery - Discovery result
|
|
120
|
+
* @returns {Object} Resource decision
|
|
121
|
+
*/
|
|
122
|
+
resolveSubnetGroup(appDefinition, discovery) {
|
|
123
|
+
const userIntent = appDefinition.database?.postgres?.ownership?.subnetGroup || 'auto';
|
|
124
|
+
|
|
125
|
+
// Explicit external
|
|
126
|
+
if (userIntent === 'external') {
|
|
127
|
+
this.requireExternalIds(
|
|
128
|
+
appDefinition.database?.postgres?.external?.subnetGroupName,
|
|
129
|
+
'subnetGroupName'
|
|
130
|
+
);
|
|
131
|
+
return this.createExternalDecision(
|
|
132
|
+
appDefinition.database.postgres.external.subnetGroupName,
|
|
133
|
+
'User specified ownership=external for DB subnet group'
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check if subnet group exists in stack
|
|
138
|
+
const inStack = this.findInStack('FriggDBSubnetGroup', discovery);
|
|
139
|
+
|
|
140
|
+
if (inStack) {
|
|
141
|
+
return this.createStackDecision(
|
|
142
|
+
inStack.physicalId,
|
|
143
|
+
'Found FriggDBSubnetGroup in CloudFormation stack'
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// For subnet groups, always create in stack (they're cheap and cluster-specific)
|
|
148
|
+
return this.createStackDecision(
|
|
149
|
+
null,
|
|
150
|
+
'No existing DB subnet group - will create in stack'
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Resolve DB Secret ownership
|
|
156
|
+
* @param {Object} appDefinition - App definition
|
|
157
|
+
* @param {Object} discovery - Discovery result
|
|
158
|
+
* @returns {Object} Resource decision
|
|
159
|
+
*/
|
|
160
|
+
resolveSecret(appDefinition, discovery) {
|
|
161
|
+
const userIntent = appDefinition.database?.postgres?.ownership?.secret || 'auto';
|
|
162
|
+
|
|
163
|
+
// Explicit external - use provided secret ARN
|
|
164
|
+
if (userIntent === 'external') {
|
|
165
|
+
this.requireExternalIds(
|
|
166
|
+
appDefinition.database?.postgres?.external?.secretArn,
|
|
167
|
+
'secretArn'
|
|
168
|
+
);
|
|
169
|
+
return this.createExternalDecision(
|
|
170
|
+
appDefinition.database.postgres.external.secretArn,
|
|
171
|
+
'User specified ownership=external for DB secret'
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check if secret exists in stack
|
|
176
|
+
const inStack = this.findInStack('FriggDBSecret', discovery);
|
|
177
|
+
|
|
178
|
+
if (inStack) {
|
|
179
|
+
return this.createStackDecision(
|
|
180
|
+
inStack.physicalId,
|
|
181
|
+
'Found FriggDBSecret in CloudFormation stack'
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// For secrets tied to the cluster, always create in stack
|
|
186
|
+
return this.createStackDecision(
|
|
187
|
+
null,
|
|
188
|
+
'No existing DB secret - will create in stack'
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Resolve all Aurora resources at once
|
|
194
|
+
* Convenience method that returns decisions for all Aurora resources
|
|
195
|
+
*
|
|
196
|
+
* @param {Object} appDefinition - App definition
|
|
197
|
+
* @param {Object} discovery - Discovery result
|
|
198
|
+
* @returns {Object} Decisions for all Aurora resources
|
|
199
|
+
*/
|
|
200
|
+
resolveAll(appDefinition, discovery) {
|
|
201
|
+
return {
|
|
202
|
+
cluster: this.resolveCluster(appDefinition, discovery),
|
|
203
|
+
instance: this.resolveInstance(appDefinition, discovery),
|
|
204
|
+
subnetGroup: this.resolveSubnetGroup(appDefinition, discovery),
|
|
205
|
+
secret: this.resolveSecret(appDefinition, discovery)
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
module.exports = AuroraResourceResolver;
|