regscale-cli 6.27.3.0__py3-none-any.whl → 6.28.1.0__py3-none-any.whl

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.

Potentially problematic release.


This version of regscale-cli might be problematic. Click here for more details.

Files changed (113) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/utils/app_utils.py +11 -2
  3. regscale/dev/cli.py +26 -0
  4. regscale/dev/version.py +72 -0
  5. regscale/integrations/commercial/__init__.py +15 -1
  6. regscale/integrations/commercial/amazon/amazon/__init__.py +0 -0
  7. regscale/integrations/commercial/amazon/amazon/common.py +204 -0
  8. regscale/integrations/commercial/amazon/common.py +48 -58
  9. regscale/integrations/commercial/aws/audit_manager_compliance.py +2671 -0
  10. regscale/integrations/commercial/aws/cli.py +3093 -55
  11. regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
  12. regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
  13. regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
  14. regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
  15. regscale/integrations/commercial/aws/config_compliance.py +914 -0
  16. regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
  17. regscale/integrations/commercial/aws/evidence_generator.py +283 -0
  18. regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
  19. regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
  20. regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
  21. regscale/integrations/commercial/aws/iam_evidence.py +574 -0
  22. regscale/integrations/commercial/aws/inventory/__init__.py +223 -22
  23. regscale/integrations/commercial/aws/inventory/base.py +107 -5
  24. regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
  25. regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
  26. regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
  27. regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
  28. regscale/integrations/commercial/aws/inventory/resources/compute.py +66 -9
  29. regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
  30. regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
  31. regscale/integrations/commercial/aws/inventory/resources/database.py +106 -31
  32. regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
  33. regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
  34. regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
  35. regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
  36. regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
  37. regscale/integrations/commercial/aws/inventory/resources/networking.py +103 -67
  38. regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
  39. regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
  40. regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
  41. regscale/integrations/commercial/aws/inventory/resources/storage.py +53 -29
  42. regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
  43. regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
  44. regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
  45. regscale/integrations/commercial/aws/kms_evidence.py +879 -0
  46. regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
  47. regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
  48. regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
  49. regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
  50. regscale/integrations/commercial/aws/org_evidence.py +666 -0
  51. regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
  52. regscale/integrations/commercial/aws/s3_evidence.py +632 -0
  53. regscale/integrations/commercial/aws/scanner.py +851 -206
  54. regscale/integrations/commercial/aws/security_hub.py +319 -0
  55. regscale/integrations/commercial/aws/session_manager.py +282 -0
  56. regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
  57. regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
  58. regscale/integrations/commercial/synqly/ticketing.py +27 -0
  59. regscale/integrations/compliance_integration.py +308 -38
  60. regscale/integrations/due_date_handler.py +3 -0
  61. regscale/integrations/scanner_integration.py +399 -84
  62. regscale/models/integration_models/cisa_kev_data.json +65 -5
  63. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  64. regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +17 -9
  65. regscale/models/regscale_models/assessment.py +2 -1
  66. regscale/models/regscale_models/control_objective.py +74 -5
  67. regscale/models/regscale_models/file.py +2 -0
  68. regscale/models/regscale_models/issue.py +2 -5
  69. {regscale_cli-6.27.3.0.dist-info → regscale_cli-6.28.1.0.dist-info}/METADATA +1 -1
  70. {regscale_cli-6.27.3.0.dist-info → regscale_cli-6.28.1.0.dist-info}/RECORD +113 -34
  71. tests/regscale/integrations/commercial/aws/__init__.py +0 -0
  72. tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
  73. tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
  74. tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
  75. tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
  76. tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
  77. tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
  78. tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
  79. tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
  80. tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
  81. tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
  82. tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
  83. tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
  84. tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
  85. tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
  86. tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
  87. tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
  88. tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
  89. tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
  90. tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
  91. tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
  92. tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
  93. tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
  94. tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
  95. tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
  96. tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
  97. tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
  98. tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
  99. tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
  100. tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
  101. tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
  102. tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
  103. tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
  104. tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
  105. tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
  106. tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
  107. tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
  108. tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
  109. tests/regscale/integrations/commercial/test_aws.py +55 -56
  110. {regscale_cli-6.27.3.0.dist-info → regscale_cli-6.28.1.0.dist-info}/LICENSE +0 -0
  111. {regscale_cli-6.27.3.0.dist-info → regscale_cli-6.28.1.0.dist-info}/WHEEL +0 -0
  112. {regscale_cli-6.27.3.0.dist-info → regscale_cli-6.28.1.0.dist-info}/entry_points.txt +0 -0
  113. {regscale_cli-6.27.3.0.dist-info → regscale_cli-6.28.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,996 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Unit tests for AWS VPC collector."""
4
+
5
+ import logging
6
+ from datetime import datetime
7
+ from unittest.mock import MagicMock, patch
8
+
9
+ import pytest
10
+ from botocore.exceptions import ClientError
11
+
12
+ from regscale.integrations.commercial.aws.inventory.resources.vpc import VPCCollector
13
+
14
+ logger = logging.getLogger("regscale")
15
+
16
+
17
+ class TestVPCCollector:
18
+ """Test suite for VPCCollector."""
19
+
20
+ @pytest.fixture
21
+ def mock_session(self):
22
+ """Create a mock boto3 session."""
23
+ session = MagicMock()
24
+ return session
25
+
26
+ @pytest.fixture
27
+ def mock_ec2_client(self):
28
+ """Create a mock EC2 client."""
29
+ client = MagicMock()
30
+ return client
31
+
32
+ @pytest.fixture
33
+ def vpc_collector(self, mock_session):
34
+ """Create a VPCCollector instance with mock session."""
35
+ return VPCCollector(session=mock_session, region="us-east-1", account_id="123456789012")
36
+
37
+ @pytest.fixture
38
+ def vpc_collector_no_filter(self, mock_session):
39
+ """Create a VPCCollector instance without account filtering."""
40
+ return VPCCollector(session=mock_session, region="us-east-1", account_id=None)
41
+
42
+ # Test initialization
43
+
44
+ def test_vpc_collector_initialization(self, vpc_collector):
45
+ """Test VPCCollector initialization with account_id."""
46
+ assert vpc_collector.region == "us-east-1"
47
+ assert vpc_collector.account_id == "123456789012"
48
+
49
+ def test_vpc_collector_initialization_no_filter(self, vpc_collector_no_filter):
50
+ """Test VPCCollector initialization without account_id."""
51
+ assert vpc_collector_no_filter.region == "us-east-1"
52
+ assert vpc_collector_no_filter.account_id is None
53
+
54
+ # Test _matches_account_id
55
+
56
+ def test_matches_account_id_with_matching_owner(self, vpc_collector):
57
+ """Test _matches_account_id with matching owner ID."""
58
+ assert vpc_collector._matches_account_id("123456789012") is True
59
+
60
+ def test_matches_account_id_with_non_matching_owner(self, vpc_collector):
61
+ """Test _matches_account_id with non-matching owner ID."""
62
+ assert vpc_collector._matches_account_id("999999999999") is False
63
+
64
+ def test_matches_account_id_no_filter(self, vpc_collector_no_filter):
65
+ """Test _matches_account_id when no account_id filter is set."""
66
+ assert vpc_collector_no_filter._matches_account_id("123456789012") is True
67
+ assert vpc_collector_no_filter._matches_account_id("999999999999") is True
68
+
69
+ # Test _get_vpc_attributes
70
+
71
+ def test_get_vpc_attributes_success(self, vpc_collector, mock_ec2_client):
72
+ """Test _get_vpc_attributes with successful API calls."""
73
+ mock_ec2_client.describe_vpc_attribute.side_effect = [
74
+ {"EnableDnsSupport": {"Value": True}},
75
+ {"EnableDnsHostnames": {"Value": False}},
76
+ ]
77
+
78
+ result = vpc_collector._get_vpc_attributes(mock_ec2_client, "vpc-12345")
79
+
80
+ assert result["EnableDnsSupport"] is True
81
+ assert result["EnableDnsHostnames"] is False
82
+ assert mock_ec2_client.describe_vpc_attribute.call_count == 2
83
+
84
+ def test_get_vpc_attributes_unauthorized(self, vpc_collector, mock_ec2_client):
85
+ """Test _get_vpc_attributes with UnauthorizedOperation error."""
86
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
87
+ mock_ec2_client.describe_vpc_attribute.side_effect = ClientError(error_response, "describe_vpc_attribute")
88
+
89
+ result = vpc_collector._get_vpc_attributes(mock_ec2_client, "vpc-12345")
90
+
91
+ assert result == {}
92
+
93
+ def test_get_vpc_attributes_vpc_not_found(self, vpc_collector, mock_ec2_client):
94
+ """Test _get_vpc_attributes with InvalidVpcID.NotFound error."""
95
+ error_response = {"Error": {"Code": "InvalidVpcID.NotFound"}}
96
+ mock_ec2_client.describe_vpc_attribute.side_effect = ClientError(error_response, "describe_vpc_attribute")
97
+
98
+ result = vpc_collector._get_vpc_attributes(mock_ec2_client, "vpc-invalid")
99
+
100
+ assert result == {}
101
+
102
+ def test_get_vpc_attributes_other_error(self, vpc_collector, mock_ec2_client):
103
+ """Test _get_vpc_attributes with other ClientError."""
104
+ error_response = {"Error": {"Code": "InternalError"}}
105
+ mock_ec2_client.describe_vpc_attribute.side_effect = ClientError(error_response, "describe_vpc_attribute")
106
+
107
+ result = vpc_collector._get_vpc_attributes(mock_ec2_client, "vpc-12345")
108
+
109
+ # Should return empty dict but log the error
110
+ assert result == {}
111
+
112
+ # Test _list_vpcs
113
+
114
+ def test_list_vpcs_success(self, vpc_collector, mock_ec2_client):
115
+ """Test _list_vpcs with successful API call."""
116
+ mock_paginator = MagicMock()
117
+ mock_ec2_client.get_paginator.return_value = mock_paginator
118
+ mock_paginator.paginate.return_value = [
119
+ {
120
+ "Vpcs": [
121
+ {
122
+ "VpcId": "vpc-12345",
123
+ "OwnerId": "123456789012",
124
+ "CidrBlock": "10.0.0.0/16",
125
+ "CidrBlockAssociationSet": [],
126
+ "Ipv6CidrBlockAssociationSet": [],
127
+ "State": "available",
128
+ "IsDefault": False,
129
+ "DhcpOptionsId": "dopt-12345",
130
+ "InstanceTenancy": "default",
131
+ "Tags": [{"Key": "Name", "Value": "Test VPC"}],
132
+ }
133
+ ]
134
+ }
135
+ ]
136
+
137
+ # Mock _get_vpc_attributes
138
+ with patch.object(vpc_collector, "_get_vpc_attributes") as mock_get_attributes:
139
+ mock_get_attributes.return_value = {"EnableDnsSupport": True, "EnableDnsHostnames": True}
140
+
141
+ result = vpc_collector._list_vpcs(mock_ec2_client)
142
+
143
+ assert len(result) == 1
144
+ assert result[0]["VpcId"] == "vpc-12345"
145
+ assert result[0]["Region"] == "us-east-1"
146
+ assert result[0]["EnableDnsSupport"] is True
147
+
148
+ def test_list_vpcs_with_pagination(self, vpc_collector, mock_ec2_client):
149
+ """Test _list_vpcs with multiple pages."""
150
+ mock_paginator = MagicMock()
151
+ mock_ec2_client.get_paginator.return_value = mock_paginator
152
+ mock_paginator.paginate.return_value = [
153
+ {"Vpcs": [{"VpcId": "vpc-1", "OwnerId": "123456789012", "CidrBlock": "10.0.0.0/16", "State": "available"}]},
154
+ {"Vpcs": [{"VpcId": "vpc-2", "OwnerId": "123456789012", "CidrBlock": "10.1.0.0/16", "State": "available"}]},
155
+ ]
156
+
157
+ with patch.object(vpc_collector, "_get_vpc_attributes") as mock_get_attributes:
158
+ mock_get_attributes.return_value = {}
159
+
160
+ result = vpc_collector._list_vpcs(mock_ec2_client)
161
+
162
+ assert len(result) == 2
163
+ assert result[0]["VpcId"] == "vpc-1"
164
+ assert result[1]["VpcId"] == "vpc-2"
165
+
166
+ def test_list_vpcs_account_filtering(self, vpc_collector, mock_ec2_client):
167
+ """Test _list_vpcs filters by account ID."""
168
+ mock_paginator = MagicMock()
169
+ mock_ec2_client.get_paginator.return_value = mock_paginator
170
+ mock_paginator.paginate.return_value = [
171
+ {
172
+ "Vpcs": [
173
+ {"VpcId": "vpc-1", "OwnerId": "123456789012", "CidrBlock": "10.0.0.0/16", "State": "available"},
174
+ {"VpcId": "vpc-2", "OwnerId": "999999999999", "CidrBlock": "10.1.0.0/16", "State": "available"},
175
+ ]
176
+ }
177
+ ]
178
+
179
+ with patch.object(vpc_collector, "_get_vpc_attributes") as mock_get_attributes:
180
+ mock_get_attributes.return_value = {}
181
+
182
+ result = vpc_collector._list_vpcs(mock_ec2_client)
183
+
184
+ # Should only include vpc-1 (matching account ID)
185
+ assert len(result) == 1
186
+ assert result[0]["VpcId"] == "vpc-1"
187
+
188
+ def test_list_vpcs_unauthorized(self, vpc_collector, mock_ec2_client):
189
+ """Test _list_vpcs with UnauthorizedOperation error."""
190
+ mock_paginator = MagicMock()
191
+ mock_ec2_client.get_paginator.return_value = mock_paginator
192
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
193
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_vpcs")
194
+
195
+ result = vpc_collector._list_vpcs(mock_ec2_client)
196
+
197
+ assert result == []
198
+
199
+ def test_list_vpcs_other_error(self, vpc_collector, mock_ec2_client):
200
+ """Test _list_vpcs with other ClientError."""
201
+ mock_paginator = MagicMock()
202
+ mock_ec2_client.get_paginator.return_value = mock_paginator
203
+ error_response = {"Error": {"Code": "InternalError"}}
204
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_vpcs")
205
+
206
+ result = vpc_collector._list_vpcs(mock_ec2_client)
207
+
208
+ assert result == []
209
+
210
+ # Test _list_subnets
211
+
212
+ def test_list_subnets_success(self, vpc_collector, mock_ec2_client):
213
+ """Test _list_subnets with successful API call."""
214
+ mock_paginator = MagicMock()
215
+ mock_ec2_client.get_paginator.return_value = mock_paginator
216
+ mock_paginator.paginate.return_value = [
217
+ {
218
+ "Subnets": [
219
+ {
220
+ "SubnetId": "subnet-12345",
221
+ "VpcId": "vpc-12345",
222
+ "OwnerId": "123456789012",
223
+ "AvailabilityZone": "us-east-1a",
224
+ "AvailabilityZoneId": "use1-az1",
225
+ "CidrBlock": "10.0.1.0/24",
226
+ "Ipv6CidrBlockAssociationSet": [],
227
+ "State": "available",
228
+ "AvailableIpAddressCount": 251,
229
+ "DefaultForAz": False,
230
+ "MapPublicIpOnLaunch": True,
231
+ "AssignIpv6AddressOnCreation": False,
232
+ "Tags": [{"Key": "Name", "Value": "Public Subnet"}],
233
+ }
234
+ ]
235
+ }
236
+ ]
237
+
238
+ result = vpc_collector._list_subnets(mock_ec2_client)
239
+
240
+ assert len(result) == 1
241
+ assert result[0]["SubnetId"] == "subnet-12345"
242
+ assert result[0]["Region"] == "us-east-1"
243
+
244
+ def test_list_subnets_account_filtering(self, vpc_collector, mock_ec2_client):
245
+ """Test _list_subnets filters by account ID."""
246
+ mock_paginator = MagicMock()
247
+ mock_ec2_client.get_paginator.return_value = mock_paginator
248
+ mock_paginator.paginate.return_value = [
249
+ {
250
+ "Subnets": [
251
+ {"SubnetId": "subnet-1", "VpcId": "vpc-1", "OwnerId": "123456789012", "CidrBlock": "10.0.1.0/24"},
252
+ {"SubnetId": "subnet-2", "VpcId": "vpc-2", "OwnerId": "999999999999", "CidrBlock": "10.1.1.0/24"},
253
+ ]
254
+ }
255
+ ]
256
+
257
+ result = vpc_collector._list_subnets(mock_ec2_client)
258
+
259
+ assert len(result) == 1
260
+ assert result[0]["SubnetId"] == "subnet-1"
261
+
262
+ def test_list_subnets_unauthorized(self, vpc_collector, mock_ec2_client):
263
+ """Test _list_subnets with UnauthorizedOperation error."""
264
+ mock_paginator = MagicMock()
265
+ mock_ec2_client.get_paginator.return_value = mock_paginator
266
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
267
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_subnets")
268
+
269
+ result = vpc_collector._list_subnets(mock_ec2_client)
270
+
271
+ assert result == []
272
+
273
+ def test_list_subnets_other_error(self, vpc_collector, mock_ec2_client):
274
+ """Test _list_subnets with other ClientError."""
275
+ mock_paginator = MagicMock()
276
+ mock_ec2_client.get_paginator.return_value = mock_paginator
277
+ error_response = {"Error": {"Code": "InternalError"}}
278
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_subnets")
279
+
280
+ result = vpc_collector._list_subnets(mock_ec2_client)
281
+
282
+ assert result == []
283
+
284
+ # Test _list_security_groups
285
+
286
+ def test_list_security_groups_success(self, vpc_collector, mock_ec2_client):
287
+ """Test _list_security_groups with successful API call."""
288
+ mock_paginator = MagicMock()
289
+ mock_ec2_client.get_paginator.return_value = mock_paginator
290
+ mock_paginator.paginate.return_value = [
291
+ {
292
+ "SecurityGroups": [
293
+ {
294
+ "GroupId": "sg-12345",
295
+ "GroupName": "default",
296
+ "VpcId": "vpc-12345",
297
+ "OwnerId": "123456789012",
298
+ "Description": "Default security group",
299
+ "IpPermissions": [],
300
+ "IpPermissionsEgress": [],
301
+ "Tags": [],
302
+ }
303
+ ]
304
+ }
305
+ ]
306
+
307
+ result = vpc_collector._list_security_groups(mock_ec2_client)
308
+
309
+ assert len(result) == 1
310
+ assert result[0]["GroupId"] == "sg-12345"
311
+ assert result[0]["Region"] == "us-east-1"
312
+
313
+ def test_list_security_groups_account_filtering(self, vpc_collector, mock_ec2_client):
314
+ """Test _list_security_groups filters by account ID."""
315
+ mock_paginator = MagicMock()
316
+ mock_ec2_client.get_paginator.return_value = mock_paginator
317
+ mock_paginator.paginate.return_value = [
318
+ {
319
+ "SecurityGroups": [
320
+ {"GroupId": "sg-1", "GroupName": "sg1", "OwnerId": "123456789012", "Description": "SG 1"},
321
+ {"GroupId": "sg-2", "GroupName": "sg2", "OwnerId": "999999999999", "Description": "SG 2"},
322
+ ]
323
+ }
324
+ ]
325
+
326
+ result = vpc_collector._list_security_groups(mock_ec2_client)
327
+
328
+ assert len(result) == 1
329
+ assert result[0]["GroupId"] == "sg-1"
330
+
331
+ def test_list_security_groups_unauthorized(self, vpc_collector, mock_ec2_client):
332
+ """Test _list_security_groups with UnauthorizedOperation error."""
333
+ mock_paginator = MagicMock()
334
+ mock_ec2_client.get_paginator.return_value = mock_paginator
335
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
336
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_security_groups")
337
+
338
+ result = vpc_collector._list_security_groups(mock_ec2_client)
339
+
340
+ assert result == []
341
+
342
+ def test_list_security_groups_other_error(self, vpc_collector, mock_ec2_client):
343
+ """Test _list_security_groups with other ClientError."""
344
+ mock_paginator = MagicMock()
345
+ mock_ec2_client.get_paginator.return_value = mock_paginator
346
+ error_response = {"Error": {"Code": "InternalError"}}
347
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_security_groups")
348
+
349
+ result = vpc_collector._list_security_groups(mock_ec2_client)
350
+
351
+ assert result == []
352
+
353
+ # Test _list_network_acls
354
+
355
+ def test_list_network_acls_success(self, vpc_collector, mock_ec2_client):
356
+ """Test _list_network_acls with successful API call."""
357
+ mock_paginator = MagicMock()
358
+ mock_ec2_client.get_paginator.return_value = mock_paginator
359
+ mock_paginator.paginate.return_value = [
360
+ {
361
+ "NetworkAcls": [
362
+ {
363
+ "NetworkAclId": "acl-12345",
364
+ "VpcId": "vpc-12345",
365
+ "OwnerId": "123456789012",
366
+ "IsDefault": True,
367
+ "Entries": [],
368
+ "Associations": [],
369
+ "Tags": [],
370
+ }
371
+ ]
372
+ }
373
+ ]
374
+
375
+ result = vpc_collector._list_network_acls(mock_ec2_client)
376
+
377
+ assert len(result) == 1
378
+ assert result[0]["NetworkAclId"] == "acl-12345"
379
+ assert result[0]["Region"] == "us-east-1"
380
+
381
+ def test_list_network_acls_account_filtering(self, vpc_collector, mock_ec2_client):
382
+ """Test _list_network_acls filters by account ID."""
383
+ mock_paginator = MagicMock()
384
+ mock_ec2_client.get_paginator.return_value = mock_paginator
385
+ mock_paginator.paginate.return_value = [
386
+ {
387
+ "NetworkAcls": [
388
+ {"NetworkAclId": "acl-1", "VpcId": "vpc-1", "OwnerId": "123456789012", "IsDefault": True},
389
+ {"NetworkAclId": "acl-2", "VpcId": "vpc-2", "OwnerId": "999999999999", "IsDefault": False},
390
+ ]
391
+ }
392
+ ]
393
+
394
+ result = vpc_collector._list_network_acls(mock_ec2_client)
395
+
396
+ assert len(result) == 1
397
+ assert result[0]["NetworkAclId"] == "acl-1"
398
+
399
+ def test_list_network_acls_unauthorized(self, vpc_collector, mock_ec2_client):
400
+ """Test _list_network_acls with UnauthorizedOperation error."""
401
+ mock_paginator = MagicMock()
402
+ mock_ec2_client.get_paginator.return_value = mock_paginator
403
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
404
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_network_acls")
405
+
406
+ result = vpc_collector._list_network_acls(mock_ec2_client)
407
+
408
+ assert result == []
409
+
410
+ def test_list_network_acls_other_error(self, vpc_collector, mock_ec2_client):
411
+ """Test _list_network_acls with other ClientError."""
412
+ mock_paginator = MagicMock()
413
+ mock_ec2_client.get_paginator.return_value = mock_paginator
414
+ error_response = {"Error": {"Code": "InternalError"}}
415
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_network_acls")
416
+
417
+ result = vpc_collector._list_network_acls(mock_ec2_client)
418
+
419
+ assert result == []
420
+
421
+ # Test _list_route_tables
422
+
423
+ def test_list_route_tables_success(self, vpc_collector, mock_ec2_client):
424
+ """Test _list_route_tables with successful API call."""
425
+ mock_paginator = MagicMock()
426
+ mock_ec2_client.get_paginator.return_value = mock_paginator
427
+ mock_paginator.paginate.return_value = [
428
+ {
429
+ "RouteTables": [
430
+ {
431
+ "RouteTableId": "rtb-12345",
432
+ "VpcId": "vpc-12345",
433
+ "OwnerId": "123456789012",
434
+ "Routes": [],
435
+ "Associations": [],
436
+ "PropagatingVgws": [],
437
+ "Tags": [],
438
+ }
439
+ ]
440
+ }
441
+ ]
442
+
443
+ result = vpc_collector._list_route_tables(mock_ec2_client)
444
+
445
+ assert len(result) == 1
446
+ assert result[0]["RouteTableId"] == "rtb-12345"
447
+ assert result[0]["Region"] == "us-east-1"
448
+
449
+ def test_list_route_tables_account_filtering(self, vpc_collector, mock_ec2_client):
450
+ """Test _list_route_tables filters by account ID."""
451
+ mock_paginator = MagicMock()
452
+ mock_ec2_client.get_paginator.return_value = mock_paginator
453
+ mock_paginator.paginate.return_value = [
454
+ {
455
+ "RouteTables": [
456
+ {"RouteTableId": "rtb-1", "VpcId": "vpc-1", "OwnerId": "123456789012"},
457
+ {"RouteTableId": "rtb-2", "VpcId": "vpc-2", "OwnerId": "999999999999"},
458
+ ]
459
+ }
460
+ ]
461
+
462
+ result = vpc_collector._list_route_tables(mock_ec2_client)
463
+
464
+ assert len(result) == 1
465
+ assert result[0]["RouteTableId"] == "rtb-1"
466
+
467
+ def test_list_route_tables_unauthorized(self, vpc_collector, mock_ec2_client):
468
+ """Test _list_route_tables with UnauthorizedOperation error."""
469
+ mock_paginator = MagicMock()
470
+ mock_ec2_client.get_paginator.return_value = mock_paginator
471
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
472
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_route_tables")
473
+
474
+ result = vpc_collector._list_route_tables(mock_ec2_client)
475
+
476
+ assert result == []
477
+
478
+ def test_list_route_tables_other_error(self, vpc_collector, mock_ec2_client):
479
+ """Test _list_route_tables with other ClientError."""
480
+ mock_paginator = MagicMock()
481
+ mock_ec2_client.get_paginator.return_value = mock_paginator
482
+ error_response = {"Error": {"Code": "InternalError"}}
483
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_route_tables")
484
+
485
+ result = vpc_collector._list_route_tables(mock_ec2_client)
486
+
487
+ assert result == []
488
+
489
+ # Test _list_internet_gateways
490
+
491
+ def test_list_internet_gateways_success(self, vpc_collector, mock_ec2_client):
492
+ """Test _list_internet_gateways with successful API call."""
493
+ mock_paginator = MagicMock()
494
+ mock_ec2_client.get_paginator.return_value = mock_paginator
495
+ mock_paginator.paginate.return_value = [
496
+ {
497
+ "InternetGateways": [
498
+ {
499
+ "InternetGatewayId": "igw-12345",
500
+ "OwnerId": "123456789012",
501
+ "Attachments": [{"State": "available", "VpcId": "vpc-12345"}],
502
+ "Tags": [],
503
+ }
504
+ ]
505
+ }
506
+ ]
507
+
508
+ result = vpc_collector._list_internet_gateways(mock_ec2_client)
509
+
510
+ assert len(result) == 1
511
+ assert result[0]["InternetGatewayId"] == "igw-12345"
512
+ assert result[0]["Region"] == "us-east-1"
513
+
514
+ def test_list_internet_gateways_account_filtering(self, vpc_collector, mock_ec2_client):
515
+ """Test _list_internet_gateways filters by account ID."""
516
+ mock_paginator = MagicMock()
517
+ mock_ec2_client.get_paginator.return_value = mock_paginator
518
+ mock_paginator.paginate.return_value = [
519
+ {
520
+ "InternetGateways": [
521
+ {"InternetGatewayId": "igw-1", "OwnerId": "123456789012", "Attachments": []},
522
+ {"InternetGatewayId": "igw-2", "OwnerId": "999999999999", "Attachments": []},
523
+ ]
524
+ }
525
+ ]
526
+
527
+ result = vpc_collector._list_internet_gateways(mock_ec2_client)
528
+
529
+ assert len(result) == 1
530
+ assert result[0]["InternetGatewayId"] == "igw-1"
531
+
532
+ def test_list_internet_gateways_unauthorized(self, vpc_collector, mock_ec2_client):
533
+ """Test _list_internet_gateways with UnauthorizedOperation error."""
534
+ mock_paginator = MagicMock()
535
+ mock_ec2_client.get_paginator.return_value = mock_paginator
536
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
537
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_internet_gateways")
538
+
539
+ result = vpc_collector._list_internet_gateways(mock_ec2_client)
540
+
541
+ assert result == []
542
+
543
+ def test_list_internet_gateways_other_error(self, vpc_collector, mock_ec2_client):
544
+ """Test _list_internet_gateways with other ClientError."""
545
+ mock_paginator = MagicMock()
546
+ mock_ec2_client.get_paginator.return_value = mock_paginator
547
+ error_response = {"Error": {"Code": "InternalError"}}
548
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_internet_gateways")
549
+
550
+ result = vpc_collector._list_internet_gateways(mock_ec2_client)
551
+
552
+ assert result == []
553
+
554
+ # Test _list_nat_gateways
555
+
556
+ def test_list_nat_gateways_success(self, vpc_collector, mock_ec2_client):
557
+ """Test _list_nat_gateways with successful API call."""
558
+ mock_paginator = MagicMock()
559
+ mock_ec2_client.get_paginator.return_value = mock_paginator
560
+ mock_paginator.paginate.return_value = [
561
+ {
562
+ "NatGateways": [
563
+ {
564
+ "NatGatewayId": "nat-12345",
565
+ "VpcId": "vpc-12345",
566
+ "SubnetId": "subnet-12345",
567
+ "State": "available",
568
+ "ConnectivityType": "public",
569
+ "NatGatewayAddresses": [],
570
+ "CreateTime": datetime(2024, 1, 1),
571
+ "DeleteTime": None,
572
+ "Tags": [],
573
+ }
574
+ ]
575
+ }
576
+ ]
577
+
578
+ result = vpc_collector._list_nat_gateways(mock_ec2_client)
579
+
580
+ assert len(result) == 1
581
+ assert result[0]["NatGatewayId"] == "nat-12345"
582
+ assert result[0]["Region"] == "us-east-1"
583
+
584
+ def test_list_nat_gateways_with_delete_time(self, vpc_collector, mock_ec2_client):
585
+ """Test _list_nat_gateways with DeleteTime present."""
586
+ mock_paginator = MagicMock()
587
+ mock_ec2_client.get_paginator.return_value = mock_paginator
588
+ mock_paginator.paginate.return_value = [
589
+ {
590
+ "NatGateways": [
591
+ {
592
+ "NatGatewayId": "nat-12345",
593
+ "VpcId": "vpc-12345",
594
+ "SubnetId": "subnet-12345",
595
+ "State": "deleted",
596
+ "ConnectivityType": "public",
597
+ "NatGatewayAddresses": [],
598
+ "CreateTime": datetime(2024, 1, 1),
599
+ "DeleteTime": datetime(2024, 1, 2),
600
+ "Tags": [],
601
+ }
602
+ ]
603
+ }
604
+ ]
605
+
606
+ result = vpc_collector._list_nat_gateways(mock_ec2_client)
607
+
608
+ assert len(result) == 1
609
+ assert result[0]["DeleteTime"] is not None
610
+
611
+ def test_list_nat_gateways_unauthorized(self, vpc_collector, mock_ec2_client):
612
+ """Test _list_nat_gateways with UnauthorizedOperation error."""
613
+ mock_paginator = MagicMock()
614
+ mock_ec2_client.get_paginator.return_value = mock_paginator
615
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
616
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_nat_gateways")
617
+
618
+ result = vpc_collector._list_nat_gateways(mock_ec2_client)
619
+
620
+ assert result == []
621
+
622
+ def test_list_nat_gateways_other_error(self, vpc_collector, mock_ec2_client):
623
+ """Test _list_nat_gateways with other ClientError."""
624
+ mock_paginator = MagicMock()
625
+ mock_ec2_client.get_paginator.return_value = mock_paginator
626
+ error_response = {"Error": {"Code": "InternalError"}}
627
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_nat_gateways")
628
+
629
+ result = vpc_collector._list_nat_gateways(mock_ec2_client)
630
+
631
+ assert result == []
632
+
633
+ # Test _list_vpc_endpoints
634
+
635
+ def test_list_vpc_endpoints_success(self, vpc_collector, mock_ec2_client):
636
+ """Test _list_vpc_endpoints with successful API call."""
637
+ mock_paginator = MagicMock()
638
+ mock_ec2_client.get_paginator.return_value = mock_paginator
639
+ mock_paginator.paginate.return_value = [
640
+ {
641
+ "VpcEndpoints": [
642
+ {
643
+ "VpcEndpointId": "vpce-12345",
644
+ "VpcId": "vpc-12345",
645
+ "OwnerId": "123456789012",
646
+ "ServiceName": "com.amazonaws.us-east-1.s3",
647
+ "VpcEndpointType": "Gateway",
648
+ "State": "available",
649
+ "PolicyDocument": '{"Version": "2012-10-17"}',
650
+ "SubnetIds": [],
651
+ "RouteTableIds": ["rtb-12345"],
652
+ "Groups": [],
653
+ "PrivateDnsEnabled": False,
654
+ "DnsEntries": [],
655
+ "CreationTimestamp": datetime(2024, 1, 1),
656
+ "Tags": [],
657
+ }
658
+ ]
659
+ }
660
+ ]
661
+
662
+ result = vpc_collector._list_vpc_endpoints(mock_ec2_client)
663
+
664
+ assert len(result) == 1
665
+ assert result[0]["VpcEndpointId"] == "vpce-12345"
666
+ assert result[0]["Region"] == "us-east-1"
667
+
668
+ def test_list_vpc_endpoints_account_filtering(self, vpc_collector, mock_ec2_client):
669
+ """Test _list_vpc_endpoints filters by account ID."""
670
+ mock_paginator = MagicMock()
671
+ mock_ec2_client.get_paginator.return_value = mock_paginator
672
+ mock_paginator.paginate.return_value = [
673
+ {
674
+ "VpcEndpoints": [
675
+ {
676
+ "VpcEndpointId": "vpce-1",
677
+ "VpcId": "vpc-1",
678
+ "OwnerId": "123456789012",
679
+ "ServiceName": "com.amazonaws.us-east-1.s3",
680
+ "VpcEndpointType": "Gateway",
681
+ "State": "available",
682
+ "CreationTimestamp": datetime(2024, 1, 1),
683
+ },
684
+ {
685
+ "VpcEndpointId": "vpce-2",
686
+ "VpcId": "vpc-2",
687
+ "OwnerId": "999999999999",
688
+ "ServiceName": "com.amazonaws.us-east-1.ec2",
689
+ "VpcEndpointType": "Interface",
690
+ "State": "available",
691
+ "CreationTimestamp": datetime(2024, 1, 1),
692
+ },
693
+ ]
694
+ }
695
+ ]
696
+
697
+ result = vpc_collector._list_vpc_endpoints(mock_ec2_client)
698
+
699
+ assert len(result) == 1
700
+ assert result[0]["VpcEndpointId"] == "vpce-1"
701
+
702
+ def test_list_vpc_endpoints_unauthorized(self, vpc_collector, mock_ec2_client):
703
+ """Test _list_vpc_endpoints with UnauthorizedOperation error."""
704
+ mock_paginator = MagicMock()
705
+ mock_ec2_client.get_paginator.return_value = mock_paginator
706
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
707
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_vpc_endpoints")
708
+
709
+ result = vpc_collector._list_vpc_endpoints(mock_ec2_client)
710
+
711
+ assert result == []
712
+
713
+ def test_list_vpc_endpoints_other_error(self, vpc_collector, mock_ec2_client):
714
+ """Test _list_vpc_endpoints with other ClientError."""
715
+ mock_paginator = MagicMock()
716
+ mock_ec2_client.get_paginator.return_value = mock_paginator
717
+ error_response = {"Error": {"Code": "InternalError"}}
718
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_vpc_endpoints")
719
+
720
+ result = vpc_collector._list_vpc_endpoints(mock_ec2_client)
721
+
722
+ assert result == []
723
+
724
+ # Test _list_vpc_peering_connections
725
+
726
+ def test_list_vpc_peering_connections_success(self, vpc_collector, mock_ec2_client):
727
+ """Test _list_vpc_peering_connections with successful API call."""
728
+ mock_paginator = MagicMock()
729
+ mock_ec2_client.get_paginator.return_value = mock_paginator
730
+ mock_paginator.paginate.return_value = [
731
+ {
732
+ "VpcPeeringConnections": [
733
+ {
734
+ "VpcPeeringConnectionId": "pcx-12345",
735
+ "RequesterVpcInfo": {
736
+ "VpcId": "vpc-12345",
737
+ "OwnerId": "123456789012",
738
+ "CidrBlock": "10.0.0.0/16",
739
+ "Region": "us-east-1",
740
+ },
741
+ "AccepterVpcInfo": {
742
+ "VpcId": "vpc-67890",
743
+ "OwnerId": "999999999999",
744
+ "CidrBlock": "10.1.0.0/16",
745
+ "Region": "us-west-2",
746
+ },
747
+ "Status": {"Code": "active"},
748
+ "ExpirationTime": None,
749
+ "Tags": [],
750
+ }
751
+ ]
752
+ }
753
+ ]
754
+
755
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
756
+
757
+ assert len(result) == 1
758
+ assert result[0]["VpcPeeringConnectionId"] == "pcx-12345"
759
+ assert result[0]["Region"] == "us-east-1"
760
+
761
+ def test_list_vpc_peering_connections_requester_filter(self, vpc_collector, mock_ec2_client):
762
+ """Test _list_vpc_peering_connections filters by requester account ID."""
763
+ mock_paginator = MagicMock()
764
+ mock_ec2_client.get_paginator.return_value = mock_paginator
765
+ mock_paginator.paginate.return_value = [
766
+ {
767
+ "VpcPeeringConnections": [
768
+ {
769
+ "VpcPeeringConnectionId": "pcx-1",
770
+ "RequesterVpcInfo": {"VpcId": "vpc-1", "OwnerId": "123456789012"},
771
+ "AccepterVpcInfo": {"VpcId": "vpc-2", "OwnerId": "999999999999"},
772
+ "Status": {"Code": "active"},
773
+ },
774
+ {
775
+ "VpcPeeringConnectionId": "pcx-2",
776
+ "RequesterVpcInfo": {"VpcId": "vpc-3", "OwnerId": "888888888888"},
777
+ "AccepterVpcInfo": {"VpcId": "vpc-4", "OwnerId": "777777777777"},
778
+ "Status": {"Code": "active"},
779
+ },
780
+ ]
781
+ }
782
+ ]
783
+
784
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
785
+
786
+ # Should include pcx-1 (requester matches account_id)
787
+ assert len(result) == 1
788
+ assert result[0]["VpcPeeringConnectionId"] == "pcx-1"
789
+
790
+ def test_list_vpc_peering_connections_accepter_filter(self, vpc_collector, mock_ec2_client):
791
+ """Test _list_vpc_peering_connections filters by accepter account ID."""
792
+ mock_paginator = MagicMock()
793
+ mock_ec2_client.get_paginator.return_value = mock_paginator
794
+ mock_paginator.paginate.return_value = [
795
+ {
796
+ "VpcPeeringConnections": [
797
+ {
798
+ "VpcPeeringConnectionId": "pcx-1",
799
+ "RequesterVpcInfo": {"VpcId": "vpc-1", "OwnerId": "999999999999"},
800
+ "AccepterVpcInfo": {"VpcId": "vpc-2", "OwnerId": "123456789012"},
801
+ "Status": {"Code": "active"},
802
+ }
803
+ ]
804
+ }
805
+ ]
806
+
807
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
808
+
809
+ # Should include pcx-1 (accepter matches account_id)
810
+ assert len(result) == 1
811
+ assert result[0]["VpcPeeringConnectionId"] == "pcx-1"
812
+
813
+ def test_list_vpc_peering_connections_with_expiration(self, vpc_collector, mock_ec2_client):
814
+ """Test _list_vpc_peering_connections with ExpirationTime."""
815
+ mock_paginator = MagicMock()
816
+ mock_ec2_client.get_paginator.return_value = mock_paginator
817
+ mock_paginator.paginate.return_value = [
818
+ {
819
+ "VpcPeeringConnections": [
820
+ {
821
+ "VpcPeeringConnectionId": "pcx-1",
822
+ "RequesterVpcInfo": {"VpcId": "vpc-1", "OwnerId": "123456789012"},
823
+ "AccepterVpcInfo": {"VpcId": "vpc-2", "OwnerId": "999999999999"},
824
+ "Status": {"Code": "expired", "Message": "Expired"},
825
+ "ExpirationTime": datetime(2024, 1, 1),
826
+ "Tags": [],
827
+ }
828
+ ]
829
+ }
830
+ ]
831
+
832
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
833
+
834
+ assert len(result) == 1
835
+ assert result[0]["ExpirationTime"] is not None
836
+ assert result[0]["StatusMessage"] == "Expired"
837
+
838
+ def test_list_vpc_peering_connections_unauthorized(self, vpc_collector, mock_ec2_client):
839
+ """Test _list_vpc_peering_connections with UnauthorizedOperation error."""
840
+ mock_paginator = MagicMock()
841
+ mock_ec2_client.get_paginator.return_value = mock_paginator
842
+ error_response = {"Error": {"Code": "UnauthorizedOperation"}}
843
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_vpc_peering_connections")
844
+
845
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
846
+
847
+ assert result == []
848
+
849
+ def test_list_vpc_peering_connections_other_error(self, vpc_collector, mock_ec2_client):
850
+ """Test _list_vpc_peering_connections with other ClientError."""
851
+ mock_paginator = MagicMock()
852
+ mock_ec2_client.get_paginator.return_value = mock_paginator
853
+ error_response = {"Error": {"Code": "InternalError"}}
854
+ mock_paginator.paginate.side_effect = ClientError(error_response, "describe_vpc_peering_connections")
855
+
856
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
857
+
858
+ assert result == []
859
+
860
+ def test_list_vpc_peering_connections_no_match_filter(self, vpc_collector, mock_ec2_client):
861
+ """Test _list_vpc_peering_connections filters out non-matching peering connections."""
862
+ mock_paginator = MagicMock()
863
+ mock_ec2_client.get_paginator.return_value = mock_paginator
864
+ mock_paginator.paginate.return_value = [
865
+ {
866
+ "VpcPeeringConnections": [
867
+ {
868
+ "VpcPeeringConnectionId": "pcx-1",
869
+ "RequesterVpcInfo": {"VpcId": "vpc-1", "OwnerId": "888888888888"},
870
+ "AccepterVpcInfo": {"VpcId": "vpc-2", "OwnerId": "999999999999"},
871
+ "Status": {"Code": "active"},
872
+ }
873
+ ]
874
+ }
875
+ ]
876
+
877
+ result = vpc_collector._list_vpc_peering_connections(mock_ec2_client)
878
+
879
+ # Should not include pcx-1 (neither requester nor accepter matches account_id)
880
+ assert len(result) == 0
881
+
882
+ # Test collect method
883
+
884
+ def test_collect_success(self, vpc_collector, mock_session):
885
+ """Test collect method with successful API calls."""
886
+ mock_ec2_client = MagicMock()
887
+ mock_session.client.return_value = mock_ec2_client
888
+
889
+ # Mock all list methods
890
+ with patch.object(vpc_collector, "_list_vpcs") as mock_vpcs, patch.object(
891
+ vpc_collector, "_list_subnets"
892
+ ) as mock_subnets, patch.object(vpc_collector, "_list_security_groups") as mock_sgs, patch.object(
893
+ vpc_collector, "_list_network_acls"
894
+ ) as mock_acls, patch.object(
895
+ vpc_collector, "_list_route_tables"
896
+ ) as mock_route_tables, patch.object(
897
+ vpc_collector, "_list_internet_gateways"
898
+ ) as mock_igws, patch.object(
899
+ vpc_collector, "_list_nat_gateways"
900
+ ) as mock_nats, patch.object(
901
+ vpc_collector, "_list_vpc_endpoints"
902
+ ) as mock_endpoints, patch.object(
903
+ vpc_collector, "_list_vpc_peering_connections"
904
+ ) as mock_peering:
905
+ mock_vpcs.return_value = [{"VpcId": "vpc-1"}]
906
+ mock_subnets.return_value = [{"SubnetId": "subnet-1"}]
907
+ mock_sgs.return_value = [{"GroupId": "sg-1"}]
908
+ mock_acls.return_value = [{"NetworkAclId": "acl-1"}]
909
+ mock_route_tables.return_value = [{"RouteTableId": "rtb-1"}]
910
+ mock_igws.return_value = [{"InternetGatewayId": "igw-1"}]
911
+ mock_nats.return_value = [{"NatGatewayId": "nat-1"}]
912
+ mock_endpoints.return_value = [{"VpcEndpointId": "vpce-1"}]
913
+ mock_peering.return_value = [{"VpcPeeringConnectionId": "pcx-1"}]
914
+
915
+ result = vpc_collector.collect()
916
+
917
+ assert len(result["VPCs"]) == 1
918
+ assert len(result["Subnets"]) == 1
919
+ assert len(result["SecurityGroups"]) == 1
920
+ assert len(result["NetworkACLs"]) == 1
921
+ assert len(result["RouteTables"]) == 1
922
+ assert len(result["InternetGateways"]) == 1
923
+ assert len(result["NATGateways"]) == 1
924
+ assert len(result["VPCEndpoints"]) == 1
925
+ assert len(result["VPCPeeringConnections"]) == 1
926
+
927
+ def test_collect_with_client_error(self, vpc_collector, mock_session):
928
+ """Test collect method with ClientError."""
929
+ mock_ec2_client = MagicMock()
930
+ mock_session.client.return_value = mock_ec2_client
931
+
932
+ error_response = {"Error": {"Code": "AccessDeniedException"}}
933
+
934
+ with patch.object(vpc_collector, "_list_vpcs") as mock_vpcs:
935
+ mock_vpcs.side_effect = ClientError(error_response, "describe_vpcs")
936
+
937
+ result = vpc_collector.collect()
938
+
939
+ # Should return empty structure but not crash
940
+ assert result["VPCs"] == []
941
+
942
+ def test_collect_with_unexpected_error(self, vpc_collector, mock_session):
943
+ """Test collect method with unexpected error."""
944
+ mock_ec2_client = MagicMock()
945
+ mock_session.client.return_value = mock_ec2_client
946
+
947
+ with patch.object(vpc_collector, "_list_vpcs") as mock_vpcs:
948
+ mock_vpcs.side_effect = Exception("Unexpected error")
949
+
950
+ result = vpc_collector.collect()
951
+
952
+ # Should return empty structure but not crash
953
+ assert result["VPCs"] == []
954
+
955
+ def test_collect_empty_results(self, vpc_collector, mock_session):
956
+ """Test collect method with no VPC resources."""
957
+ mock_ec2_client = MagicMock()
958
+ mock_session.client.return_value = mock_ec2_client
959
+
960
+ # Mock all list methods to return empty lists
961
+ with patch.object(vpc_collector, "_list_vpcs") as mock_vpcs, patch.object(
962
+ vpc_collector, "_list_subnets"
963
+ ) as mock_subnets, patch.object(vpc_collector, "_list_security_groups") as mock_sgs, patch.object(
964
+ vpc_collector, "_list_network_acls"
965
+ ) as mock_acls, patch.object(
966
+ vpc_collector, "_list_route_tables"
967
+ ) as mock_route_tables, patch.object(
968
+ vpc_collector, "_list_internet_gateways"
969
+ ) as mock_igws, patch.object(
970
+ vpc_collector, "_list_nat_gateways"
971
+ ) as mock_nats, patch.object(
972
+ vpc_collector, "_list_vpc_endpoints"
973
+ ) as mock_endpoints, patch.object(
974
+ vpc_collector, "_list_vpc_peering_connections"
975
+ ) as mock_peering:
976
+ mock_vpcs.return_value = []
977
+ mock_subnets.return_value = []
978
+ mock_sgs.return_value = []
979
+ mock_acls.return_value = []
980
+ mock_route_tables.return_value = []
981
+ mock_igws.return_value = []
982
+ mock_nats.return_value = []
983
+ mock_endpoints.return_value = []
984
+ mock_peering.return_value = []
985
+
986
+ result = vpc_collector.collect()
987
+
988
+ assert result["VPCs"] == []
989
+ assert result["Subnets"] == []
990
+ assert result["SecurityGroups"] == []
991
+ assert result["NetworkACLs"] == []
992
+ assert result["RouteTables"] == []
993
+ assert result["InternetGateways"] == []
994
+ assert result["NATGateways"] == []
995
+ assert result["VPCEndpoints"] == []
996
+ assert result["VPCPeeringConnections"] == []