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,341 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Unit tests for AWS Audit Manager Evidence-Based Compliance Aggregation."""
4
+
5
+ import unittest
6
+
7
+ from regscale.integrations.commercial.aws.audit_manager_compliance import AWSAuditManagerComplianceItem
8
+
9
+
10
+ class TestEvidenceAggregation(unittest.TestCase):
11
+ """Test cases for evidence-based compliance aggregation logic."""
12
+
13
+ def setUp(self):
14
+ """Set up test fixtures."""
15
+ self.assessment_data = {
16
+ "name": "Test Assessment",
17
+ "arn": "arn:aws:auditmanager:us-east-1:123456789012:assessment/test",
18
+ "framework": {"type": "Standard", "metadata": {"name": "NIST SP 800-53 Revision 5"}},
19
+ "complianceType": "NIST800-53",
20
+ "awsAccount": {"id": "123456789012", "name": "Test Account"},
21
+ }
22
+
23
+ self.control_data = {
24
+ "id": "test-control-id",
25
+ "name": "CP-10(2) - Transaction Recovery",
26
+ "description": "Control description",
27
+ "status": "REVIEWED", # Workflow status - not used for compliance
28
+ "evidenceCount": 8,
29
+ }
30
+
31
+ def test_all_compliant_evidence_passes(self):
32
+ """Test that all COMPLIANT evidence results in PASS."""
33
+ evidence = [
34
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Security Hub"},
35
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
36
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Security Hub"},
37
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
38
+ ]
39
+
40
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
41
+ self.assertEqual(item.compliance_result, "PASS")
42
+
43
+ def test_any_failed_evidence_fails_control(self):
44
+ """Test that ANY FAILED evidence causes control to FAIL."""
45
+ evidence = [
46
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
47
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
48
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
49
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"}, # ONE failure
50
+ ]
51
+
52
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
53
+ self.assertEqual(item.compliance_result, "FAIL")
54
+
55
+ def test_multiple_failed_evidence_fails_control(self):
56
+ """Test that multiple FAILED evidence items causes control to FAIL."""
57
+ evidence = [
58
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
59
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
60
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
61
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
62
+ ]
63
+
64
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
65
+ self.assertEqual(item.compliance_result, "FAIL")
66
+
67
+ def test_all_failed_evidence_fails_control(self):
68
+ """Test that all FAILED evidence results in FAIL."""
69
+ evidence = [
70
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
71
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
72
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
73
+ ]
74
+
75
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
76
+ self.assertEqual(item.compliance_result, "FAIL")
77
+
78
+ def test_no_evidence_returns_none(self):
79
+ """Test that no evidence results in None (control should not be updated)."""
80
+ evidence = []
81
+
82
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
83
+ self.assertIsNone(item.compliance_result)
84
+
85
+ def test_none_evidence_returns_none(self):
86
+ """Test that None evidence results in None (control should not be updated)."""
87
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, None)
88
+ self.assertIsNone(item.compliance_result)
89
+
90
+ def test_inconclusive_evidence_only_returns_none(self):
91
+ """Test that only inconclusive evidence (null checks) results in None (control should not be updated)."""
92
+ evidence = [
93
+ {"dataSource": "AWS CloudTrail"}, # No complianceCheck field
94
+ {"complianceCheck": None, "dataSource": "Manual"},
95
+ {"dataSource": "API Call"}, # No complianceCheck field
96
+ ]
97
+
98
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
99
+ self.assertIsNone(item.compliance_result)
100
+
101
+ def test_compliant_with_inconclusive_passes(self):
102
+ """Test that COMPLIANT evidence with some inconclusive results in PASS."""
103
+ evidence = [
104
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Security Hub"},
105
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
106
+ {"dataSource": "AWS CloudTrail"}, # No complianceCheck
107
+ {"complianceCheck": None, "dataSource": "Manual"}, # Null check
108
+ ]
109
+
110
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
111
+ self.assertEqual(item.compliance_result, "PASS")
112
+
113
+ def test_failed_with_inconclusive_fails(self):
114
+ """Test that FAILED evidence with inconclusive results in FAIL."""
115
+ evidence = [
116
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
117
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
118
+ {"dataSource": "AWS CloudTrail"}, # No complianceCheck
119
+ {"complianceCheck": None, "dataSource": "Manual"}, # Null check
120
+ ]
121
+
122
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
123
+ self.assertEqual(item.compliance_result, "FAIL")
124
+
125
+ def test_real_world_mixed_evidence_cp10(self):
126
+ """Test real-world scenario: CP-10(2) with 4 COMPLIANT and 4 FAILED."""
127
+ # Based on actual audit_manager_evidence_cp_10(2)_2025-10-17.jsonl data
128
+ evidence = [
129
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
130
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
131
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
132
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
133
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
134
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
135
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
136
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
137
+ ]
138
+
139
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
140
+ # Should FAIL because there are FAILED evidence items
141
+ self.assertEqual(item.compliance_result, "FAIL")
142
+
143
+ def test_workflow_status_not_used_for_compliance(self):
144
+ """Test that control workflow status (REVIEWED) does NOT determine compliance."""
145
+ # Control marked as REVIEWED (workflow status) but has failing evidence
146
+ self.control_data["status"] = "REVIEWED"
147
+ evidence = [
148
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
149
+ ]
150
+
151
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
152
+ # Should FAIL based on evidence, not REVIEWED status
153
+ self.assertEqual(item.compliance_result, "FAIL")
154
+ # Verify workflow status is still REVIEWED
155
+ self.assertEqual(item.control_status, "REVIEWED")
156
+
157
+ def test_under_review_with_passing_evidence(self):
158
+ """Test that UNDER_REVIEW workflow status with passing evidence results in PASS."""
159
+ self.control_data["status"] = "UNDER_REVIEW"
160
+ evidence = [
161
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
162
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Security Hub"},
163
+ ]
164
+
165
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
166
+ # Should PASS based on evidence, regardless of UNDER_REVIEW status
167
+ self.assertEqual(item.compliance_result, "PASS")
168
+ # Verify workflow status is still UNDER_REVIEW
169
+ self.assertEqual(item.control_status, "UNDER_REVIEW")
170
+
171
+ def test_compliance_result_caching(self):
172
+ """Test that compliance result is cached after first calculation."""
173
+ evidence = [
174
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
175
+ ]
176
+
177
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
178
+
179
+ # First call
180
+ result1 = item.compliance_result
181
+ self.assertEqual(result1, "PASS")
182
+
183
+ # Verify cached value is used
184
+ self.assertEqual(item._aggregated_compliance_result, "PASS")
185
+
186
+ # Second call should return same cached result
187
+ result2 = item.compliance_result
188
+ self.assertEqual(result2, "PASS")
189
+
190
+ def test_severity_when_passed(self):
191
+ """Test that severity is None when control passes."""
192
+ evidence = [
193
+ {"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"},
194
+ ]
195
+
196
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
197
+ self.assertIsNone(item.severity)
198
+
199
+ def test_severity_when_failed(self):
200
+ """Test that severity is set when control fails."""
201
+ evidence = [
202
+ {"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"},
203
+ ]
204
+
205
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
206
+ self.assertEqual(item.severity, "MEDIUM")
207
+
208
+
209
+ class TestEvidenceAggregationEdgeCases(unittest.TestCase):
210
+ """Test edge cases for evidence aggregation."""
211
+
212
+ def setUp(self):
213
+ """Set up test fixtures."""
214
+ self.assessment_data = {
215
+ "name": "Edge Case Assessment",
216
+ "arn": "arn:aws:auditmanager:us-east-1:123456789012:assessment/test",
217
+ "framework": {"type": "Standard", "metadata": {"name": "NIST SP 800-53 Revision 5"}},
218
+ "complianceType": "NIST800-53",
219
+ "awsAccount": {"id": "123456789012"},
220
+ }
221
+
222
+ self.control_data = {
223
+ "id": "test-control-id",
224
+ "name": "AC-2 - Account Management",
225
+ "description": "Control description",
226
+ "status": "REVIEWED",
227
+ }
228
+
229
+ def test_case_sensitivity_compliant(self):
230
+ """Test that complianceCheck is case-sensitive (COMPLIANT vs compliant)."""
231
+ evidence = [
232
+ {"complianceCheck": "compliant", "dataSource": "AWS Config"}, # lowercase
233
+ ]
234
+
235
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
236
+ # Lowercase "compliant" should NOT match "COMPLIANT", treated as inconclusive
237
+ self.assertIsNone(item.compliance_result)
238
+
239
+ def test_case_sensitivity_failed(self):
240
+ """Test that complianceCheck is case-sensitive (FAILED vs failed)."""
241
+ evidence = [
242
+ {"complianceCheck": "failed", "dataSource": "AWS Security Hub"}, # lowercase
243
+ ]
244
+
245
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
246
+ # Lowercase "failed" should NOT match "FAILED", treated as inconclusive
247
+ self.assertIsNone(item.compliance_result)
248
+
249
+ def test_empty_string_compliance_check(self):
250
+ """Test that empty string complianceCheck is treated as inconclusive."""
251
+ evidence = [
252
+ {"complianceCheck": "", "dataSource": "AWS Config"},
253
+ ]
254
+
255
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
256
+ self.assertIsNone(item.compliance_result)
257
+
258
+ def test_whitespace_compliance_check(self):
259
+ """Test that whitespace-only complianceCheck is treated as inconclusive."""
260
+ evidence = [
261
+ {"complianceCheck": " ", "dataSource": "AWS Config"},
262
+ ]
263
+
264
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
265
+ self.assertIsNone(item.compliance_result)
266
+
267
+ def test_unexpected_compliance_check_value(self):
268
+ """Test that unexpected values are treated as inconclusive."""
269
+ evidence = [
270
+ {"complianceCheck": "UNKNOWN", "dataSource": "AWS Config"},
271
+ {"complianceCheck": "PENDING", "dataSource": "AWS Config"},
272
+ {"complianceCheck": 123, "dataSource": "AWS Config"}, # Number instead of string
273
+ ]
274
+
275
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
276
+ self.assertIsNone(item.compliance_result)
277
+
278
+ def test_large_number_of_evidence_items(self):
279
+ """Test aggregation with large number of evidence items."""
280
+ # Create 1000 evidence items
281
+ evidence = [{"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"} for _ in range(1000)]
282
+
283
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
284
+ self.assertEqual(item.compliance_result, "PASS")
285
+
286
+ def test_large_number_with_one_failure(self):
287
+ """Test that one failure in many evidence items still causes FAIL."""
288
+ evidence = [{"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"} for _ in range(999)]
289
+ evidence.append({"complianceCheck": "FAILED", "dataSource": "AWS Security Hub"}) # One failure
290
+
291
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
292
+ self.assertEqual(item.compliance_result, "FAIL")
293
+
294
+
295
+ class TestComplianceItemCreation(unittest.TestCase):
296
+ """Test creating compliance items with evidence."""
297
+
298
+ def setUp(self):
299
+ """Set up test fixtures."""
300
+ self.assessment_data = {
301
+ "name": "Test Assessment",
302
+ "arn": "arn:aws:auditmanager:us-east-1:123456789012:assessment/test",
303
+ "framework": {"type": "Standard", "metadata": {"name": "NIST 800-53"}},
304
+ "awsAccount": {"id": "123456789012"},
305
+ }
306
+
307
+ self.control_data = {
308
+ "id": "test-id",
309
+ "name": "AC-2 - Account Management",
310
+ "status": "REVIEWED",
311
+ }
312
+
313
+ def test_create_with_evidence(self):
314
+ """Test creating compliance item with evidence."""
315
+ evidence = [{"complianceCheck": "COMPLIANT", "dataSource": "AWS Config"}]
316
+
317
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, evidence)
318
+
319
+ self.assertEqual(item.control_id, "AC-2")
320
+ self.assertEqual(len(item.evidence_items), 1)
321
+ self.assertEqual(item.compliance_result, "PASS")
322
+
323
+ def test_create_without_evidence(self):
324
+ """Test creating compliance item without evidence (backward compatibility)."""
325
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data)
326
+
327
+ self.assertEqual(item.control_id, "AC-2")
328
+ self.assertEqual(len(item.evidence_items), 0)
329
+ self.assertIsNone(item.compliance_result) # No evidence = None (skip update)
330
+
331
+ def test_create_with_explicit_none_evidence(self):
332
+ """Test creating compliance item with explicit None evidence."""
333
+ item = AWSAuditManagerComplianceItem(self.assessment_data, self.control_data, None)
334
+
335
+ self.assertEqual(item.control_id, "AC-2")
336
+ self.assertEqual(len(item.evidence_items), 0)
337
+ self.assertIsNone(item.compliance_result) # No evidence = None (skip update)
338
+
339
+
340
+ if __name__ == "__main__":
341
+ unittest.main()