@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,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for PropertyMismatch Entity
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const PropertyMismatch = require('./property-mismatch');
|
|
6
|
+
const PropertyMutability = require('../value-objects/property-mutability');
|
|
7
|
+
|
|
8
|
+
describe('PropertyMismatch', () => {
|
|
9
|
+
describe('constructor', () => {
|
|
10
|
+
it('should create property mismatch with all fields', () => {
|
|
11
|
+
const mismatch = new PropertyMismatch({
|
|
12
|
+
propertyPath: 'Properties.BucketName',
|
|
13
|
+
expectedValue: 'my-app-prod-bucket',
|
|
14
|
+
actualValue: 'my-app-dev-bucket',
|
|
15
|
+
mutability: PropertyMutability.IMMUTABLE,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(mismatch.propertyPath).toBe('Properties.BucketName');
|
|
19
|
+
expect(mismatch.expectedValue).toBe('my-app-prod-bucket');
|
|
20
|
+
expect(mismatch.actualValue).toBe('my-app-dev-bucket');
|
|
21
|
+
expect(mismatch.mutability.value).toBe('IMMUTABLE');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should require propertyPath', () => {
|
|
25
|
+
expect(() => {
|
|
26
|
+
new PropertyMismatch({
|
|
27
|
+
expectedValue: 'value1',
|
|
28
|
+
actualValue: 'value2',
|
|
29
|
+
mutability: PropertyMutability.MUTABLE,
|
|
30
|
+
});
|
|
31
|
+
}).toThrow('propertyPath is required');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should require expectedValue parameter', () => {
|
|
35
|
+
expect(() => {
|
|
36
|
+
new PropertyMismatch({
|
|
37
|
+
propertyPath: 'Properties.Name',
|
|
38
|
+
actualValue: 'value2',
|
|
39
|
+
mutability: PropertyMutability.MUTABLE,
|
|
40
|
+
});
|
|
41
|
+
}).toThrow('expectedValue must be provided');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should require actualValue parameter', () => {
|
|
45
|
+
expect(() => {
|
|
46
|
+
new PropertyMismatch({
|
|
47
|
+
propertyPath: 'Properties.Name',
|
|
48
|
+
expectedValue: 'value1',
|
|
49
|
+
mutability: PropertyMutability.MUTABLE,
|
|
50
|
+
});
|
|
51
|
+
}).toThrow('actualValue must be provided');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should accept undefined as expectedValue', () => {
|
|
55
|
+
const mismatch = new PropertyMismatch({
|
|
56
|
+
propertyPath: 'Properties.NewProperty',
|
|
57
|
+
expectedValue: undefined,
|
|
58
|
+
actualValue: 'new-value',
|
|
59
|
+
mutability: PropertyMutability.MUTABLE,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(mismatch.expectedValue).toBeUndefined();
|
|
63
|
+
expect(mismatch.actualValue).toBe('new-value');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should accept undefined as actualValue', () => {
|
|
67
|
+
const mismatch = new PropertyMismatch({
|
|
68
|
+
propertyPath: 'Properties.OldProperty',
|
|
69
|
+
expectedValue: 'old-value',
|
|
70
|
+
actualValue: undefined,
|
|
71
|
+
mutability: PropertyMutability.MUTABLE,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(mismatch.expectedValue).toBe('old-value');
|
|
75
|
+
expect(mismatch.actualValue).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should require mutability', () => {
|
|
79
|
+
expect(() => {
|
|
80
|
+
new PropertyMismatch({
|
|
81
|
+
propertyPath: 'Properties.Name',
|
|
82
|
+
expectedValue: 'value1',
|
|
83
|
+
actualValue: 'value2',
|
|
84
|
+
});
|
|
85
|
+
}).toThrow('mutability is required');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should accept null as expectedValue', () => {
|
|
89
|
+
const mismatch = new PropertyMismatch({
|
|
90
|
+
propertyPath: 'Properties.Tags',
|
|
91
|
+
expectedValue: null,
|
|
92
|
+
actualValue: ['tag1', 'tag2'],
|
|
93
|
+
mutability: PropertyMutability.MUTABLE,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(mismatch.expectedValue).toBeNull();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should accept null as actualValue', () => {
|
|
100
|
+
const mismatch = new PropertyMismatch({
|
|
101
|
+
propertyPath: 'Properties.Tags',
|
|
102
|
+
expectedValue: ['tag1', 'tag2'],
|
|
103
|
+
actualValue: null,
|
|
104
|
+
mutability: PropertyMutability.MUTABLE,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
expect(mismatch.actualValue).toBeNull();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('requiresReplacement', () => {
|
|
112
|
+
it('should return true for immutable property', () => {
|
|
113
|
+
const mismatch = new PropertyMismatch({
|
|
114
|
+
propertyPath: 'Properties.BucketName',
|
|
115
|
+
expectedValue: 'bucket1',
|
|
116
|
+
actualValue: 'bucket2',
|
|
117
|
+
mutability: PropertyMutability.IMMUTABLE,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(mismatch.requiresReplacement()).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should return false for mutable property', () => {
|
|
124
|
+
const mismatch = new PropertyMismatch({
|
|
125
|
+
propertyPath: 'Properties.Tags',
|
|
126
|
+
expectedValue: ['tag1'],
|
|
127
|
+
actualValue: ['tag2'],
|
|
128
|
+
mutability: PropertyMutability.MUTABLE,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(mismatch.requiresReplacement()).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should return false for conditional property', () => {
|
|
135
|
+
const mismatch = new PropertyMismatch({
|
|
136
|
+
propertyPath: 'Properties.EngineVersion',
|
|
137
|
+
expectedValue: '5.7',
|
|
138
|
+
actualValue: '5.6',
|
|
139
|
+
mutability: PropertyMutability.CONDITIONAL,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(mismatch.requiresReplacement()).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('canAutoFix', () => {
|
|
147
|
+
it('should return true for mutable property', () => {
|
|
148
|
+
const mismatch = new PropertyMismatch({
|
|
149
|
+
propertyPath: 'Properties.Tags',
|
|
150
|
+
expectedValue: ['tag1'],
|
|
151
|
+
actualValue: ['tag2'],
|
|
152
|
+
mutability: PropertyMutability.MUTABLE,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(mismatch.canAutoFix()).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should return false for immutable property', () => {
|
|
159
|
+
const mismatch = new PropertyMismatch({
|
|
160
|
+
propertyPath: 'Properties.BucketName',
|
|
161
|
+
expectedValue: 'bucket1',
|
|
162
|
+
actualValue: 'bucket2',
|
|
163
|
+
mutability: PropertyMutability.IMMUTABLE,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
expect(mismatch.canAutoFix()).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should return false for conditional property', () => {
|
|
170
|
+
const mismatch = new PropertyMismatch({
|
|
171
|
+
propertyPath: 'Properties.EngineVersion',
|
|
172
|
+
expectedValue: '5.7',
|
|
173
|
+
actualValue: '5.6',
|
|
174
|
+
mutability: PropertyMutability.CONDITIONAL,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(mismatch.canAutoFix()).toBe(false);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('getSeverity', () => {
|
|
182
|
+
it('should return critical for immutable property mismatch', () => {
|
|
183
|
+
const mismatch = new PropertyMismatch({
|
|
184
|
+
propertyPath: 'Properties.BucketName',
|
|
185
|
+
expectedValue: 'bucket1',
|
|
186
|
+
actualValue: 'bucket2',
|
|
187
|
+
mutability: PropertyMutability.IMMUTABLE,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
expect(mismatch.getSeverity()).toBe('critical');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should return warning for mutable property mismatch', () => {
|
|
194
|
+
const mismatch = new PropertyMismatch({
|
|
195
|
+
propertyPath: 'Properties.Tags',
|
|
196
|
+
expectedValue: ['tag1'],
|
|
197
|
+
actualValue: ['tag2'],
|
|
198
|
+
mutability: PropertyMutability.MUTABLE,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(mismatch.getSeverity()).toBe('warning');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return warning for conditional property mismatch', () => {
|
|
205
|
+
const mismatch = new PropertyMismatch({
|
|
206
|
+
propertyPath: 'Properties.EngineVersion',
|
|
207
|
+
expectedValue: '5.7',
|
|
208
|
+
actualValue: '5.6',
|
|
209
|
+
mutability: PropertyMutability.CONDITIONAL,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(mismatch.getSeverity()).toBe('warning');
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe('toString', () => {
|
|
217
|
+
it('should return string representation', () => {
|
|
218
|
+
const mismatch = new PropertyMismatch({
|
|
219
|
+
propertyPath: 'Properties.BucketName',
|
|
220
|
+
expectedValue: 'bucket1',
|
|
221
|
+
actualValue: 'bucket2',
|
|
222
|
+
mutability: PropertyMutability.IMMUTABLE,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
expect(mismatch.toString()).toBe(
|
|
226
|
+
'PropertyMismatch: Properties.BucketName (expected: bucket1, actual: bucket2, mutability: IMMUTABLE)'
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should handle null expected value', () => {
|
|
231
|
+
const mismatch = new PropertyMismatch({
|
|
232
|
+
propertyPath: 'Properties.Tags',
|
|
233
|
+
expectedValue: null,
|
|
234
|
+
actualValue: ['tag1'],
|
|
235
|
+
mutability: PropertyMutability.MUTABLE,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
expect(mismatch.toString()).toContain('expected: null');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should handle null actual value', () => {
|
|
242
|
+
const mismatch = new PropertyMismatch({
|
|
243
|
+
propertyPath: 'Properties.Tags',
|
|
244
|
+
expectedValue: ['tag1'],
|
|
245
|
+
actualValue: null,
|
|
246
|
+
mutability: PropertyMutability.MUTABLE,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
expect(mismatch.toString()).toContain('actual: null');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('toJSON', () => {
|
|
254
|
+
it('should serialize to JSON', () => {
|
|
255
|
+
const mismatch = new PropertyMismatch({
|
|
256
|
+
propertyPath: 'Properties.BucketName',
|
|
257
|
+
expectedValue: 'bucket1',
|
|
258
|
+
actualValue: 'bucket2',
|
|
259
|
+
mutability: PropertyMutability.IMMUTABLE,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const json = mismatch.toJSON();
|
|
263
|
+
|
|
264
|
+
expect(json).toEqual({
|
|
265
|
+
propertyPath: 'Properties.BucketName',
|
|
266
|
+
expectedValue: 'bucket1',
|
|
267
|
+
actualValue: 'bucket2',
|
|
268
|
+
mutability: 'IMMUTABLE',
|
|
269
|
+
severity: 'critical',
|
|
270
|
+
canAutoFix: false,
|
|
271
|
+
requiresReplacement: true,
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Entity
|
|
3
|
+
*
|
|
4
|
+
* Represents a CloudFormation resource with its current state and any detected issues
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const ResourceState = require('../value-objects/resource-state');
|
|
8
|
+
|
|
9
|
+
class Resource {
|
|
10
|
+
/**
|
|
11
|
+
* Create a new Resource
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} params
|
|
14
|
+
* @param {string|null} params.logicalId - CloudFormation logical ID (null for orphaned resources)
|
|
15
|
+
* @param {string} params.physicalId - Physical resource ID in cloud provider
|
|
16
|
+
* @param {string} params.resourceType - CloudFormation resource type (e.g., AWS::EC2::VPC)
|
|
17
|
+
* @param {ResourceState} params.state - Resource state
|
|
18
|
+
* @param {Object} [params.properties={}] - Resource properties
|
|
19
|
+
* @param {Issue[]} [params.issues=[]] - Detected issues with this resource
|
|
20
|
+
*/
|
|
21
|
+
constructor({
|
|
22
|
+
logicalId = null,
|
|
23
|
+
physicalId,
|
|
24
|
+
resourceType,
|
|
25
|
+
state,
|
|
26
|
+
properties = {},
|
|
27
|
+
issues = [],
|
|
28
|
+
}) {
|
|
29
|
+
// Validate required fields
|
|
30
|
+
if (physicalId === undefined || physicalId === null) {
|
|
31
|
+
throw new Error('physicalId is required');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!resourceType) {
|
|
35
|
+
throw new Error('resourceType is required');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!state) {
|
|
39
|
+
throw new Error('state is required');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!(state instanceof ResourceState)) {
|
|
43
|
+
throw new Error('state must be a ResourceState instance');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.logicalId = logicalId;
|
|
47
|
+
this.physicalId = physicalId;
|
|
48
|
+
this.resourceType = resourceType;
|
|
49
|
+
this.state = state;
|
|
50
|
+
this.properties = properties;
|
|
51
|
+
this.issues = [...issues]; // Copy array to avoid mutations
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if resource is in CloudFormation stack
|
|
56
|
+
* @returns {boolean}
|
|
57
|
+
*/
|
|
58
|
+
isInStack() {
|
|
59
|
+
return this.state.isInStack();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if resource is orphaned (exists in cloud but not in stack)
|
|
64
|
+
* @returns {boolean}
|
|
65
|
+
*/
|
|
66
|
+
isOrphaned() {
|
|
67
|
+
return this.state.isOrphaned();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check if resource is missing (exists in stack but not in cloud)
|
|
72
|
+
* @returns {boolean}
|
|
73
|
+
*/
|
|
74
|
+
isMissing() {
|
|
75
|
+
return this.state.isMissing();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if resource has drifted (properties differ)
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
*/
|
|
82
|
+
isDrifted() {
|
|
83
|
+
return this.state.isDrifted();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Add an issue to this resource
|
|
88
|
+
* @param {Issue} issue
|
|
89
|
+
*/
|
|
90
|
+
addIssue(issue) {
|
|
91
|
+
this.issues.push(issue);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if resource has any issues
|
|
96
|
+
* @returns {boolean}
|
|
97
|
+
*/
|
|
98
|
+
hasIssues() {
|
|
99
|
+
return this.issues.length > 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check if resource has critical issues
|
|
104
|
+
* @returns {boolean}
|
|
105
|
+
*/
|
|
106
|
+
hasCriticalIssues() {
|
|
107
|
+
return this.issues.some(issue => issue.isCritical());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get all critical issues
|
|
112
|
+
* @returns {Issue[]}
|
|
113
|
+
*/
|
|
114
|
+
getCriticalIssues() {
|
|
115
|
+
return this.issues.filter(issue => issue.isCritical());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if resource is healthy (no issues)
|
|
120
|
+
* @returns {boolean}
|
|
121
|
+
*/
|
|
122
|
+
isHealthy() {
|
|
123
|
+
return !this.hasIssues();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get resource identifier (logical ID or physical ID)
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
getIdentifier() {
|
|
131
|
+
return this.logicalId || this.physicalId;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get string representation
|
|
136
|
+
* @returns {string}
|
|
137
|
+
*/
|
|
138
|
+
toString() {
|
|
139
|
+
return `Resource: ${this.resourceType} [${this.state.toString()}] - LogicalId: ${this.logicalId}, PhysicalId: ${this.physicalId}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Serialize to JSON
|
|
144
|
+
* @returns {Object}
|
|
145
|
+
*/
|
|
146
|
+
toJSON() {
|
|
147
|
+
return {
|
|
148
|
+
logicalId: this.logicalId,
|
|
149
|
+
physicalId: this.physicalId,
|
|
150
|
+
resourceType: this.resourceType,
|
|
151
|
+
state: this.state.toString(),
|
|
152
|
+
properties: this.properties,
|
|
153
|
+
issues: this.issues.map(issue => issue.toJSON()),
|
|
154
|
+
isHealthy: this.isHealthy(),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = Resource;
|