@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/infrastructure/ARCHITECTURE.md +487 -0
  2. package/infrastructure/HEALTH.md +468 -0
  3. package/infrastructure/README.md +51 -0
  4. package/infrastructure/__tests__/postgres-config.test.js +914 -0
  5. package/infrastructure/__tests__/template-generation.test.js +687 -0
  6. package/infrastructure/create-frigg-infrastructure.js +1 -1
  7. package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
  8. package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
  9. package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
  10. package/infrastructure/domains/database/aurora-builder.js +809 -0
  11. package/infrastructure/domains/database/aurora-builder.test.js +950 -0
  12. package/infrastructure/domains/database/aurora-discovery.js +87 -0
  13. package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
  14. package/infrastructure/domains/database/aurora-resolver.js +210 -0
  15. package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
  16. package/infrastructure/domains/database/migration-builder.js +695 -0
  17. package/infrastructure/domains/database/migration-builder.test.js +294 -0
  18. package/infrastructure/domains/database/migration-resolver.js +163 -0
  19. package/infrastructure/domains/database/migration-resolver.test.js +337 -0
  20. package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
  21. package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
  22. package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
  23. package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
  24. package/infrastructure/domains/health/application/ports/index.js +26 -0
  25. package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
  26. package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
  27. package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
  28. package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
  29. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
  30. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
  31. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
  32. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
  33. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
  34. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
  35. package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
  36. package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
  37. package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
  38. package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
  39. package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
  40. package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
  41. package/infrastructure/domains/health/domain/entities/issue.js +299 -0
  42. package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
  43. package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
  44. package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
  45. package/infrastructure/domains/health/domain/entities/resource.js +159 -0
  46. package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
  47. package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
  48. package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
  49. package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
  50. package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
  51. package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
  52. package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
  53. package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
  54. package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
  55. package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
  56. package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
  57. package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
  58. package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
  59. package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
  60. package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
  61. package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
  62. package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
  63. package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
  64. package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
  65. package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
  66. package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
  67. package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
  68. package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
  69. package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
  70. package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
  71. package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
  72. package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
  73. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
  74. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
  75. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
  76. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
  77. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
  78. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
  79. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
  80. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
  81. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
  82. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
  83. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
  84. package/infrastructure/domains/integration/integration-builder.js +397 -0
  85. package/infrastructure/domains/integration/integration-builder.test.js +593 -0
  86. package/infrastructure/domains/integration/integration-resolver.js +170 -0
  87. package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
  88. package/infrastructure/domains/integration/websocket-builder.js +69 -0
  89. package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
  90. package/infrastructure/domains/networking/vpc-builder.js +1829 -0
  91. package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
  92. package/infrastructure/domains/networking/vpc-discovery.js +177 -0
  93. package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
  94. package/infrastructure/domains/networking/vpc-resolver.js +324 -0
  95. package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
  96. package/infrastructure/domains/parameters/ssm-builder.js +79 -0
  97. package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
  98. package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
  99. package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
  100. package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
  101. package/infrastructure/domains/security/kms-builder.js +366 -0
  102. package/infrastructure/domains/security/kms-builder.test.js +374 -0
  103. package/infrastructure/domains/security/kms-discovery.js +80 -0
  104. package/infrastructure/domains/security/kms-discovery.test.js +177 -0
  105. package/infrastructure/domains/security/kms-resolver.js +96 -0
  106. package/infrastructure/domains/security/kms-resolver.test.js +216 -0
  107. package/infrastructure/domains/shared/base-builder.js +112 -0
  108. package/infrastructure/domains/shared/base-resolver.js +186 -0
  109. package/infrastructure/domains/shared/base-resolver.test.js +305 -0
  110. package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
  111. package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
  112. package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
  113. package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
  114. package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
  115. package/infrastructure/domains/shared/environment-builder.js +119 -0
  116. package/infrastructure/domains/shared/environment-builder.test.js +247 -0
  117. package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
  118. package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
  119. package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
  120. package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
  121. package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
  122. package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
  123. package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
  124. package/infrastructure/domains/shared/resource-discovery.js +192 -0
  125. package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
  126. package/infrastructure/domains/shared/types/app-definition.js +205 -0
  127. package/infrastructure/domains/shared/types/discovery-result.js +106 -0
  128. package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
  129. package/infrastructure/domains/shared/types/index.js +46 -0
  130. package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
  131. package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
  132. package/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
  133. package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
  134. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
  135. package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
  136. package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
  137. package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
  138. package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
  139. package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
  140. package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
  141. package/infrastructure/esbuild.config.js +53 -0
  142. package/infrastructure/infrastructure-composer.js +87 -0
  143. package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
  144. package/infrastructure/scripts/build-prisma-layer.js +553 -0
  145. package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
  146. package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
  147. package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
  148. package/layers/prisma/nodejs/package.json +8 -0
  149. package/management-ui/server/utils/cliIntegration.js +1 -1
  150. package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
  151. package/package.json +11 -11
  152. package/frigg-cli/.eslintrc.js +0 -141
  153. package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
  154. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
  155. package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
  156. package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
  157. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
  158. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
  159. package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
  160. package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
  161. package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
  162. package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
  163. package/frigg-cli/__tests__/utils/test-setup.js +0 -287
  164. package/frigg-cli/build-command/index.js +0 -65
  165. package/frigg-cli/db-setup-command/index.js +0 -193
  166. package/frigg-cli/deploy-command/index.js +0 -175
  167. package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
  168. package/frigg-cli/generate-command/azure-generator.js +0 -43
  169. package/frigg-cli/generate-command/gcp-generator.js +0 -47
  170. package/frigg-cli/generate-command/index.js +0 -332
  171. package/frigg-cli/generate-command/terraform-generator.js +0 -555
  172. package/frigg-cli/generate-iam-command.js +0 -118
  173. package/frigg-cli/index.js +0 -75
  174. package/frigg-cli/index.test.js +0 -158
  175. package/frigg-cli/init-command/backend-first-handler.js +0 -756
  176. package/frigg-cli/init-command/index.js +0 -93
  177. package/frigg-cli/init-command/template-handler.js +0 -143
  178. package/frigg-cli/install-command/backend-js.js +0 -33
  179. package/frigg-cli/install-command/commit-changes.js +0 -16
  180. package/frigg-cli/install-command/environment-variables.js +0 -127
  181. package/frigg-cli/install-command/environment-variables.test.js +0 -136
  182. package/frigg-cli/install-command/index.js +0 -54
  183. package/frigg-cli/install-command/install-package.js +0 -13
  184. package/frigg-cli/install-command/integration-file.js +0 -30
  185. package/frigg-cli/install-command/logger.js +0 -12
  186. package/frigg-cli/install-command/template.js +0 -90
  187. package/frigg-cli/install-command/validate-package.js +0 -75
  188. package/frigg-cli/jest.config.js +0 -124
  189. package/frigg-cli/package.json +0 -54
  190. package/frigg-cli/start-command/index.js +0 -149
  191. package/frigg-cli/start-command/start-command.test.js +0 -297
  192. package/frigg-cli/test/init-command.test.js +0 -180
  193. package/frigg-cli/test/npm-registry.test.js +0 -319
  194. package/frigg-cli/ui-command/index.js +0 -154
  195. package/frigg-cli/utils/app-resolver.js +0 -319
  196. package/frigg-cli/utils/backend-path.js +0 -25
  197. package/frigg-cli/utils/database-validator.js +0 -161
  198. package/frigg-cli/utils/error-messages.js +0 -257
  199. package/frigg-cli/utils/npm-registry.js +0 -167
  200. package/frigg-cli/utils/prisma-runner.js +0 -280
  201. package/frigg-cli/utils/process-manager.js +0 -199
  202. package/frigg-cli/utils/repo-detection.js +0 -405
  203. package/infrastructure/aws-discovery.js +0 -1176
  204. package/infrastructure/aws-discovery.test.js +0 -1220
  205. package/infrastructure/serverless-template.js +0 -2094
  206. /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
  207. /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
  208. /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
  209. /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
  210. /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
  211. /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
  212. /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Issue Entity
3
+ *
4
+ * Represents a problem detected in infrastructure health check
5
+ */
6
+
7
+ class Issue {
8
+ /**
9
+ * Valid issue types
10
+ */
11
+ static TYPES = {
12
+ ORPHANED_RESOURCE: 'ORPHANED_RESOURCE',
13
+ MISSING_RESOURCE: 'MISSING_RESOURCE',
14
+ PROPERTY_MISMATCH: 'PROPERTY_MISMATCH',
15
+ DRIFTED_RESOURCE: 'DRIFTED_RESOURCE',
16
+ MISSING_TAG: 'MISSING_TAG',
17
+ };
18
+
19
+ /**
20
+ * Valid severity levels
21
+ */
22
+ static SEVERITIES = {
23
+ CRITICAL: 'critical',
24
+ WARNING: 'warning',
25
+ INFO: 'info',
26
+ };
27
+
28
+ /**
29
+ * Create a new Issue
30
+ *
31
+ * @param {Object} params
32
+ * @param {string} params.type - Issue type (ORPHANED_RESOURCE, MISSING_RESOURCE, etc.)
33
+ * @param {string} params.severity - Severity level (critical, warning, info)
34
+ * @param {string} params.resourceType - CloudFormation resource type
35
+ * @param {string} params.resourceId - Resource identifier (physical or logical ID)
36
+ * @param {string} params.description - Human-readable description
37
+ * @param {string} [params.resolution] - Suggested resolution
38
+ * @param {boolean} [params.canAutoFix=false] - Whether issue can be automatically fixed
39
+ * @param {PropertyMismatch} [params.propertyMismatch] - Property mismatch details (for PROPERTY_MISMATCH type)
40
+ */
41
+ constructor({
42
+ type,
43
+ severity,
44
+ resourceType,
45
+ resourceId,
46
+ description,
47
+ resolution = null,
48
+ canAutoFix = false,
49
+ propertyMismatch = null,
50
+ }) {
51
+ // Validate required fields
52
+ if (!type) {
53
+ throw new Error('type is required');
54
+ }
55
+
56
+ if (!severity) {
57
+ throw new Error('severity is required');
58
+ }
59
+
60
+ if (!resourceType) {
61
+ throw new Error('resourceType is required');
62
+ }
63
+
64
+ if (!resourceId) {
65
+ throw new Error('resourceId is required');
66
+ }
67
+
68
+ if (!description) {
69
+ throw new Error('description is required');
70
+ }
71
+
72
+ // Validate type
73
+ if (!Object.values(Issue.TYPES).includes(type)) {
74
+ throw new Error(`Invalid issue type: ${type}`);
75
+ }
76
+
77
+ // Validate severity
78
+ if (!Object.values(Issue.SEVERITIES).includes(severity)) {
79
+ throw new Error(`Invalid severity: ${severity}`);
80
+ }
81
+
82
+ this.type = type;
83
+ this.severity = severity;
84
+ this.resourceType = resourceType;
85
+ this.resourceId = resourceId;
86
+ this.description = description;
87
+ this.resolution = resolution;
88
+ this.canAutoFix = canAutoFix;
89
+ this.propertyMismatch = propertyMismatch;
90
+ }
91
+
92
+ /**
93
+ * Check if issue is an orphaned resource
94
+ * @returns {boolean}
95
+ */
96
+ isOrphanedResource() {
97
+ return this.type === Issue.TYPES.ORPHANED_RESOURCE;
98
+ }
99
+
100
+ /**
101
+ * Check if issue is a missing resource
102
+ * @returns {boolean}
103
+ */
104
+ isMissingResource() {
105
+ return this.type === Issue.TYPES.MISSING_RESOURCE;
106
+ }
107
+
108
+ /**
109
+ * Check if issue is a property mismatch
110
+ * @returns {boolean}
111
+ */
112
+ isPropertyMismatch() {
113
+ return this.type === Issue.TYPES.PROPERTY_MISMATCH;
114
+ }
115
+
116
+ /**
117
+ * Check if issue is a drifted resource
118
+ * @returns {boolean}
119
+ */
120
+ isDrifted() {
121
+ return this.type === Issue.TYPES.DRIFTED_RESOURCE;
122
+ }
123
+
124
+ /**
125
+ * Check if issue is critical severity
126
+ * @returns {boolean}
127
+ */
128
+ isCritical() {
129
+ return this.severity === Issue.SEVERITIES.CRITICAL;
130
+ }
131
+
132
+ /**
133
+ * Check if issue is warning severity
134
+ * @returns {boolean}
135
+ */
136
+ isWarning() {
137
+ return this.severity === Issue.SEVERITIES.WARNING;
138
+ }
139
+
140
+ /**
141
+ * Check if issue is info severity
142
+ * @returns {boolean}
143
+ */
144
+ isInfo() {
145
+ return this.severity === Issue.SEVERITIES.INFO;
146
+ }
147
+
148
+ /**
149
+ * Get string representation
150
+ * @returns {string}
151
+ */
152
+ toString() {
153
+ return `Issue: ${this.type} [${this.severity}] - ${this.resourceType} (${this.resourceId}): ${this.description}`;
154
+ }
155
+
156
+ /**
157
+ * Serialize to JSON
158
+ * @returns {Object}
159
+ */
160
+ toJSON() {
161
+ return {
162
+ type: this.type,
163
+ severity: this.severity,
164
+ resourceType: this.resourceType,
165
+ resourceId: this.resourceId,
166
+ description: this.description,
167
+ resolution: this.resolution,
168
+ canAutoFix: this.canAutoFix,
169
+ propertyMismatch: this.propertyMismatch ? this.propertyMismatch.toJSON() : null,
170
+ };
171
+ }
172
+
173
+ /**
174
+ * Create an orphaned resource issue
175
+ *
176
+ * @param {Object} params
177
+ * @param {string} params.resourceType - CloudFormation resource type
178
+ * @param {string} params.resourceId - Resource physical ID
179
+ * @param {string} params.description - Issue description
180
+ * @returns {Issue}
181
+ */
182
+ static orphanedResource({ resourceType, resourceId, description }) {
183
+ return new Issue({
184
+ type: Issue.TYPES.ORPHANED_RESOURCE,
185
+ severity: Issue.SEVERITIES.CRITICAL,
186
+ resourceType,
187
+ resourceId,
188
+ description,
189
+ resolution: 'Import resource into CloudFormation stack using frigg repair --import',
190
+ canAutoFix: true,
191
+ });
192
+ }
193
+
194
+ /**
195
+ * Create a missing resource issue
196
+ *
197
+ * @param {Object} params
198
+ * @param {string} params.resourceType - CloudFormation resource type
199
+ * @param {string} params.resourceId - Resource logical ID
200
+ * @param {string} params.description - Issue description
201
+ * @returns {Issue}
202
+ */
203
+ static missingResource({ resourceType, resourceId, description }) {
204
+ return new Issue({
205
+ type: Issue.TYPES.MISSING_RESOURCE,
206
+ severity: Issue.SEVERITIES.CRITICAL,
207
+ resourceType,
208
+ resourceId,
209
+ description,
210
+ resolution: 'Verify resource was not manually deleted. May need to recreate or remove from stack definition.',
211
+ canAutoFix: false,
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Format a value for display in issue descriptions
217
+ * Handles arrays, objects, and primitive types
218
+ *
219
+ * @private
220
+ * @param {*} value - Value to format
221
+ * @returns {string} Formatted value
222
+ */
223
+ static _formatValue(value) {
224
+ if (value === null || value === undefined) {
225
+ return String(value);
226
+ }
227
+
228
+ // Handle arrays
229
+ if (Array.isArray(value)) {
230
+ // For arrays of objects (like Tags), show count and first few items
231
+ if (value.length > 0 && typeof value[0] === 'object') {
232
+ if (value.length <= 3) {
233
+ return JSON.stringify(value);
234
+ }
235
+ // Show first 2 items + count for long arrays
236
+ const preview = value.slice(0, 2);
237
+ return `${JSON.stringify(preview).slice(0, -1)}, ... (${value.length} total)]`;
238
+ }
239
+ // For simple arrays, stringify
240
+ return JSON.stringify(value);
241
+ }
242
+
243
+ // Handle objects
244
+ if (typeof value === 'object') {
245
+ const keys = Object.keys(value);
246
+ if (keys.length === 0) {
247
+ return '{}';
248
+ }
249
+ if (keys.length <= 3) {
250
+ return JSON.stringify(value);
251
+ }
252
+ // For large objects, show keys count
253
+ return `{${keys.slice(0, 3).join(', ')}, ... (${keys.length} keys total)}`;
254
+ }
255
+
256
+ // Primitives
257
+ return String(value);
258
+ }
259
+
260
+ /**
261
+ * Create a property mismatch issue
262
+ *
263
+ * @param {Object} params
264
+ * @param {string} params.resourceType - CloudFormation resource type
265
+ * @param {string} params.resourceId - Resource identifier
266
+ * @param {PropertyMismatch} params.mismatch - Property mismatch details
267
+ * @returns {Issue}
268
+ */
269
+ static propertyMismatch({ resourceType, resourceId, mismatch }) {
270
+ const severity = mismatch.requiresReplacement()
271
+ ? Issue.SEVERITIES.CRITICAL
272
+ : Issue.SEVERITIES.WARNING;
273
+
274
+ const canAutoFix = mismatch.canAutoFix();
275
+
276
+ // Format expected and actual values for display
277
+ const formattedExpected = Issue._formatValue(mismatch.expectedValue);
278
+ const formattedActual = Issue._formatValue(mismatch.actualValue);
279
+
280
+ const description = `Property mismatch: ${mismatch.propertyPath} (expected: ${formattedExpected}, actual: ${formattedActual})`;
281
+
282
+ const resolution = canAutoFix
283
+ ? 'Can be auto-fixed using frigg repair --reconcile'
284
+ : 'Requires resource replacement - manual intervention needed';
285
+
286
+ return new Issue({
287
+ type: Issue.TYPES.PROPERTY_MISMATCH,
288
+ severity,
289
+ resourceType,
290
+ resourceId,
291
+ description,
292
+ resolution,
293
+ canAutoFix,
294
+ propertyMismatch: mismatch,
295
+ });
296
+ }
297
+ }
298
+
299
+ module.exports = Issue;