@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,235 @@
1
+ /**
2
+ * Organizations Store - Persistência em JSON
3
+ */
4
+
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+ const logger = require('../../utils/logger');
8
+
9
+ class OrganizationsStore {
10
+ constructor(dataDir) {
11
+ this.dataDir = dataDir;
12
+ this.organizationsDir = path.join(dataDir, 'organizations');
13
+ this.metadataFile = path.join(this.organizationsDir, '__metadata__.json');
14
+
15
+ if (!fs.existsSync(this.organizationsDir)) {
16
+ fs.mkdirSync(this.organizationsDir, { recursive: true });
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Carrega metadados da organização
22
+ */
23
+ loadOrganizationMetadata() {
24
+ if (fs.existsSync(this.metadataFile)) {
25
+ try {
26
+ const data = fs.readFileSync(this.metadataFile, 'utf8');
27
+ return JSON.parse(data);
28
+ } catch (error) {
29
+ logger.warn(`Erro ao ler ${this.metadataFile}: ${error.message}`);
30
+ return null;
31
+ }
32
+ }
33
+ return null;
34
+ }
35
+
36
+ /**
37
+ * Salva metadados da organização
38
+ */
39
+ saveOrganizationMetadata(metadata) {
40
+ try {
41
+ fs.writeFileSync(this.metadataFile, JSON.stringify(metadata, null, 2), 'utf8');
42
+ logger.debug(`Metadados da organização salvos em ${this.metadataFile}`);
43
+ } catch (error) {
44
+ logger.error(`Erro ao salvar ${this.metadataFile}: ${error.message}`);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Carrega OUs
50
+ */
51
+ loadOrganizationalUnits() {
52
+ const ouFile = path.join(this.organizationsDir, '__ous__.json');
53
+
54
+ if (fs.existsSync(ouFile)) {
55
+ try {
56
+ const data = fs.readFileSync(ouFile, 'utf8');
57
+ return JSON.parse(data);
58
+ } catch (error) {
59
+ logger.warn(`Erro ao ler OUs: ${error.message}`);
60
+ return {};
61
+ }
62
+ }
63
+ return {};
64
+ }
65
+
66
+ /**
67
+ * Salva OUs
68
+ */
69
+ saveOrganizationalUnits(ous) {
70
+ try {
71
+ const ouFile = path.join(this.organizationsDir, '__ous__.json');
72
+ const data = {};
73
+
74
+ for (const [ouId, ou] of ous) {
75
+ data[ouId] = ou;
76
+ }
77
+
78
+ fs.writeFileSync(ouFile, JSON.stringify(data, null, 2), 'utf8');
79
+ logger.debug(`${Object.keys(data).length} OUs salvas`);
80
+ } catch (error) {
81
+ logger.error(`Erro ao salvar OUs: ${error.message}`);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Carrega contas
87
+ */
88
+ loadAccounts() {
89
+ const accountsFile = path.join(this.organizationsDir, '__accounts__.json');
90
+
91
+ if (fs.existsSync(accountsFile)) {
92
+ try {
93
+ const data = fs.readFileSync(accountsFile, 'utf8');
94
+ return JSON.parse(data);
95
+ } catch (error) {
96
+ logger.warn(`Erro ao ler contas: ${error.message}`);
97
+ return {};
98
+ }
99
+ }
100
+ return {};
101
+ }
102
+
103
+ /**
104
+ * Salva contas
105
+ */
106
+ saveAccounts(accounts) {
107
+ try {
108
+ const accountsFile = path.join(this.organizationsDir, '__accounts__.json');
109
+ const data = {};
110
+
111
+ for (const [accountId, account] of accounts) {
112
+ data[accountId] = account;
113
+ }
114
+
115
+ fs.writeFileSync(accountsFile, JSON.stringify(data, null, 2), 'utf8');
116
+ logger.debug(`${Object.keys(data).length} contas salvas`);
117
+ } catch (error) {
118
+ logger.error(`Erro ao salvar contas: ${error.message}`);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Carrega policies
124
+ */
125
+ loadPolicies() {
126
+ const policiesFile = path.join(this.organizationsDir, '__policies__.json');
127
+
128
+ if (fs.existsSync(policiesFile)) {
129
+ try {
130
+ const data = fs.readFileSync(policiesFile, 'utf8');
131
+ return JSON.parse(data);
132
+ } catch (error) {
133
+ logger.warn(`Erro ao ler policies: ${error.message}`);
134
+ return {};
135
+ }
136
+ }
137
+ return {};
138
+ }
139
+
140
+ /**
141
+ * Salva policies
142
+ */
143
+ savePolicies(policies) {
144
+ try {
145
+ const policiesFile = path.join(this.organizationsDir, '__policies__.json');
146
+ const data = {};
147
+
148
+ for (const [policyId, policy] of policies) {
149
+ data[policyId] = {
150
+ id: policy.id,
151
+ name: policy.name,
152
+ document: policy.document,
153
+ type: policy.type,
154
+ status: policy.status,
155
+ targets: policy.targets,
156
+ createdAt: policy.createdAt,
157
+ lastModifiedAt: policy.lastModifiedAt
158
+ };
159
+ }
160
+
161
+ fs.writeFileSync(policiesFile, JSON.stringify(data, null, 2), 'utf8');
162
+ logger.debug(`${Object.keys(data).length} policies salvas`);
163
+ } catch (error) {
164
+ logger.error(`Erro ao salvar policies: ${error.message}`);
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Carrega roles
170
+ */
171
+ loadRoles() {
172
+ const rolesFile = path.join(this.organizationsDir, '__roles__.json');
173
+
174
+ if (fs.existsSync(rolesFile)) {
175
+ try {
176
+ const data = fs.readFileSync(rolesFile, 'utf8');
177
+ return JSON.parse(data);
178
+ } catch (error) {
179
+ logger.warn(`Erro ao ler roles: ${error.message}`);
180
+ return {};
181
+ }
182
+ }
183
+ return {};
184
+ }
185
+
186
+ /**
187
+ * Salva roles
188
+ */
189
+ saveRoles(roles) {
190
+ try {
191
+ const rolesFile = path.join(this.organizationsDir, '__roles__.json');
192
+ const data = {};
193
+
194
+ for (const [roleId, role] of roles) {
195
+ data[roleId] = {
196
+ id: role.id,
197
+ name: role.name,
198
+ arn: role.arn,
199
+ accountId: role.accountId,
200
+ trustPolicy: role.trustPolicy,
201
+ inlinePolicies: Array.from(role.inlinePolicies.entries()),
202
+ managedPolicies: role.managedPolicies,
203
+ createdAt: role.createdAt,
204
+ lastModifiedAt: role.lastModifiedAt
205
+ };
206
+ }
207
+
208
+ fs.writeFileSync(rolesFile, JSON.stringify(data, null, 2), 'utf8');
209
+ logger.debug(`${Object.keys(data).length} roles salvas`);
210
+ } catch (error) {
211
+ logger.error(`Erro ao salvar roles: ${error.message}`);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Limpa tudo
217
+ */
218
+ clear() {
219
+ try {
220
+ if (fs.existsSync(this.organizationsDir)) {
221
+ const files = fs.readdirSync(this.organizationsDir);
222
+ files.forEach(file => {
223
+ if (file.endsWith('.json')) {
224
+ fs.unlinkSync(path.join(this.organizationsDir, file));
225
+ }
226
+ });
227
+ logger.debug('Todos os dados de organizações foram limpos');
228
+ }
229
+ } catch (error) {
230
+ logger.error(`Erro ao limpar organizações: ${error.message}`);
231
+ }
232
+ }
233
+ }
234
+
235
+ module.exports = OrganizationsStore;
@@ -0,0 +1,453 @@
1
+ /**
2
+ * VPC Integration Module
3
+ * Integra Organizations com VPC para restrições regionais e de serviços
4
+ */
5
+
6
+ const logger = require('../../utils/logger');
7
+
8
+ class VPCIntegration {
9
+ constructor(organizationsSimulator, vpcService, ec2Service) {
10
+ this.organizationsSimulator = organizationsSimulator;
11
+ this.vpcService = vpcService;
12
+ this.ec2Service = ec2Service;
13
+ }
14
+
15
+ /**
16
+ * Valida se um recurso VPC pode ser criado em uma conta/região
17
+ */
18
+ validateVPCResource(accountId, region, resourceType, config = {}) {
19
+ logger.debug(`Validating VPC resource: ${resourceType} in ${region} for account ${accountId}`);
20
+
21
+ // 1. Verifica se SCP permite operação em serviço VPC
22
+ const scpEvaluation = this.organizationsSimulator.evaluateSCPs(
23
+ accountId,
24
+ `ec2:Create*`,
25
+ `arn:aws:ec2:${region}:${accountId}:*`
26
+ );
27
+
28
+ if (!scpEvaluation.allowed) {
29
+ return {
30
+ allowed: false,
31
+ deniedBy: 'SCP',
32
+ reason: `Service Control Policy denies VPC operations in region ${region}`,
33
+ details: scpEvaluation
34
+ };
35
+ }
36
+
37
+ // 2. Verifica restrições regionais por SCP
38
+ const regionalCheck = this.checkRegionalRestrictions(accountId, region);
39
+ if (!regionalCheck.allowed) {
40
+ return {
41
+ allowed: false,
42
+ deniedBy: 'RegionalSCP',
43
+ reason: regionalCheck.reason,
44
+ details: regionalCheck
45
+ };
46
+ }
47
+
48
+ // 3. Valida tipo de recurso específico
49
+ const typeValidation = this.validateResourceType(resourceType, region, config);
50
+ if (!typeValidation.allowed) {
51
+ return typeValidation;
52
+ }
53
+
54
+ return {
55
+ allowed: true,
56
+ accountId,
57
+ region,
58
+ resourceType,
59
+ message: 'VPC resource creation allowed'
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Verifica restrições regionais definidas em SCP
65
+ */
66
+ checkRegionalRestrictions(accountId, region) {
67
+ try {
68
+ const account = this.organizationsSimulator.organization.getAccount(accountId);
69
+ if (!account) {
70
+ return {
71
+ allowed: false,
72
+ reason: `Account ${accountId} not found`
73
+ };
74
+ }
75
+
76
+ // Coleta todas as SCPs aplicáveis à conta
77
+ const applicablePolicies = [];
78
+
79
+ let currentOUId = account.parentId;
80
+ while (currentOUId) {
81
+ const policies = this.organizationsSimulator.organization.listPoliciesForTarget(currentOUId);
82
+ applicablePolicies.push(...policies);
83
+
84
+ const ou = this.organizationsSimulator.organization.getOrganizationalUnit(currentOUId);
85
+ currentOUId = ou?.parentId;
86
+ }
87
+
88
+ const accountPolicies = this.organizationsSimulator.organization.listPoliciesForTarget(accountId);
89
+ applicablePolicies.push(...accountPolicies);
90
+
91
+ // Verifica se há restrições regionais
92
+ const allowedRegions = this.extractAllowedRegions(applicablePolicies);
93
+
94
+ if (allowedRegions.length > 0 && !allowedRegions.includes(region)) {
95
+ return {
96
+ allowed: false,
97
+ reason: `Region ${region} not in allowed regions: ${allowedRegions.join(', ')}`,
98
+ allowedRegions
99
+ };
100
+ }
101
+
102
+ const deniedRegions = this.extractDeniedRegions(applicablePolicies);
103
+ if (deniedRegions.includes(region)) {
104
+ return {
105
+ allowed: false,
106
+ reason: `Region ${region} is explicitly denied`,
107
+ deniedRegions
108
+ };
109
+ }
110
+
111
+ return {
112
+ allowed: true,
113
+ allowedRegions: allowedRegions.length > 0 ? allowedRegions : 'all',
114
+ deniedRegions
115
+ };
116
+
117
+ } catch (error) {
118
+ logger.error(`Error checking regional restrictions: ${error.message}`);
119
+ return {
120
+ allowed: false,
121
+ reason: error.message
122
+ };
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Extrai regiões permitidas de policies
128
+ */
129
+ extractAllowedRegions(policies) {
130
+ const regions = new Set();
131
+
132
+ for (const policy of policies) {
133
+ if (!policy.document || !policy.document.Statement) continue;
134
+
135
+ for (const statement of policy.document.Statement) {
136
+ if (statement.Effect === 'Allow') {
137
+ // Procura por restrições de região na Resource ou Condition
138
+ if (statement.Resource) {
139
+ const resourceRegions = this.extractRegionsFromResources(statement.Resource);
140
+ resourceRegions.forEach(r => regions.add(r));
141
+ }
142
+
143
+ if (statement.Condition?.StringEquals?.['aws:RequestedRegion']) {
144
+ const regionValues = statement.Condition.StringEquals['aws:RequestedRegion'];
145
+ const regionList = Array.isArray(regionValues) ? regionValues : [regionValues];
146
+ regionList.forEach(r => regions.add(r));
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ return Array.from(regions);
153
+ }
154
+
155
+ /**
156
+ * Extrai regiões negadas de policies
157
+ */
158
+ extractDeniedRegions(policies) {
159
+ const regions = new Set();
160
+
161
+ for (const policy of policies) {
162
+ if (!policy.document || !policy.document.Statement) continue;
163
+
164
+ for (const statement of policy.document.Statement) {
165
+ if (statement.Effect === 'Deny') {
166
+ if (statement.Resource) {
167
+ const resourceRegions = this.extractRegionsFromResources(statement.Resource);
168
+ resourceRegions.forEach(r => regions.add(r));
169
+ }
170
+
171
+ if (statement.Condition?.StringEquals?.['aws:RequestedRegion']) {
172
+ const regionValues = statement.Condition.StringEquals['aws:RequestedRegion'];
173
+ const regionList = Array.isArray(regionValues) ? regionValues : [regionValues];
174
+ regionList.forEach(r => regions.add(r));
175
+ }
176
+ }
177
+ }
178
+ }
179
+
180
+ return Array.from(regions);
181
+ }
182
+
183
+ /**
184
+ * Extrai regiões de um ARN
185
+ */
186
+ extractRegionsFromResources(resources) {
187
+ const regions = new Set();
188
+ const resourceList = Array.isArray(resources) ? resources : [resources];
189
+
190
+ for (const resource of resourceList) {
191
+ // ARN format: arn:aws:service:region:account:resource
192
+ const parts = resource.split(':');
193
+ if (parts.length >= 4) {
194
+ const region = parts[3];
195
+ if (region && region !== '*') {
196
+ regions.add(region);
197
+ }
198
+ }
199
+ }
200
+
201
+ return Array.from(regions);
202
+ }
203
+
204
+ /**
205
+ * Valida tipo de recurso específico
206
+ */
207
+ validateResourceType(resourceType, region, config = {}) {
208
+ try {
209
+ switch (resourceType.toLowerCase()) {
210
+ case 'vpc':
211
+ return this.validateVPC(region, config);
212
+
213
+ case 'subnet':
214
+ return this.validateSubnet(region, config);
215
+
216
+ case 'securitygroup':
217
+ case 'security-group':
218
+ return this.validateSecurityGroup(region, config);
219
+
220
+ case 'routetable':
221
+ case 'route-table':
222
+ return this.validateRouteTable(region, config);
223
+
224
+ case 'internetgateway':
225
+ case 'internet-gateway':
226
+ return this.validateInternetGateway(region, config);
227
+
228
+ case 'natgateway':
229
+ case 'nat-gateway':
230
+ return this.validateNATGateway(region, config);
231
+
232
+ default:
233
+ return {
234
+ allowed: true,
235
+ message: `Resource type ${resourceType} validation passed`
236
+ };
237
+ }
238
+ } catch (error) {
239
+ logger.error(`Error validating resource type ${resourceType}: ${error.message}`);
240
+ return {
241
+ allowed: false,
242
+ reason: error.message
243
+ };
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Valida criação de VPC
249
+ */
250
+ validateVPC(region, config = {}) {
251
+ // Validações específicas para VPC
252
+ if (!config.cidrBlock) {
253
+ return {
254
+ allowed: false,
255
+ reason: 'CIDR block is required for VPC'
256
+ };
257
+ }
258
+
259
+ // Verifica se CIDR é válido
260
+ if (!this.isValidCIDR(config.cidrBlock)) {
261
+ return {
262
+ allowed: false,
263
+ reason: `Invalid CIDR block: ${config.cidrBlock}`
264
+ };
265
+ }
266
+
267
+ return {
268
+ allowed: true,
269
+ message: 'VPC creation validation passed'
270
+ };
271
+ }
272
+
273
+ /**
274
+ * Valida criação de Subnet
275
+ */
276
+ validateSubnet(region, config = {}) {
277
+ if (!config.vpcId) {
278
+ return {
279
+ allowed: false,
280
+ reason: 'VPC ID is required for subnet'
281
+ };
282
+ }
283
+
284
+ if (!config.cidrBlock) {
285
+ return {
286
+ allowed: false,
287
+ reason: 'CIDR block is required for subnet'
288
+ };
289
+ }
290
+
291
+ if (!this.isValidCIDR(config.cidrBlock)) {
292
+ return {
293
+ allowed: false,
294
+ reason: `Invalid CIDR block: ${config.cidrBlock}`
295
+ };
296
+ }
297
+
298
+ return {
299
+ allowed: true,
300
+ message: 'Subnet creation validation passed'
301
+ };
302
+ }
303
+
304
+ /**
305
+ * Valida criação de Security Group
306
+ */
307
+ validateSecurityGroup(region, config = {}) {
308
+ if (!config.groupName) {
309
+ return {
310
+ allowed: false,
311
+ reason: 'Group name is required'
312
+ };
313
+ }
314
+
315
+ return {
316
+ allowed: true,
317
+ message: 'Security group creation validation passed'
318
+ };
319
+ }
320
+
321
+ /**
322
+ * Valida criação de Route Table
323
+ */
324
+ validateRouteTable(region, config = {}) {
325
+ if (!config.vpcId) {
326
+ return {
327
+ allowed: false,
328
+ reason: 'VPC ID is required for route table'
329
+ };
330
+ }
331
+
332
+ return {
333
+ allowed: true,
334
+ message: 'Route table creation validation passed'
335
+ };
336
+ }
337
+
338
+ /**
339
+ * Valida criação de Internet Gateway
340
+ */
341
+ validateInternetGateway(region, config = {}) {
342
+ return {
343
+ allowed: true,
344
+ message: 'Internet gateway creation validation passed'
345
+ };
346
+ }
347
+
348
+ /**
349
+ * Valida criação de NAT Gateway
350
+ */
351
+ validateNATGateway(region, config = {}) {
352
+ if (!config.subnetId) {
353
+ return {
354
+ allowed: false,
355
+ reason: 'Subnet ID is required for NAT gateway'
356
+ };
357
+ }
358
+
359
+ if (!config.allocationId) {
360
+ return {
361
+ allowed: false,
362
+ reason: 'Elastic IP allocation ID is required for NAT gateway'
363
+ };
364
+ }
365
+
366
+ return {
367
+ allowed: true,
368
+ message: 'NAT gateway creation validation passed'
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Valida CIDR block
374
+ */
375
+ isValidCIDR(cidr) {
376
+ const cidrRegex = /^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/;
377
+
378
+ if (!cidrRegex.test(cidr)) {
379
+ return false;
380
+ }
381
+
382
+ // Valida octetos
383
+ const [network, prefix] = cidr.split('/');
384
+ const octets = network.split('.');
385
+
386
+ for (const octet of octets) {
387
+ const num = parseInt(octet, 10);
388
+ if (num < 0 || num > 255) {
389
+ return false;
390
+ }
391
+ }
392
+
393
+ // Valida prefix length
394
+ const prefixLen = parseInt(prefix, 10);
395
+ return prefixLen >= 0 && prefixLen <= 32;
396
+ }
397
+
398
+ /**
399
+ * Valida regra de Security Group
400
+ */
401
+ validateSecurityGroupRule(rule, direction = 'ingress') {
402
+ if (!rule.protocol) {
403
+ return {
404
+ allowed: false,
405
+ reason: 'Protocol is required'
406
+ };
407
+ }
408
+
409
+ if (rule.protocol !== '-1' && !['tcp', 'udp', 'icmp'].includes(rule.protocol.toLowerCase())) {
410
+ return {
411
+ allowed: false,
412
+ reason: `Invalid protocol: ${rule.protocol}`
413
+ };
414
+ }
415
+
416
+ if (rule.protocol !== '-1' && direction === 'ingress') {
417
+ if (rule.fromPort === undefined || rule.toPort === undefined) {
418
+ return {
419
+ allowed: false,
420
+ reason: 'Port range is required for protocol'
421
+ };
422
+ }
423
+
424
+ if (rule.fromPort < 0 || rule.fromPort > 65535) {
425
+ return {
426
+ allowed: false,
427
+ reason: `Invalid from port: ${rule.fromPort}`
428
+ };
429
+ }
430
+
431
+ if (rule.toPort < 0 || rule.toPort > 65535) {
432
+ return {
433
+ allowed: false,
434
+ reason: `Invalid to port: ${rule.toPort}`
435
+ };
436
+ }
437
+
438
+ if (rule.fromPort > rule.toPort) {
439
+ return {
440
+ allowed: false,
441
+ reason: 'From port cannot be greater than to port'
442
+ };
443
+ }
444
+ }
445
+
446
+ return {
447
+ allowed: true,
448
+ message: 'Security group rule validation passed'
449
+ };
450
+ }
451
+ }
452
+
453
+ module.exports = VPCIntegration;