@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.
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 +633 -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 -2074
  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,377 @@
1
+ /**
2
+ * Tests for AWS Provider Adapter
3
+ *
4
+ * Tests AWS-specific cloud resource discovery
5
+ */
6
+
7
+ const { AWSProviderAdapter } = require('./aws-provider-adapter');
8
+
9
+ // Mock AWS SDK v3 clients
10
+ jest.mock('@aws-sdk/client-ec2');
11
+ jest.mock('@aws-sdk/client-kms');
12
+ jest.mock('@aws-sdk/client-rds');
13
+ jest.mock('@aws-sdk/client-ssm');
14
+ jest.mock('@aws-sdk/client-secrets-manager');
15
+
16
+ describe('AWSProviderAdapter', () => {
17
+ let provider;
18
+
19
+ beforeEach(() => {
20
+ jest.clearAllMocks();
21
+ delete process.env.AWS_REGION;
22
+ });
23
+
24
+ describe('constructor()', () => {
25
+ it('should initialize with provided region', () => {
26
+ provider = new AWSProviderAdapter('eu-west-1');
27
+
28
+ expect(provider.region).toBe('eu-west-1');
29
+ });
30
+
31
+ it('should default to us-east-1 if no region provided', () => {
32
+ provider = new AWSProviderAdapter();
33
+
34
+ expect(provider.region).toBe('us-east-1');
35
+ });
36
+
37
+ it('should use AWS_REGION environment variable', () => {
38
+ process.env.AWS_REGION = 'ap-southeast-1';
39
+ provider = new AWSProviderAdapter();
40
+
41
+ expect(provider.region).toBe('ap-southeast-1');
42
+ });
43
+
44
+ it('should prefer provided region over environment variable', () => {
45
+ process.env.AWS_REGION = 'us-west-2';
46
+ provider = new AWSProviderAdapter('eu-central-1');
47
+
48
+ expect(provider.region).toBe('eu-central-1');
49
+ });
50
+
51
+ it('should store credentials if provided', () => {
52
+ const credentials = {
53
+ accessKeyId: 'test-key',
54
+ secretAccessKey: 'test-secret',
55
+ };
56
+
57
+ provider = new AWSProviderAdapter('us-east-1', credentials);
58
+
59
+ expect(provider.credentials).toEqual(credentials);
60
+ });
61
+
62
+ it('should lazy-load clients (not instantiated on construction)', () => {
63
+ provider = new AWSProviderAdapter('us-east-1');
64
+
65
+ expect(provider.ec2).toBeNull();
66
+ expect(provider.kms).toBeNull();
67
+ expect(provider.rds).toBeNull();
68
+ expect(provider.ssm).toBeNull();
69
+ expect(provider.secretsManager).toBeNull();
70
+ });
71
+ });
72
+
73
+ describe('getName()', () => {
74
+ it('should return "aws"', () => {
75
+ provider = new AWSProviderAdapter();
76
+
77
+ expect(provider.getName()).toBe('aws');
78
+ });
79
+ });
80
+
81
+ describe('getSupportedRegions()', () => {
82
+ it('should return array of AWS regions', () => {
83
+ provider = new AWSProviderAdapter();
84
+
85
+ const regions = provider.getSupportedRegions();
86
+
87
+ expect(Array.isArray(regions)).toBe(true);
88
+ expect(regions.length).toBeGreaterThan(0);
89
+ });
90
+
91
+ it('should include common US regions', () => {
92
+ provider = new AWSProviderAdapter();
93
+
94
+ const regions = provider.getSupportedRegions();
95
+
96
+ expect(regions).toContain('us-east-1');
97
+ expect(regions).toContain('us-east-2');
98
+ expect(regions).toContain('us-west-1');
99
+ expect(regions).toContain('us-west-2');
100
+ });
101
+
102
+ it('should include common EU regions', () => {
103
+ provider = new AWSProviderAdapter();
104
+
105
+ const regions = provider.getSupportedRegions();
106
+
107
+ expect(regions).toContain('eu-west-1');
108
+ expect(regions).toContain('eu-central-1');
109
+ });
110
+
111
+ it('should include common APAC regions', () => {
112
+ provider = new AWSProviderAdapter();
113
+
114
+ const regions = provider.getSupportedRegions();
115
+
116
+ expect(regions).toContain('ap-southeast-1');
117
+ expect(regions).toContain('ap-northeast-1');
118
+ });
119
+ });
120
+
121
+ describe('Lazy loading clients', () => {
122
+ beforeEach(() => {
123
+ provider = new AWSProviderAdapter('us-east-1');
124
+ });
125
+
126
+ it('should lazy-load EC2 client', () => {
127
+ expect(provider.ec2).toBeNull();
128
+
129
+ const client = provider.getEC2Client();
130
+
131
+ expect(provider.ec2).not.toBeNull();
132
+ expect(client).toBe(provider.ec2);
133
+ });
134
+
135
+ it('should lazy-load KMS client', () => {
136
+ expect(provider.kms).toBeNull();
137
+
138
+ const client = provider.getKMSClient();
139
+
140
+ expect(provider.kms).not.toBeNull();
141
+ expect(client).toBe(provider.kms);
142
+ });
143
+
144
+ it('should lazy-load RDS client', () => {
145
+ expect(provider.rds).toBeNull();
146
+
147
+ const client = provider.getRDSClient();
148
+
149
+ expect(provider.rds).not.toBeNull();
150
+ expect(client).toBe(provider.rds);
151
+ });
152
+
153
+ it('should lazy-load SSM client', () => {
154
+ expect(provider.ssm).toBeNull();
155
+
156
+ const client = provider.getSSMClient();
157
+
158
+ expect(provider.ssm).not.toBeNull();
159
+ expect(client).toBe(provider.ssm);
160
+ });
161
+
162
+ it('should lazy-load Secrets Manager client', () => {
163
+ expect(provider.secretsManager).toBeNull();
164
+
165
+ const client = provider.getSecretsManagerClient();
166
+
167
+ expect(provider.secretsManager).not.toBeNull();
168
+ expect(client).toBe(provider.secretsManager);
169
+ });
170
+
171
+ it('should lazy-load CloudFormation client', () => {
172
+ expect(provider.cloudformation).toBeNull();
173
+
174
+ const client = provider.getCloudFormationClient();
175
+
176
+ expect(provider.cloudformation).not.toBeNull();
177
+ expect(client).toBe(provider.cloudformation);
178
+ });
179
+
180
+ it('should reuse client on subsequent calls', () => {
181
+ const client1 = provider.getEC2Client();
182
+ const client2 = provider.getEC2Client();
183
+
184
+ expect(client1).toBe(client2);
185
+ });
186
+ });
187
+
188
+ describe('discoverVpc()', () => {
189
+ beforeEach(() => {
190
+ provider = new AWSProviderAdapter('us-east-1');
191
+ const { EC2Client } = require('@aws-sdk/client-ec2');
192
+ EC2Client.mockImplementation(() => ({
193
+ send: jest.fn(),
194
+ }));
195
+ });
196
+
197
+ it('should return VPC discovery results', async () => {
198
+ const mockSend = jest.fn()
199
+ .mockResolvedValueOnce({ // VPCs
200
+ Vpcs: [
201
+ { VpcId: 'vpc-123', CidrBlock: '172.31.0.0/16' },
202
+ ],
203
+ })
204
+ .mockResolvedValueOnce({ Subnets: [] }) // Subnets
205
+ .mockResolvedValueOnce({ SecurityGroups: [] }) // Security Groups
206
+ .mockResolvedValueOnce({ RouteTables: [] }) // Route Tables
207
+ .mockResolvedValueOnce({ NatGateways: [] }) // NAT Gateways
208
+ .mockResolvedValueOnce({ InternetGateways: [] }) // Internet Gateways
209
+ .mockResolvedValueOnce({ VpcEndpoints: [] }); // VPC Endpoints
210
+
211
+ provider.getEC2Client = jest.fn().mockReturnValue({ send: mockSend });
212
+
213
+ const result = await provider.discoverVpc({});
214
+
215
+ expect(result.vpcId).toBe('vpc-123');
216
+ expect(result.vpcCidr).toBe('172.31.0.0/16');
217
+ });
218
+
219
+ it('should handle discovery errors', async () => {
220
+ provider.getEC2Client = jest.fn().mockReturnValue({
221
+ send: jest.fn().mockRejectedValue(new Error('EC2 API Error')),
222
+ });
223
+
224
+ await expect(provider.discoverVpc({})).rejects.toThrow('Failed to discover AWS VPC');
225
+ });
226
+
227
+ it('should discover default VPC when no vpcId specified', async () => {
228
+ const mockSend = jest.fn();
229
+ provider.getEC2Client = jest.fn().mockReturnValue({ send: mockSend });
230
+
231
+ await provider.discoverVpc({}).catch(() => { });
232
+
233
+ // First call should filter for default VPC
234
+ expect(mockSend).toHaveBeenCalled();
235
+ });
236
+ });
237
+
238
+ describe('discoverKmsKeys()', () => {
239
+ beforeEach(() => {
240
+ provider = new AWSProviderAdapter('us-east-1');
241
+ const { KMSClient } = require('@aws-sdk/client-kms');
242
+ KMSClient.mockImplementation(() => ({
243
+ send: jest.fn(),
244
+ }));
245
+ });
246
+
247
+ it('should return KMS discovery results', async () => {
248
+ const mockSend = jest.fn()
249
+ .mockResolvedValueOnce({ // ListKeys
250
+ Keys: [{ KeyId: 'key-123' }],
251
+ })
252
+ .mockResolvedValueOnce({ // DescribeKey
253
+ KeyMetadata: {
254
+ KeyId: 'key-123',
255
+ Arn: 'arn:aws:kms:us-east-1:123:key/abc',
256
+ Enabled: true,
257
+ },
258
+ })
259
+ .mockResolvedValueOnce({ // ListAliases
260
+ Aliases: [
261
+ { AliasName: 'alias/my-key', TargetKeyId: 'key-123' },
262
+ ],
263
+ });
264
+
265
+ provider.getKMSClient = jest.fn().mockReturnValue({ send: mockSend });
266
+
267
+ const result = await provider.discoverKmsKeys({});
268
+
269
+ expect(result.keys.length).toBeGreaterThan(0);
270
+ expect(result.defaultKey).toBeDefined();
271
+ });
272
+
273
+ it('should handle discovery errors', async () => {
274
+ provider.getKMSClient = jest.fn().mockReturnValue({
275
+ send: jest.fn().mockRejectedValue(new Error('KMS API Error')),
276
+ });
277
+
278
+ await expect(provider.discoverKmsKeys({})).rejects.toThrow('Failed to discover AWS KMS keys');
279
+ });
280
+ });
281
+
282
+ describe('discoverDatabase()', () => {
283
+ beforeEach(() => {
284
+ provider = new AWSProviderAdapter('us-east-1');
285
+ const { RDSClient } = require('@aws-sdk/client-rds');
286
+ RDSClient.mockImplementation(() => ({
287
+ send: jest.fn(),
288
+ }));
289
+ });
290
+
291
+ it('should return database discovery results', async () => {
292
+ const mockSend = jest.fn()
293
+ .mockResolvedValueOnce({ // Clusters
294
+ DBClusters: [
295
+ {
296
+ DBClusterIdentifier: 'cluster-1',
297
+ Endpoint: 'cluster-1.example.com',
298
+ Port: 5432,
299
+ Engine: 'aurora-postgresql',
300
+ },
301
+ ],
302
+ })
303
+ .mockResolvedValueOnce({ DBInstances: [] }); // Instances
304
+
305
+ provider.getRDSClient = jest.fn().mockReturnValue({ send: mockSend });
306
+
307
+ const result = await provider.discoverDatabase({});
308
+
309
+ expect(result.endpoint).toBe('cluster-1.example.com');
310
+ expect(result.port).toBe(5432);
311
+ expect(result.engine).toBe('aurora-postgresql');
312
+ });
313
+
314
+ it('should handle discovery errors', async () => {
315
+ provider.getRDSClient = jest.fn().mockReturnValue({
316
+ send: jest.fn().mockRejectedValue(new Error('RDS API Error')),
317
+ });
318
+
319
+ await expect(provider.discoverDatabase({})).rejects.toThrow('Failed to discover AWS databases');
320
+ });
321
+ });
322
+
323
+ describe('discoverParameters()', () => {
324
+ beforeEach(() => {
325
+ provider = new AWSProviderAdapter('us-east-1');
326
+ });
327
+
328
+ it('should return parameter discovery results', async () => {
329
+ const mockSSMSend = jest.fn().mockResolvedValue({
330
+ Parameters: [
331
+ { Name: '/my-app/api-key', Value: 'encrypted' },
332
+ ],
333
+ });
334
+
335
+ const mockSMSend = jest.fn().mockResolvedValue({
336
+ SecretList: [
337
+ { Name: 'my-app/secret', ARN: 'arn:aws:secretsmanager:us-east-1:123:secret:my-app/secret' },
338
+ ],
339
+ });
340
+
341
+ provider.getSSMClient = jest.fn().mockReturnValue({ send: mockSSMSend });
342
+ provider.getSecretsManagerClient = jest.fn().mockReturnValue({ send: mockSMSend });
343
+
344
+ const result = await provider.discoverParameters({
345
+ parameterPath: '/my-app',
346
+ includeSecrets: true,
347
+ });
348
+
349
+ expect(result.parameters).toHaveLength(1);
350
+ expect(result.secrets).toHaveLength(1);
351
+ });
352
+
353
+ it('should handle discovery errors', async () => {
354
+ provider.getSSMClient = jest.fn().mockReturnValue({
355
+ send: jest.fn().mockRejectedValue(new Error('SSM API Error')),
356
+ });
357
+
358
+ await expect(provider.discoverParameters({ parameterPath: '/test' })).rejects.toThrow('Failed to discover AWS parameters');
359
+ });
360
+
361
+ it('should skip secrets when includeSecrets is false', async () => {
362
+ const mockSSMSend = jest.fn().mockResolvedValue({ Parameters: [] });
363
+
364
+ provider.getSSMClient = jest.fn().mockReturnValue({ send: mockSSMSend });
365
+
366
+ const result = await provider.discoverParameters({
367
+ includeSecrets: false,
368
+ });
369
+
370
+ expect(result.parameters).toEqual([]);
371
+ expect(result.secrets).toEqual([]);
372
+ // Behavior-based test: secrets should be empty when includeSecrets is false
373
+ // (Implementation detail: getSecretsManagerClient shouldn't be called)
374
+ });
375
+ });
376
+ });
377
+
@@ -0,0 +1,93 @@
1
+ /**
2
+ * FUTURE: Microsoft Azure Provider Adapter
3
+ *
4
+ * This file serves as a placeholder for future Azure support.
5
+ *
6
+ * Implementation will use:
7
+ * - @azure/arm-network for Virtual Network discovery
8
+ * - @azure/keyvault-keys for Key Vault key management
9
+ * - @azure/arm-sql for Azure SQL database discovery
10
+ * - @azure/keyvault-secrets for secrets management
11
+ * - @azure/arm-resources for resource group management
12
+ *
13
+ * Resources:
14
+ * - Azure SDK for JavaScript: https://docs.microsoft.com/en-us/javascript/azure/
15
+ * - ARM Network API: https://docs.microsoft.com/en-us/javascript/api/@azure/arm-network
16
+ * - Key Vault API: https://docs.microsoft.com/en-us/javascript/api/@azure/keyvault-keys
17
+ * - Azure SQL API: https://docs.microsoft.com/en-us/javascript/api/@azure/arm-sql
18
+ *
19
+ * Architecture mapping:
20
+ * - AWS VPC → Azure Virtual Network (VNet)
21
+ * - AWS KMS → Azure Key Vault
22
+ * - AWS RDS Aurora → Azure SQL Database / Azure Database for PostgreSQL
23
+ * - AWS SSM Parameter Store → Azure Key Vault Secrets
24
+ * - AWS Lambda → Azure Functions
25
+ *
26
+ * Example structure:
27
+ *
28
+ * const { NetworkManagementClient } = require('@azure/arm-network');
29
+ * const { KeyClient } = require('@azure/keyvault-keys');
30
+ * const { DefaultAzureCredential } = require('@azure/identity');
31
+ * const { CloudProviderAdapter } = require('./cloud-provider-adapter');
32
+ *
33
+ * class AzureProviderAdapter extends CloudProviderAdapter {
34
+ * constructor(region, credentials = {}) {
35
+ * super();
36
+ * this.region = region || 'eastus';
37
+ * this.subscriptionId = credentials.subscriptionId || process.env.AZURE_SUBSCRIPTION_ID;
38
+ * this.credential = new DefaultAzureCredential();
39
+ *
40
+ * this.networkClient = new NetworkManagementClient(
41
+ * this.credential,
42
+ * this.subscriptionId
43
+ * );
44
+ * }
45
+ *
46
+ * getName() {
47
+ * return 'azure';
48
+ * }
49
+ *
50
+ * getSupportedRegions() {
51
+ * return [
52
+ * 'eastus', 'eastus2', 'westus', 'westus2',
53
+ * 'northeurope', 'westeurope', 'southeastasia'
54
+ * ];
55
+ * }
56
+ *
57
+ * async discoverVpc(config) {
58
+ * // Discover Azure Virtual Networks
59
+ * const vnets = [];
60
+ * for await (const vnet of this.networkClient.virtualNetworks.listAll()) {
61
+ * vnets.push(vnet);
62
+ * }
63
+ * // ... implementation
64
+ * }
65
+ *
66
+ * async discoverKmsKeys(config) {
67
+ * // Discover Azure Key Vault keys
68
+ * const keyVaultUrl = `https://${config.keyVaultName}.vault.azure.net`;
69
+ * const keyClient = new KeyClient(keyVaultUrl, this.credential);
70
+ * const keys = [];
71
+ * for await (const key of keyClient.listPropertiesOfKeys()) {
72
+ * keys.push(key);
73
+ * }
74
+ * // ... implementation
75
+ * }
76
+ *
77
+ * async discoverDatabase(config) {
78
+ * // Discover Azure SQL databases
79
+ * // ... implementation
80
+ * }
81
+ *
82
+ * async discoverParameters(config) {
83
+ * // Discover Azure Key Vault secrets
84
+ * // ... implementation
85
+ * }
86
+ * }
87
+ *
88
+ * module.exports = { AzureProviderAdapter };
89
+ */
90
+
91
+ // Placeholder export to prevent import errors
92
+ module.exports = {};
93
+
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Cloud Provider Adapter (Abstract Base Class)
3
+ *
4
+ * Port - Hexagonal Architecture
5
+ *
6
+ * Defines the contract for cloud provider implementations.
7
+ * This abstraction enables multi-cloud support by providing a consistent
8
+ * interface for AWS, GCP, Azure, and other cloud providers.
9
+ *
10
+ * Benefits:
11
+ * - Cloud-agnostic infrastructure code
12
+ * - Easy to add new providers (just implement this interface)
13
+ * - Testable with mock providers
14
+ * - Clear separation between cloud-specific and business logic
15
+ */
16
+
17
+ class CloudProviderAdapter {
18
+ /**
19
+ * Get provider name
20
+ * @returns {string} Provider name ('aws', 'gcp', 'azure', etc.)
21
+ */
22
+ getName() {
23
+ throw new Error('CloudProviderAdapter.getName() must be implemented by subclass');
24
+ }
25
+
26
+ /**
27
+ * Get supported regions for this provider
28
+ * @returns {Array<string>} List of supported region identifiers
29
+ */
30
+ getSupportedRegions() {
31
+ throw new Error('CloudProviderAdapter.getSupportedRegions() must be implemented by subclass');
32
+ }
33
+
34
+ // ==================== Discovery Methods ====================
35
+
36
+ /**
37
+ * Discover VPC/network resources
38
+ *
39
+ * @param {Object} config - Discovery configuration
40
+ * @param {string} [config.vpcId] - Specific VPC ID to discover
41
+ * @param {string} [config.vpcName] - VPC name pattern to search for
42
+ * @param {boolean} [config.includeSubnets] - Whether to include subnet details
43
+ * @returns {Promise<Object>} Discovered VPC resources
44
+ * @returns {Promise<Object>} result.vpcId - VPC identifier
45
+ * @returns {Promise<Object>} result.vpcCidr - VPC CIDR block
46
+ * @returns {Promise<Object>} result.subnets - Array of subnet objects
47
+ * @returns {Promise<Object>} result.securityGroups - Array of security group objects
48
+ * @returns {Promise<Object>} result.routeTables - Array of route table objects
49
+ */
50
+ async discoverVpc(config) {
51
+ throw new Error('CloudProviderAdapter.discoverVpc() must be implemented by subclass');
52
+ }
53
+
54
+ /**
55
+ * Discover encryption keys (KMS, Cloud KMS, Azure Key Vault, etc.)
56
+ *
57
+ * @param {Object} config - Discovery configuration
58
+ * @param {string} [config.keyId] - Specific key ID to discover
59
+ * @param {string} [config.keyAlias] - Key alias to search for
60
+ * @returns {Promise<Object>} Discovered encryption key resources
61
+ * @returns {Promise<Object>} result.keyId - Key identifier
62
+ * @returns {Promise<Object>} result.keyArn - Key ARN/resource name
63
+ * @returns {Promise<Object>} result.aliases - Array of key aliases
64
+ */
65
+ async discoverKmsKeys(config) {
66
+ throw new Error('CloudProviderAdapter.discoverKmsKeys() must be implemented by subclass');
67
+ }
68
+
69
+ /**
70
+ * Discover database resources (RDS, Cloud SQL, Azure SQL, etc.)
71
+ *
72
+ * @param {Object} config - Discovery configuration
73
+ * @param {string} [config.databaseId] - Specific database instance/cluster ID
74
+ * @param {string} [config.engine] - Database engine filter ('postgresql', 'mysql', etc.)
75
+ * @returns {Promise<Object>} Discovered database resources
76
+ * @returns {Promise<Object>} result.endpoint - Database connection endpoint
77
+ * @returns {Promise<Object>} result.port - Database port
78
+ * @returns {Promise<Object>} result.engine - Database engine type
79
+ * @returns {Promise<Object>} result.version - Database version
80
+ */
81
+ async discoverDatabase(config) {
82
+ throw new Error('CloudProviderAdapter.discoverDatabase() must be implemented by subclass');
83
+ }
84
+
85
+ /**
86
+ * Discover parameter store/secret manager resources
87
+ *
88
+ * @param {Object} config - Discovery configuration
89
+ * @param {string} [config.parameterPath] - Parameter path prefix to search
90
+ * @param {string} [config.secretName] - Specific secret name to discover
91
+ * @returns {Promise<Object>} Discovered parameter/secret resources
92
+ * @returns {Promise<Object>} result.parameters - Array of parameter objects
93
+ * @returns {Promise<Object>} result.secrets - Array of secret objects
94
+ */
95
+ async discoverParameters(config) {
96
+ throw new Error('CloudProviderAdapter.discoverParameters() must be implemented by subclass');
97
+ }
98
+
99
+ // ==================== Provisioning Methods (Future) ====================
100
+ // These will be used for Terraform/Pulumi/CloudFormation generation
101
+
102
+ /**
103
+ * Generate VPC provisioning configuration
104
+ *
105
+ * @param {Object} config - VPC configuration
106
+ * @returns {Promise<Object>} Infrastructure-as-code configuration
107
+ */
108
+ async provisionVpc(config) {
109
+ throw new Error('CloudProviderAdapter.provisionVpc() not yet implemented. Future feature for IaC generation.');
110
+ }
111
+
112
+ /**
113
+ * Generate encryption key provisioning configuration
114
+ *
115
+ * @param {Object} config - Key configuration
116
+ * @returns {Promise<Object>} Infrastructure-as-code configuration
117
+ */
118
+ async provisionKmsKey(config) {
119
+ throw new Error('CloudProviderAdapter.provisionKmsKey() not yet implemented. Future feature for IaC generation.');
120
+ }
121
+
122
+ /**
123
+ * Generate database provisioning configuration
124
+ *
125
+ * @param {Object} config - Database configuration
126
+ * @returns {Promise<Object>} Infrastructure-as-code configuration
127
+ */
128
+ async provisionDatabase(config) {
129
+ throw new Error('CloudProviderAdapter.provisionDatabase() not yet implemented. Future feature for IaC generation.');
130
+ }
131
+ }
132
+
133
+ module.exports = {
134
+ CloudProviderAdapter,
135
+ };
136
+
@@ -0,0 +1,82 @@
1
+ /**
2
+ * FUTURE: Google Cloud Platform Provider Adapter
3
+ *
4
+ * This file serves as a placeholder for future GCP support.
5
+ *
6
+ * Implementation will use:
7
+ * - @google-cloud/compute for VPC/network discovery
8
+ * - @google-cloud/kms for encryption key management
9
+ * - @google-cloud/sql for Cloud SQL database discovery
10
+ * - @google-cloud/secret-manager for secrets management
11
+ *
12
+ * Resources:
13
+ * - GCP Node.js SDK: https://cloud.google.com/nodejs/docs/reference
14
+ * - Compute Engine API: https://cloud.google.com/compute/docs/reference/rest/v1
15
+ * - Cloud KMS API: https://cloud.google.com/kms/docs/reference/rest
16
+ * - Cloud SQL API: https://cloud.google.com/sql/docs/mysql/admin-api
17
+ *
18
+ * Architecture mapping:
19
+ * - AWS VPC → GCP VPC Network
20
+ * - AWS KMS → GCP Cloud KMS
21
+ * - AWS RDS Aurora → GCP Cloud SQL
22
+ * - AWS SSM Parameter Store → GCP Secret Manager
23
+ * - AWS Lambda → GCP Cloud Functions / Cloud Run
24
+ *
25
+ * Example structure:
26
+ *
27
+ * const { Compute } = require('@google-cloud/compute');
28
+ * const { KeyManagementServiceClient } = require('@google-cloud/kms');
29
+ * const { CloudProviderAdapter } = require('./cloud-provider-adapter');
30
+ *
31
+ * class GCPProviderAdapter extends CloudProviderAdapter {
32
+ * constructor(region, credentials = {}) {
33
+ * super();
34
+ * this.region = region || 'us-central1';
35
+ * this.projectId = credentials.projectId || process.env.GCP_PROJECT_ID;
36
+ *
37
+ * this.compute = new Compute({ projectId: this.projectId });
38
+ * this.kms = new KeyManagementServiceClient();
39
+ * }
40
+ *
41
+ * getName() {
42
+ * return 'gcp';
43
+ * }
44
+ *
45
+ * getSupportedRegions() {
46
+ * return [
47
+ * 'us-central1', 'us-east1', 'us-west1',
48
+ * 'europe-west1', 'asia-east1', 'asia-northeast1'
49
+ * ];
50
+ * }
51
+ *
52
+ * async discoverVpc(config) {
53
+ * // Discover GCP VPC networks
54
+ * const [networks] = await this.compute.getNetworks();
55
+ * // ... implementation
56
+ * }
57
+ *
58
+ * async discoverKmsKeys(config) {
59
+ * // Discover GCP Cloud KMS keys
60
+ * const [keyRings] = await this.kms.listKeyRings({
61
+ * parent: `projects/${this.projectId}/locations/${this.region}`
62
+ * });
63
+ * // ... implementation
64
+ * }
65
+ *
66
+ * async discoverDatabase(config) {
67
+ * // Discover GCP Cloud SQL instances
68
+ * // ... implementation
69
+ * }
70
+ *
71
+ * async discoverParameters(config) {
72
+ * // Discover GCP Secret Manager secrets
73
+ * // ... implementation
74
+ * }
75
+ * }
76
+ *
77
+ * module.exports = { GCPProviderAdapter };
78
+ */
79
+
80
+ // Placeholder export to prevent import errors
81
+ module.exports = {};
82
+