@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,552 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Resource Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Tests orchestration of cloud resource discovery
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { shouldRunDiscovery, gatherDiscoveredResources } = require('./resource-discovery');
|
|
8
|
+
|
|
9
|
+
// Mock the provider factory and discovery classes
|
|
10
|
+
jest.mock('./providers/provider-factory');
|
|
11
|
+
jest.mock('../networking/vpc-discovery');
|
|
12
|
+
jest.mock('../security/kms-discovery');
|
|
13
|
+
jest.mock('../database/aurora-discovery');
|
|
14
|
+
jest.mock('../parameters/ssm-discovery');
|
|
15
|
+
|
|
16
|
+
const { CloudProviderFactory } = require('./providers/provider-factory');
|
|
17
|
+
const { VpcDiscovery } = require('../networking/vpc-discovery');
|
|
18
|
+
const { KmsDiscovery } = require('../security/kms-discovery');
|
|
19
|
+
const { AuroraDiscovery } = require('../database/aurora-discovery');
|
|
20
|
+
const { SsmDiscovery } = require('../parameters/ssm-discovery');
|
|
21
|
+
|
|
22
|
+
describe('Resource Discovery', () => {
|
|
23
|
+
let mockProvider;
|
|
24
|
+
let mockVpcDiscovery;
|
|
25
|
+
let mockKmsDiscovery;
|
|
26
|
+
let mockAuroraDiscovery;
|
|
27
|
+
let mockSsmDiscovery;
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
// Reset environment
|
|
31
|
+
delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
|
|
32
|
+
delete process.env.CLOUD_PROVIDER;
|
|
33
|
+
delete process.env.AWS_REGION;
|
|
34
|
+
|
|
35
|
+
// Create mock provider
|
|
36
|
+
mockProvider = {
|
|
37
|
+
getName: jest.fn().mockReturnValue('aws'),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Create mock discoveries with default responses
|
|
41
|
+
mockVpcDiscovery = {
|
|
42
|
+
discover: jest.fn().mockResolvedValue({
|
|
43
|
+
defaultVpcId: 'vpc-123',
|
|
44
|
+
privateSubnetId1: 'subnet-1',
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
mockKmsDiscovery = {
|
|
49
|
+
discover: jest.fn().mockResolvedValue({
|
|
50
|
+
kmsKeyId: 'arn:aws:kms:us-east-1:123:key/abc',
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
mockAuroraDiscovery = {
|
|
55
|
+
discover: jest.fn().mockResolvedValue({
|
|
56
|
+
auroraClusterEndpoint: 'db.example.com',
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
mockSsmDiscovery = {
|
|
61
|
+
discover: jest.fn().mockResolvedValue({
|
|
62
|
+
parameters: [],
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Mock factory and discovery constructors
|
|
67
|
+
CloudProviderFactory.create = jest.fn().mockReturnValue(mockProvider);
|
|
68
|
+
VpcDiscovery.mockImplementation(() => mockVpcDiscovery);
|
|
69
|
+
KmsDiscovery.mockImplementation(() => mockKmsDiscovery);
|
|
70
|
+
AuroraDiscovery.mockImplementation(() => mockAuroraDiscovery);
|
|
71
|
+
SsmDiscovery.mockImplementation(() => mockSsmDiscovery);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('shouldRunDiscovery()', () => {
|
|
75
|
+
it('should return false when FRIGG_SKIP_AWS_DISCOVERY is true', () => {
|
|
76
|
+
process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
|
|
77
|
+
|
|
78
|
+
const result = shouldRunDiscovery({ vpc: { enable: true } });
|
|
79
|
+
|
|
80
|
+
expect(result).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should return true when VPC is enabled', () => {
|
|
84
|
+
const result = shouldRunDiscovery({ vpc: { enable: true } });
|
|
85
|
+
|
|
86
|
+
expect(result).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should return true when KMS encryption is enabled', () => {
|
|
90
|
+
const result = shouldRunDiscovery({
|
|
91
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(result).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should return true when SSM is enabled', () => {
|
|
98
|
+
const result = shouldRunDiscovery({ ssm: { enable: true } });
|
|
99
|
+
|
|
100
|
+
expect(result).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should return true when Postgres database is enabled', () => {
|
|
104
|
+
const result = shouldRunDiscovery({
|
|
105
|
+
database: { postgres: { enable: true } },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should return false when no features require discovery', () => {
|
|
112
|
+
const result = shouldRunDiscovery({
|
|
113
|
+
vpc: { enable: false },
|
|
114
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
115
|
+
ssm: { enable: false },
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(result).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return false for empty app definition', () => {
|
|
122
|
+
const result = shouldRunDiscovery({});
|
|
123
|
+
|
|
124
|
+
expect(result).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('gatherDiscoveredResources()', () => {
|
|
129
|
+
it('should skip discovery when not needed', async () => {
|
|
130
|
+
const appDefinition = {
|
|
131
|
+
vpc: { enable: false },
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
135
|
+
|
|
136
|
+
expect(result).toEqual({});
|
|
137
|
+
expect(CloudProviderFactory.create).not.toHaveBeenCalled();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should create AWS provider by default', async () => {
|
|
141
|
+
const appDefinition = {
|
|
142
|
+
vpc: { enable: true },
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
await gatherDiscoveredResources(appDefinition);
|
|
146
|
+
|
|
147
|
+
expect(CloudProviderFactory.create).toHaveBeenCalledWith('aws', 'us-east-1');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should respect CLOUD_PROVIDER environment variable', async () => {
|
|
151
|
+
process.env.CLOUD_PROVIDER = 'gcp';
|
|
152
|
+
process.env.AWS_REGION = 'us-central1';
|
|
153
|
+
|
|
154
|
+
const appDefinition = {
|
|
155
|
+
vpc: { enable: true },
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
await gatherDiscoveredResources(appDefinition);
|
|
159
|
+
|
|
160
|
+
expect(CloudProviderFactory.create).toHaveBeenCalledWith('gcp', 'us-central1');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should respect AWS_REGION environment variable', async () => {
|
|
164
|
+
process.env.AWS_REGION = 'eu-west-1';
|
|
165
|
+
|
|
166
|
+
const appDefinition = {
|
|
167
|
+
vpc: { enable: true },
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
await gatherDiscoveredResources(appDefinition);
|
|
171
|
+
|
|
172
|
+
expect(CloudProviderFactory.create).toHaveBeenCalledWith('aws', 'eu-west-1');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should create discovery services with provider', async () => {
|
|
176
|
+
const appDefinition = {
|
|
177
|
+
vpc: { enable: true },
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
await gatherDiscoveredResources(appDefinition);
|
|
181
|
+
|
|
182
|
+
expect(VpcDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
183
|
+
expect(KmsDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
184
|
+
expect(AuroraDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
185
|
+
expect(SsmDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should run VPC discovery when enabled', async () => {
|
|
189
|
+
const appDefinition = {
|
|
190
|
+
name: 'test-app',
|
|
191
|
+
vpc: { enable: true },
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
await gatherDiscoveredResources(appDefinition);
|
|
195
|
+
|
|
196
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
197
|
+
expect.objectContaining({
|
|
198
|
+
serviceName: 'test-app',
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should skip VPC discovery when disabled', async () => {
|
|
204
|
+
const appDefinition = {
|
|
205
|
+
vpc: { enable: false },
|
|
206
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
await gatherDiscoveredResources(appDefinition);
|
|
210
|
+
|
|
211
|
+
expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should run KMS discovery when encryption is kms', async () => {
|
|
215
|
+
const appDefinition = {
|
|
216
|
+
name: 'test-app',
|
|
217
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
await gatherDiscoveredResources(appDefinition);
|
|
221
|
+
|
|
222
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should skip KMS discovery when encryption is not kms', async () => {
|
|
226
|
+
const appDefinition = {
|
|
227
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
228
|
+
vpc: { enable: true },
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await gatherDiscoveredResources(appDefinition);
|
|
232
|
+
|
|
233
|
+
expect(mockKmsDiscovery.discover).not.toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should run database discovery when postgres is enabled', async () => {
|
|
237
|
+
const appDefinition = {
|
|
238
|
+
database: { postgres: { enable: true } },
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
await gatherDiscoveredResources(appDefinition);
|
|
242
|
+
|
|
243
|
+
expect(mockAuroraDiscovery.discover).toHaveBeenCalled();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should skip database discovery when postgres is disabled', async () => {
|
|
247
|
+
const appDefinition = {
|
|
248
|
+
database: { postgres: { enable: false } },
|
|
249
|
+
vpc: { enable: true },
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
await gatherDiscoveredResources(appDefinition);
|
|
253
|
+
|
|
254
|
+
expect(mockAuroraDiscovery.discover).not.toHaveBeenCalled();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should run SSM discovery when enabled', async () => {
|
|
258
|
+
const appDefinition = {
|
|
259
|
+
ssm: { enable: true },
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
await gatherDiscoveredResources(appDefinition);
|
|
263
|
+
|
|
264
|
+
expect(mockSsmDiscovery.discover).toHaveBeenCalled();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should aggregate results from all discoveries', async () => {
|
|
268
|
+
mockVpcDiscovery.discover.mockResolvedValue({
|
|
269
|
+
defaultVpcId: 'vpc-123',
|
|
270
|
+
privateSubnetId1: 'subnet-1',
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
mockKmsDiscovery.discover.mockResolvedValue({
|
|
274
|
+
kmsKeyId: 'arn:aws:kms:key/abc',
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
mockAuroraDiscovery.discover.mockResolvedValue({
|
|
278
|
+
auroraClusterEndpoint: 'db.example.com',
|
|
279
|
+
auroraPort: 5432,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
mockSsmDiscovery.discover.mockResolvedValue({
|
|
283
|
+
parameters: ['param1'],
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const appDefinition = {
|
|
287
|
+
vpc: { enable: true },
|
|
288
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
289
|
+
database: { postgres: { enable: true } },
|
|
290
|
+
ssm: { enable: true },
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
294
|
+
|
|
295
|
+
expect(result).toEqual({
|
|
296
|
+
defaultVpcId: 'vpc-123',
|
|
297
|
+
privateSubnetId1: 'subnet-1',
|
|
298
|
+
kmsKeyId: 'arn:aws:kms:key/abc',
|
|
299
|
+
auroraClusterEndpoint: 'db.example.com',
|
|
300
|
+
auroraPort: 5432,
|
|
301
|
+
parameters: ['param1'],
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should run discoveries in parallel for performance', async () => {
|
|
306
|
+
const appDefinition = {
|
|
307
|
+
vpc: { enable: true },
|
|
308
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
309
|
+
database: { postgres: { enable: true } },
|
|
310
|
+
ssm: { enable: true },
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
await gatherDiscoveredResources(appDefinition);
|
|
314
|
+
|
|
315
|
+
// All should have been called (proving parallel execution)
|
|
316
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalled();
|
|
317
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalled();
|
|
318
|
+
expect(mockAuroraDiscovery.discover).toHaveBeenCalled();
|
|
319
|
+
expect(mockSsmDiscovery.discover).toHaveBeenCalled();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should handle discovery errors gracefully', async () => {
|
|
323
|
+
mockVpcDiscovery.discover.mockRejectedValue(new Error('VPC API Error'));
|
|
324
|
+
|
|
325
|
+
const appDefinition = {
|
|
326
|
+
vpc: { enable: true },
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
330
|
+
|
|
331
|
+
// Should return empty object instead of throwing
|
|
332
|
+
expect(result).toEqual({});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should pass configuration to discoveries', async () => {
|
|
336
|
+
const appDefinition = {
|
|
337
|
+
name: 'my-service',
|
|
338
|
+
vpc: {
|
|
339
|
+
enable: true,
|
|
340
|
+
vpcId: 'vpc-custom',
|
|
341
|
+
},
|
|
342
|
+
database: {
|
|
343
|
+
postgres: {
|
|
344
|
+
enable: true,
|
|
345
|
+
clusterId: 'my-cluster',
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
encryption: {
|
|
349
|
+
fieldLevelEncryptionMethod: 'kms',
|
|
350
|
+
keyAlias: 'alias/my-key',
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
process.env.SLS_STAGE = 'production';
|
|
355
|
+
|
|
356
|
+
await gatherDiscoveredResources(appDefinition);
|
|
357
|
+
|
|
358
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
359
|
+
expect.objectContaining({
|
|
360
|
+
serviceName: 'my-service',
|
|
361
|
+
stage: 'production',
|
|
362
|
+
vpcId: 'vpc-custom',
|
|
363
|
+
})
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
expect(mockAuroraDiscovery.discover).toHaveBeenCalledWith(
|
|
367
|
+
expect.objectContaining({
|
|
368
|
+
databaseId: 'my-cluster',
|
|
369
|
+
})
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalledWith(
|
|
373
|
+
expect.objectContaining({
|
|
374
|
+
keyAlias: 'alias/my-key',
|
|
375
|
+
})
|
|
376
|
+
);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('should default stage to dev', async () => {
|
|
380
|
+
delete process.env.SLS_STAGE;
|
|
381
|
+
|
|
382
|
+
const appDefinition = {
|
|
383
|
+
vpc: { enable: true },
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
await gatherDiscoveredResources(appDefinition);
|
|
387
|
+
|
|
388
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
389
|
+
expect.objectContaining({
|
|
390
|
+
stage: 'dev',
|
|
391
|
+
})
|
|
392
|
+
);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('should read stage from SLS_STAGE environment variable for CLI integration', async () => {
|
|
396
|
+
// This test documents the contract between frigg CLI and discovery
|
|
397
|
+
// The CLI sets SLS_STAGE environment variable when user passes --stage flag
|
|
398
|
+
process.env.SLS_STAGE = 'qa';
|
|
399
|
+
|
|
400
|
+
const appDefinition = {
|
|
401
|
+
name: 'quo-integrations',
|
|
402
|
+
vpc: { enable: true },
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
await gatherDiscoveredResources(appDefinition);
|
|
406
|
+
|
|
407
|
+
// Verify stage is read from SLS_STAGE
|
|
408
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
409
|
+
expect.objectContaining({
|
|
410
|
+
serviceName: 'quo-integrations',
|
|
411
|
+
stage: 'qa',
|
|
412
|
+
})
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
delete process.env.SLS_STAGE;
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('should include secrets in SSM discovery by default', async () => {
|
|
419
|
+
const appDefinition = {
|
|
420
|
+
ssm: { enable: true },
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
await gatherDiscoveredResources(appDefinition);
|
|
424
|
+
|
|
425
|
+
expect(mockSsmDiscovery.discover).toHaveBeenCalledWith(
|
|
426
|
+
expect.objectContaining({
|
|
427
|
+
includeSecrets: true,
|
|
428
|
+
})
|
|
429
|
+
);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
describe('Isolated Mode Discovery', () => {
|
|
434
|
+
beforeEach(() => {
|
|
435
|
+
// Mock CloudFormation discovery
|
|
436
|
+
jest.mock('./cloudformation-discovery');
|
|
437
|
+
const { CloudFormationDiscovery } = require('./cloudformation-discovery');
|
|
438
|
+
CloudFormationDiscovery.mockImplementation(() => ({
|
|
439
|
+
discoverFromStack: jest.fn().mockResolvedValue({}), // No stack found
|
|
440
|
+
}));
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('should discover KMS but not VPC/Aurora in isolated mode', async () => {
|
|
444
|
+
const appDefinition = {
|
|
445
|
+
name: 'test-app',
|
|
446
|
+
managementMode: 'managed',
|
|
447
|
+
vpcIsolation: 'isolated',
|
|
448
|
+
vpc: { enable: true },
|
|
449
|
+
database: { postgres: { enable: true } },
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
process.env.SLS_STAGE = 'dev';
|
|
453
|
+
|
|
454
|
+
// Mock KMS discovery returning a shared key
|
|
455
|
+
mockKmsDiscovery.discover.mockResolvedValue({
|
|
456
|
+
defaultKmsKeyId: 'shared-kms-key-123',
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
460
|
+
|
|
461
|
+
// Should return KMS (shareable) but not VPC/Aurora (isolated)
|
|
462
|
+
expect(result).toEqual({
|
|
463
|
+
defaultKmsKeyId: 'shared-kms-key-123',
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// Should call KMS discovery (shared) but NOT VPC/Aurora discovery (isolated)
|
|
467
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalled();
|
|
468
|
+
expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
|
|
469
|
+
expect(mockAuroraDiscovery.discover).not.toHaveBeenCalled();
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('should return empty if no KMS found in isolated mode (fresh infrastructure)', async () => {
|
|
473
|
+
const { CloudFormationDiscovery } = require('./cloudformation-discovery');
|
|
474
|
+
|
|
475
|
+
// Mock that CF stack exists but we still want fresh resources
|
|
476
|
+
CloudFormationDiscovery.mockImplementation(() => ({
|
|
477
|
+
discoverFromStack: jest.fn().mockResolvedValue({}), // Stack exists but empty
|
|
478
|
+
}));
|
|
479
|
+
|
|
480
|
+
const appDefinition = {
|
|
481
|
+
name: 'test-app',
|
|
482
|
+
managementMode: 'managed',
|
|
483
|
+
vpcIsolation: 'isolated',
|
|
484
|
+
vpc: { enable: true },
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
process.env.SLS_STAGE = 'dev';
|
|
488
|
+
|
|
489
|
+
// Mock KMS discovery finding nothing
|
|
490
|
+
mockKmsDiscovery.discover.mockResolvedValue({});
|
|
491
|
+
|
|
492
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
493
|
+
|
|
494
|
+
// Should return empty (no VPC/Aurora, and KMS not found)
|
|
495
|
+
// This will trigger fresh KMS creation
|
|
496
|
+
expect(result).toEqual({});
|
|
497
|
+
|
|
498
|
+
// Should call KMS discovery but NOT VPC/Aurora
|
|
499
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalled();
|
|
500
|
+
expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('should use AWS API discovery in shared mode', async () => {
|
|
504
|
+
const appDefinition = {
|
|
505
|
+
name: 'test-app',
|
|
506
|
+
managementMode: 'managed',
|
|
507
|
+
vpcIsolation: 'shared', // NOT isolated
|
|
508
|
+
vpc: { enable: true },
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
await gatherDiscoveredResources(appDefinition);
|
|
512
|
+
|
|
513
|
+
// Should call AWS API discovery (shared mode finds resources across stages)
|
|
514
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalled();
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
it('should search for specific KMS alias in isolated mode to find orphaned keys', async () => {
|
|
518
|
+
const appDefinition = {
|
|
519
|
+
name: 'quo-integrations',
|
|
520
|
+
managementMode: 'managed',
|
|
521
|
+
vpcIsolation: 'isolated',
|
|
522
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
process.env.SLS_STAGE = 'dev';
|
|
526
|
+
|
|
527
|
+
// Mock KMS discovery finding key via alias search
|
|
528
|
+
mockKmsDiscovery.discover.mockResolvedValue({
|
|
529
|
+
defaultKmsKeyId: 'arn:aws:kms:us-east-1:123:key/found-via-alias',
|
|
530
|
+
kmsKeyAlias: 'alias/quo-integrations-dev-frigg-kms',
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
534
|
+
|
|
535
|
+
// Should pass keyAlias to discover orphaned KMS keys
|
|
536
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalledWith(
|
|
537
|
+
expect.objectContaining({
|
|
538
|
+
serviceName: 'quo-integrations',
|
|
539
|
+
stage: 'dev',
|
|
540
|
+
keyAlias: 'alias/quo-integrations-dev-frigg-kms',
|
|
541
|
+
})
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
// Should return discovered KMS key (even if orphaned from stack)
|
|
545
|
+
expect(result).toEqual({
|
|
546
|
+
defaultKmsKeyId: 'arn:aws:kms:us-east-1:123:key/found-via-alias',
|
|
547
|
+
kmsKeyAlias: 'alias/quo-integrations-dev-frigg-kms',
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
|