@gugananuvem/aws-local-simulator 1.0.34 → 1.0.39

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 (150) hide show
  1. package/README.md +662 -658
  2. package/package.json +11 -4
  3. package/src/config/default-config.js +71 -0
  4. package/src/config/env-loader.js +4 -2
  5. package/src/middleware/authorization.js +271 -0
  6. package/src/middleware/cloudtrail-logger.js +333 -0
  7. package/src/middleware/error-handler.js +138 -0
  8. package/src/middleware/index.js +79 -0
  9. package/src/middleware/policy-enforcement.js +407 -0
  10. package/src/server.js +74 -4
  11. package/src/services/acm/index.js +66 -0
  12. package/src/services/acm/models/certificate.js +202 -0
  13. package/src/services/acm/server.js +224 -0
  14. package/src/services/acm/simulator.js +293 -0
  15. package/src/services/alb/index.js +104 -0
  16. package/src/services/alb/models/loadBalancer.js +88 -0
  17. package/src/services/alb/models/targetGroup.js +128 -0
  18. package/src/services/alb/server.js +160 -0
  19. package/src/services/alb/simulator.js +262 -0
  20. package/src/services/apigateway/index.js +22 -0
  21. package/src/services/apigateway/server.js +247 -35
  22. package/src/services/apigateway/simulator.js +780 -26
  23. package/src/services/asg/index.js +100 -0
  24. package/src/services/asg/models/autoScalingGroup.js +110 -0
  25. package/src/services/asg/models/launchTemplate.js +41 -0
  26. package/src/services/asg/models/scalingPolicy.js +51 -0
  27. package/src/services/asg/server.js +236 -0
  28. package/src/services/asg/simulator.js +410 -0
  29. package/src/services/aurora/cluster-manager.js +731 -0
  30. package/src/services/aurora/data-api.js +514 -0
  31. package/src/services/aurora/db-engine.js +270 -0
  32. package/src/services/aurora/index.js +159 -0
  33. package/src/services/aurora/rds-api.js +189 -0
  34. package/src/services/aurora/server.js +213 -0
  35. package/src/services/aurora/sql-translator.js +334 -0
  36. package/src/services/cloudformation/index.js +2 -2
  37. package/src/services/cloudformation/server.js +1 -0
  38. package/src/services/cloudfront/cache-engine.js +225 -0
  39. package/src/services/cloudfront/geo-restrictions.js +377 -0
  40. package/src/services/cloudfront/index.js +220 -0
  41. package/src/services/cloudfront/models/behavior.js +158 -0
  42. package/src/services/cloudfront/models/distribution.js +284 -0
  43. package/src/services/cloudfront/models/index.js +99 -0
  44. package/src/services/cloudfront/models/invalidation.js +109 -0
  45. package/src/services/cloudfront/models/origin.js +155 -0
  46. package/src/services/cloudfront/origin-router.js +552 -0
  47. package/src/services/cloudfront/origin-validator.js +398 -0
  48. package/src/services/cloudfront/server.js +512 -0
  49. package/src/services/cloudfront/signed-url-generator.js +377 -0
  50. package/src/services/cloudfront/simulator.js +425 -0
  51. package/src/services/cloudfront/store.js +326 -0
  52. package/src/services/cloudshell/env-builder.js +27 -0
  53. package/src/services/cloudshell/index.js +48 -0
  54. package/src/services/cloudshell/routes.js +60 -0
  55. package/src/services/cloudshell/session-manager.js +226 -0
  56. package/src/services/cloudshell/static/.gitkeep +0 -0
  57. package/src/services/cloudshell/static/index.html +406 -0
  58. package/src/services/cloudshell/websocket-handler.js +107 -0
  59. package/src/services/cloudtrail/index.js +2 -3
  60. package/src/services/cloudtrail/server.js +68 -0
  61. package/src/services/cognito/server.js +4 -1
  62. package/src/services/dynamodb/server.js +4 -1
  63. package/src/services/dynamodb/simulator.js +2 -1
  64. package/src/services/ec2/index.js +101 -0
  65. package/src/services/ec2/instanceServer.js +311 -0
  66. package/src/services/ec2/models/ami.js +39 -0
  67. package/src/services/ec2/models/instance.js +98 -0
  68. package/src/services/ec2/models/networkInterface.js +74 -0
  69. package/src/services/ec2/models/securityGroup.js +71 -0
  70. package/src/services/ec2/server.js +350 -0
  71. package/src/services/ec2/simulator.js +436 -0
  72. package/src/services/eventbridge/server.js +36 -0
  73. package/src/services/eventbridge/simulator.js +230 -45
  74. package/src/services/iam/index.js +65 -0
  75. package/src/services/iam/middleware.js +99 -0
  76. package/src/services/iam/server.js +331 -0
  77. package/src/services/iam/simulator.js +1432 -0
  78. package/src/services/index.js +28 -0
  79. package/src/services/kinesis-analytics/index.js +105 -0
  80. package/src/services/kinesis-analytics/models/application.js +325 -0
  81. package/src/services/kinesis-analytics/models/index.js +12 -0
  82. package/src/services/kinesis-analytics/server.js +250 -0
  83. package/src/services/kinesis-analytics/simulator.js +407 -0
  84. package/src/services/kinesis-analytics/store.js +176 -0
  85. package/src/services/kinesis-data-streams/index.js +106 -0
  86. package/src/services/kinesis-data-streams/models/index.js +12 -0
  87. package/src/services/kinesis-data-streams/models/record.js +70 -0
  88. package/src/services/kinesis-data-streams/models/stream.js +280 -0
  89. package/src/services/kinesis-data-streams/server.js +255 -0
  90. package/src/services/kinesis-data-streams/simulator.js +514 -0
  91. package/src/services/kinesis-data-streams/store.js +163 -0
  92. package/src/services/kinesis-firehose/index.js +106 -0
  93. package/src/services/kinesis-firehose/models/delivery-stream.js +265 -0
  94. package/src/services/kinesis-firehose/models/index.js +10 -0
  95. package/src/services/kinesis-firehose/server.js +215 -0
  96. package/src/services/kinesis-firehose/simulator.js +388 -0
  97. package/src/services/kinesis-firehose/store.js +163 -0
  98. package/src/services/kms/server.js +4 -1
  99. package/src/services/lambda/handler-loader.js +50 -5
  100. package/src/services/lambda/index.js +26 -0
  101. package/src/services/lambda/server.js +18 -12
  102. package/src/services/lambda/simulator.js +73 -17
  103. package/src/services/opensearch/index.js +105 -0
  104. package/src/services/opensearch/models/document.js +115 -0
  105. package/src/services/opensearch/models/index.js +73 -0
  106. package/src/services/opensearch/server.js +310 -0
  107. package/src/services/opensearch/simulator.js +605 -0
  108. package/src/services/opensearch/store.js +162 -0
  109. package/src/services/organizations/control-tower-simulator.js +321 -0
  110. package/src/services/organizations/control-tower-store.js +182 -0
  111. package/src/services/organizations/iam-integration.js +413 -0
  112. package/src/services/organizations/index.js +172 -0
  113. package/src/services/organizations/models/index.js +13 -0
  114. package/src/services/organizations/models/invitation.js +48 -0
  115. package/src/services/organizations/models/organization.js +566 -0
  116. package/src/services/organizations/models/role.js +244 -0
  117. package/src/services/organizations/models/scp.js +131 -0
  118. package/src/services/organizations/server.js +736 -0
  119. package/src/services/organizations/simulator.js +593 -0
  120. package/src/services/organizations/store.js +235 -0
  121. package/src/services/organizations/vpc-integration.js +453 -0
  122. package/src/services/route53/index.js +67 -0
  123. package/src/services/route53/models/healthCheck.js +101 -0
  124. package/src/services/route53/models/hostedZone.js +37 -0
  125. package/src/services/route53/models/resourceRecord.js +106 -0
  126. package/src/services/route53/server.js +841 -0
  127. package/src/services/route53/simulator.js +350 -0
  128. package/src/services/s3/index.js +62 -0
  129. package/src/services/s3/presigned-url-generator.js +337 -0
  130. package/src/services/s3/server.js +231 -0
  131. package/src/services/s3/simulator.js +551 -4
  132. package/src/services/sns/index.js +31 -0
  133. package/src/services/sns/server.js +9 -0
  134. package/src/services/sqs/index.js +38 -0
  135. package/src/services/sqs/server.js +57 -4
  136. package/src/services/sqs/simulator.js +423 -33
  137. package/src/services/sts/simulator.js +209 -17
  138. package/src/services/vpc/README.md +459 -0
  139. package/src/services/vpc/ec2ResponseFormatter.js +431 -0
  140. package/src/services/vpc/index.js +90 -0
  141. package/src/services/vpc/models/internetGateway.js +71 -0
  142. package/src/services/vpc/models/routeTable.js +160 -0
  143. package/src/services/vpc/models/subnet.js +48 -0
  144. package/src/services/vpc/models/vpc.js +37 -0
  145. package/src/services/vpc/models/vpcEndpoint.js +100 -0
  146. package/src/services/vpc/models/vpcGateway.js +134 -0
  147. package/src/services/vpc/server.js +836 -0
  148. package/src/services/vpc/simulator.js +613 -0
  149. package/src/utils/policy-cache.js +215 -0
  150. package/aws-config +0 -154
@@ -0,0 +1,331 @@
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const crypto = require('crypto');
4
+ const path = require('path');
5
+ const logger = require('../../utils/logger');
6
+ const { setupServiceMiddleware } = require('../../middleware');
7
+
8
+
9
+ class IAMServer {
10
+ constructor(simulator, logger, config) {
11
+ this.organizationsService = null;
12
+ this.stsService = null;
13
+ this.simulator = simulator;
14
+ this.logger = logger || require('../../utils/logger');
15
+ this.config = config;
16
+ this.app = express();
17
+ this._setupMiddleware();
18
+ this._setupRoutes();
19
+ }
20
+
21
+ _setupMiddleware() {
22
+ this.app.use(cors());
23
+ this.app.use(express.urlencoded({ extended: true }));
24
+ this.app.use(express.json());
25
+ this.app.use(express.static(__dirname));
26
+ }
27
+
28
+ _setupRoutes() {
29
+ // Main IAM API endpoint (AWS Query protocol)
30
+ this.app.post('/', (req, res) => {
31
+ const action = req.body.Action || req.query.Action;
32
+
33
+ if (!action) {
34
+ return this._xmlError(res, 'MissingAction', 'The request must contain the parameter Action', 400);
35
+ }
36
+
37
+ this.logger.debug(`IAM action: ${action}`);
38
+
39
+ try {
40
+ const result = this._handleAction(action, req.body);
41
+
42
+ if (result && typeof result.then === 'function') {
43
+ result
44
+ .then(data => this._xmlResponse(res, action, data))
45
+ .catch(err => this._handleError(res, err));
46
+ } else {
47
+ this._xmlResponse(res, action, result);
48
+ }
49
+ } catch (err) {
50
+ this._handleError(res, err);
51
+ }
52
+ });
53
+
54
+ // Admin health endpoint
55
+ this.app.get('/__admin/health', (req, res) => {
56
+ res.json({ status: 'ok', service: 'iam' });
57
+ });
58
+
59
+ // Admin dashboard endpoints
60
+ this.app.get('/__admin/users', (req, res) => {
61
+ const users = Array.from(this.simulator.users.values());
62
+ res.json(users);
63
+ });
64
+
65
+ this.app.get('/__admin/policies', (req, res) => {
66
+ const policies = Array.from(this.simulator.policies.values()).map(p => {
67
+ const { Document, ...metadata } = p;
68
+ return metadata;
69
+ });
70
+ res.json(policies);
71
+ });
72
+
73
+ this.app.get('/__admin/roles', (req, res) => {
74
+ const roles = Array.from(this.simulator.roles.values());
75
+ res.json(roles);
76
+ });
77
+
78
+ this.app.get('/__admin/groups', (req, res) => {
79
+ const groups = Array.from(this.simulator.groups.values()).map(g => ({
80
+ ...g,
81
+ MemberCount: this.simulator.groupMembers.get(g.GroupName)?.size || 0
82
+ }));
83
+ res.json(groups);
84
+ });
85
+
86
+ this.app.get('/__admin/access-keys', (req, res) => {
87
+ const accessKeys = Array.from(this.simulator.accessKeys.values());
88
+ res.json(accessKeys);
89
+ });
90
+
91
+ // Admin create/delete endpoints
92
+ this.app.post('/__admin/users/create', async (req, res) => {
93
+ try {
94
+ const user = await this.simulator.createUser({ UserName: req.body?.UserName });
95
+ res.json(user);
96
+ } catch (err) {
97
+ res.status(err.statusCode || 500).json({ message: err.message });
98
+ }
99
+ });
100
+
101
+ this.app.delete('/__admin/users/:name', async (req, res) => {
102
+ try {
103
+ await this.simulator.deleteUser({ UserName: req.params.name });
104
+ res.json({ success: true });
105
+ } catch (err) {
106
+ res.status(err.statusCode || 500).json({ message: err.message });
107
+ }
108
+ });
109
+
110
+ this.app.post('/__admin/groups/create', async (req, res) => {
111
+ try {
112
+ const group = await this.simulator.createGroup({ GroupName: req.body?.GroupName });
113
+ res.json(group);
114
+ } catch (err) {
115
+ res.status(err.statusCode || 500).json({ message: err.message });
116
+ }
117
+ });
118
+
119
+ this.app.delete('/__admin/groups/:name', async (req, res) => {
120
+ try {
121
+ await this.simulator.deleteGroup({ GroupName: req.params.name });
122
+ res.json({ success: true });
123
+ } catch (err) {
124
+ res.status(err.statusCode || 500).json({ message: err.message });
125
+ }
126
+ });
127
+
128
+ this.app.post('/__admin/roles/create', async (req, res) => {
129
+ try {
130
+ const role = await this.simulator.createRole({ RoleName: req.body?.RoleName });
131
+ res.json(role);
132
+ } catch (err) {
133
+ res.status(err.statusCode || 500).json({ message: err.message });
134
+ }
135
+ });
136
+
137
+ this.app.delete('/__admin/roles/:name', async (req, res) => {
138
+ try {
139
+ await this.simulator.deleteRole({ RoleName: req.params.name });
140
+ res.json({ success: true });
141
+ } catch (err) {
142
+ res.status(err.statusCode || 500).json({ message: err.message });
143
+ }
144
+ });
145
+
146
+ // Dashboard HTML
147
+ this.app.get('/dashboard', (req, res) => {
148
+ res.sendFile(path.join(__dirname, 'dashboard.html'));
149
+ });
150
+ }
151
+
152
+ _handleAction(action, params) {
153
+ switch (action) {
154
+ // User Management
155
+ case 'CreateUser':
156
+ return this.simulator.createUser(params);
157
+ case 'GetUser':
158
+ return this.simulator.getUser(params);
159
+ case 'ListUsers':
160
+ return this.simulator.listUsers(params);
161
+ case 'DeleteUser':
162
+ return this.simulator.deleteUser(params);
163
+ // Access Key Management
164
+ case 'CreateAccessKey':
165
+ return this.simulator.createAccessKey(params);
166
+ case 'ListAccessKeys':
167
+ return this.simulator.listAccessKeys(params);
168
+ case 'DeleteAccessKey':
169
+ return this.simulator.deleteAccessKey(params);
170
+ case 'UpdateAccessKey':
171
+ return this.simulator.updateAccessKey(params);
172
+ // Group Management
173
+ case 'CreateGroup':
174
+ return this.simulator.createGroup(params);
175
+ case 'GetGroup':
176
+ return this.simulator.getGroup(params);
177
+ case 'DeleteGroup':
178
+ return this.simulator.deleteGroup(params);
179
+ case 'AddUserToGroup':
180
+ return this.simulator.addUserToGroup(params);
181
+ case 'RemoveUserFromGroup':
182
+ return this.simulator.removeUserFromGroup(params);
183
+ case 'ListGroupsForUser':
184
+ return this.simulator.listGroupsForUser(params);
185
+ case 'ListGroups':
186
+ return this.simulator.listGroups(params);
187
+ // Role Management
188
+ case 'CreateRole':
189
+ return this.simulator.createRole(params);
190
+ case 'GetRole':
191
+ return this.simulator.getRole(params);
192
+ case 'ListRoles':
193
+ return this.simulator.listRoles(params);
194
+ case 'DeleteRole':
195
+ return this.simulator.deleteRole(params);
196
+ // Policy Management
197
+ case 'CreatePolicy':
198
+ return this.simulator.createPolicy(params);
199
+ case 'GetPolicy':
200
+ return this.simulator.getPolicy(params);
201
+ case 'GetPolicyVersion':
202
+ return this.simulator.getPolicyVersion(params);
203
+ case 'ListPolicies':
204
+ return this.simulator.listPolicies(params);
205
+ case 'DeletePolicy':
206
+ return this.simulator.deletePolicy(params);
207
+ // Policy Attach/Detach
208
+ case 'AttachUserPolicy':
209
+ return this.simulator.attachUserPolicy(params);
210
+ case 'AttachGroupPolicy':
211
+ return this.simulator.attachGroupPolicy(params);
212
+ case 'AttachRolePolicy':
213
+ return this.simulator.attachRolePolicy(params);
214
+ case 'DetachUserPolicy':
215
+ return this.simulator.detachUserPolicy(params);
216
+ case 'DetachGroupPolicy':
217
+ return this.simulator.detachGroupPolicy(params);
218
+ case 'DetachRolePolicy':
219
+ return this.simulator.detachRolePolicy(params);
220
+ // Attached Policy Listing
221
+ case 'ListAttachedUserPolicies':
222
+ return this.simulator.listAttachedUserPolicies(params);
223
+ case 'ListAttachedGroupPolicies':
224
+ return this.simulator.listAttachedGroupPolicies(params);
225
+ case 'ListAttachedRolePolicies':
226
+ return this.simulator.listAttachedRolePolicies(params);
227
+ // Account
228
+ case 'GetAccountSummary':
229
+ return this.simulator.getAccountSummary(params);
230
+ default:
231
+ const err = new Error(`Unsupported IAM action: ${action}`);
232
+ err.code = 'InvalidAction';
233
+ err.statusCode = 400;
234
+ throw err;
235
+ }
236
+ }
237
+
238
+ _handleError(res, err) {
239
+ const code = err.code || 'InternalFailure';
240
+ const message = err.message || 'An internal error occurred';
241
+ const statusCode = err.statusCode || 500;
242
+ this.logger.error(`IAM Error [${code}]: ${message}`);
243
+ this._xmlError(res, code, message, statusCode);
244
+ }
245
+
246
+ _xmlResponse(res, action, result) {
247
+ const requestId = crypto.randomUUID();
248
+ let resultXml = '';
249
+
250
+ if (result && typeof result === 'object') {
251
+ resultXml = this._objectToXml(result);
252
+ }
253
+
254
+ const xml = `<${action}Response xmlns="https://iam.amazonaws.com/doc/2010-05-08/">` +
255
+ `<${action}Result>${resultXml}</${action}Result>` +
256
+ `<ResponseMetadata><RequestId>${requestId}</RequestId></ResponseMetadata>` +
257
+ `</${action}Response>`;
258
+
259
+ res.set('Content-Type', 'text/xml');
260
+ res.send(xml);
261
+ }
262
+
263
+ _xmlError(res, code, message, statusCode = 400) {
264
+ const requestId = crypto.randomUUID();
265
+
266
+ const xml = `<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">` +
267
+ `<Error><Type>Sender</Type><Code>${code}</Code><Message>${message}</Message></Error>` +
268
+ `<RequestId>${requestId}</RequestId>` +
269
+ `</ErrorResponse>`;
270
+
271
+ res.status(statusCode).set('Content-Type', 'text/xml').send(xml);
272
+ }
273
+
274
+ _objectToXml(obj) {
275
+ if (obj === null || obj === undefined) return '';
276
+ if (typeof obj !== 'object') return String(obj);
277
+
278
+ const SINGULAR_MAP = {
279
+ 'Groups': 'Group',
280
+ 'Users': 'User',
281
+ 'Roles': 'Role',
282
+ 'Policies': 'Policy',
283
+ 'AccessKeyMetadata': 'member',
284
+ 'AttachedPolicies': 'member'
285
+ };
286
+
287
+ const MAP_KEYS = new Set(['SummaryMap']);
288
+
289
+ let xml = '';
290
+ for (const [key, value] of Object.entries(obj)) {
291
+ if (Array.isArray(value)) {
292
+ const itemTag = SINGULAR_MAP[key] || 'member';
293
+ xml += `<${key}>`;
294
+ for (const item of value) {
295
+ if (typeof item === 'object' && item !== null) {
296
+ xml += `<${itemTag}>${this._objectToXml(item)}</${itemTag}>`;
297
+ } else {
298
+ xml += `<${itemTag}>${this._escapeXml(String(item))}</${itemTag}>`;
299
+ }
300
+ }
301
+ xml += `</${key}>`;
302
+ } else if (MAP_KEYS.has(key) && typeof value === 'object' && value !== null) {
303
+ xml += `<${key}>`;
304
+ for (const [mapKey, mapValue] of Object.entries(value)) {
305
+ xml += `<entry><key>${this._escapeXml(String(mapKey))}</key><value>${this._escapeXml(String(mapValue))}</value></entry>`;
306
+ }
307
+ xml += `</${key}>`;
308
+ } else if (typeof value === 'object' && value !== null) {
309
+ xml += `<${key}>${this._objectToXml(value)}</${key}>`;
310
+ } else {
311
+ xml += `<${key}>${this._escapeXml(String(value))}</${key}>`;
312
+ }
313
+ }
314
+ return xml;
315
+ }
316
+
317
+ _escapeXml(str) {
318
+ return str
319
+ .replace(/&/g, '&amp;')
320
+ .replace(/</g, '&lt;')
321
+ .replace(/>/g, '&gt;')
322
+ .replace(/"/g, '&quot;')
323
+ .replace(/'/g, '&apos;');
324
+ }
325
+
326
+ getApp() {
327
+ return this.app;
328
+ }
329
+ }
330
+
331
+ module.exports = IAMServer;