regscale-cli 6.26.0.0__py3-none-any.whl → 6.27.0.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.
- regscale/_version.py +1 -1
- regscale/core/app/application.py +1 -1
- regscale/core/app/internal/evidence.py +419 -2
- regscale/dev/code_gen.py +24 -20
- regscale/integrations/commercial/jira.py +367 -126
- regscale/integrations/commercial/qualys/__init__.py +7 -8
- regscale/integrations/commercial/qualys/scanner.py +8 -3
- regscale/integrations/commercial/synqly/assets.py +17 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +45 -28
- regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
- regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
- regscale/integrations/commercial/tenablev2/commands.py +142 -1
- regscale/integrations/commercial/tenablev2/scanner.py +0 -1
- regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
- regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +44 -59
- regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
- regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
- regscale/integrations/commercial/wizv2/compliance_report.py +10 -9
- regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
- regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +3 -3
- regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +1 -17
- regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
- regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +5 -9
- regscale/integrations/commercial/wizv2/issue.py +1 -1
- regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
- regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
- regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
- regscale/integrations/commercial/wizv2/reports.py +1 -1
- regscale/integrations/commercial/wizv2/sbom.py +1 -1
- regscale/integrations/commercial/wizv2/scanner.py +40 -100
- regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
- regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
- regscale/integrations/commercial/wizv2/variables.py +89 -3
- regscale/integrations/compliance_integration.py +0 -46
- regscale/integrations/control_matcher.py +22 -3
- regscale/integrations/due_date_handler.py +14 -8
- regscale/integrations/public/fedramp/docx_parser.py +10 -1
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +393 -340
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/scanner_integration.py +127 -57
- regscale/models/integration_models/cisa_kev_data.json +132 -9
- regscale/models/integration_models/qualys.py +3 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +24 -7
- regscale/models/integration_models/synqly_models/synqly_model.py +8 -1
- regscale/models/regscale_models/control_implementation.py +1 -1
- regscale/models/regscale_models/issue.py +0 -1
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.0.dist-info}/METADATA +1 -17
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.0.dist-info}/RECORD +93 -60
- tests/regscale/integrations/commercial/test_jira.py +481 -91
- tests/regscale/integrations/commercial/test_wiz.py +96 -200
- tests/regscale/integrations/commercial/wizv2/__init__.py +1 -1
- tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
- tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
- tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
- tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
- tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
- tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
- tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
- tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
- tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
- tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +1 -1
- tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
- tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
- tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
- tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +1 -1
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +72 -29
- tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +946 -78
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +97 -202
- tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
- tests/regscale/integrations/public/test_fedramp.py +301 -0
- tests/regscale/integrations/test_control_matcher.py +83 -0
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3543
- tests/regscale/integrations/commercial/wizv2/test_wiz_policy_compliance.py +0 -750
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.0.dist-info}/top_level.txt +0 -0
|
@@ -93,7 +93,7 @@ class TestWizClientIdHandling:
|
|
|
93
93
|
@pytest.fixture
|
|
94
94
|
def mock_wiz_auth(self):
|
|
95
95
|
"""Mock wiz_authenticate."""
|
|
96
|
-
with patch("regscale.integrations.commercial.wizv2.
|
|
96
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock:
|
|
97
97
|
yield mock
|
|
98
98
|
|
|
99
99
|
@pytest.fixture
|
|
@@ -481,6 +481,7 @@ class TestWizComplianceReportItem(unittest.TestCase):
|
|
|
481
481
|
|
|
482
482
|
|
|
483
483
|
@pytest.mark.no_parallel
|
|
484
|
+
@patch("regscale.integrations.compliance_integration.ComplianceIntegration.__init__", return_value=None)
|
|
484
485
|
class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
485
486
|
"""Test suite for WizComplianceReportProcessor class."""
|
|
486
487
|
|
|
@@ -527,9 +528,21 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
527
528
|
},
|
|
528
529
|
]
|
|
529
530
|
|
|
531
|
+
def _initialize_processor_attributes(self, processor):
|
|
532
|
+
"""Initialize parent class attributes that would normally be set by __init__."""
|
|
533
|
+
from collections import defaultdict
|
|
534
|
+
|
|
535
|
+
processor.all_compliance_items = []
|
|
536
|
+
processor.failed_compliance_items = []
|
|
537
|
+
processor.passing_controls = {}
|
|
538
|
+
processor.failing_controls = {}
|
|
539
|
+
processor.asset_compliance_map = defaultdict(list)
|
|
540
|
+
processor.plan_id = self.plan_id
|
|
541
|
+
processor.title = "Wiz Compliance"
|
|
542
|
+
|
|
530
543
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager")
|
|
531
544
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate")
|
|
532
|
-
def test_init_successful_authentication(self, mock_auth, mock_report_manager):
|
|
545
|
+
def test_init_successful_authentication(self, mock_auth, mock_report_manager, mock_parent_init):
|
|
533
546
|
"""Test successful initialization with authentication."""
|
|
534
547
|
mock_auth.return_value = "test-token"
|
|
535
548
|
mock_report_manager_instance = MagicMock()
|
|
@@ -541,6 +554,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
541
554
|
client_id=self.client_id,
|
|
542
555
|
client_secret=self.client_secret,
|
|
543
556
|
)
|
|
557
|
+
self._initialize_processor_attributes(processor)
|
|
544
558
|
|
|
545
559
|
mock_auth.assert_called_once_with(self.client_id, self.client_secret)
|
|
546
560
|
mock_report_manager.assert_called_once()
|
|
@@ -551,7 +565,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
551
565
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager")
|
|
552
566
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate")
|
|
553
567
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.error_and_exit")
|
|
554
|
-
def test_init_failed_authentication(self, mock_error_exit, mock_auth, mock_report_manager):
|
|
568
|
+
def test_init_failed_authentication(self, mock_error_exit, mock_auth, mock_report_manager, mock_parent_init):
|
|
555
569
|
"""Test initialization with failed authentication."""
|
|
556
570
|
mock_auth.return_value = None
|
|
557
571
|
mock_error_exit.side_effect = SystemExit(1)
|
|
@@ -566,7 +580,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
566
580
|
|
|
567
581
|
mock_error_exit.assert_called_once_with("Failed to authenticate with Wiz")
|
|
568
582
|
|
|
569
|
-
def test_parse_csv_report_regular_file(self):
|
|
583
|
+
def test_parse_csv_report_regular_file(self, mock_parent_init):
|
|
570
584
|
"""Test parse_csv_report with regular CSV file."""
|
|
571
585
|
# Create temporary CSV file
|
|
572
586
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) as temp_file:
|
|
@@ -599,7 +613,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
599
613
|
finally:
|
|
600
614
|
os.unlink(temp_file_path)
|
|
601
615
|
|
|
602
|
-
def test_parse_csv_report_gzipped_file(self):
|
|
616
|
+
def test_parse_csv_report_gzipped_file(self, mock_parent_init):
|
|
603
617
|
"""Test parse_csv_report with gzipped CSV file."""
|
|
604
618
|
# Create temporary gzipped CSV file
|
|
605
619
|
with tempfile.NamedTemporaryFile(suffix=".csv.gz", delete=False) as temp_file:
|
|
@@ -631,7 +645,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
631
645
|
finally:
|
|
632
646
|
os.unlink(temp_file_path)
|
|
633
647
|
|
|
634
|
-
def test_parse_csv_report_file_not_found(self):
|
|
648
|
+
def test_parse_csv_report_file_not_found(self, mock_parent_init):
|
|
635
649
|
"""Test parse_csv_report with non-existent file."""
|
|
636
650
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
637
651
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -647,7 +661,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
647
661
|
|
|
648
662
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager")
|
|
649
663
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate")
|
|
650
|
-
def test_fetch_compliance_data_with_existing_report(self, mock_auth, mock_report_manager):
|
|
664
|
+
def test_fetch_compliance_data_with_existing_report(self, mock_auth, mock_report_manager, mock_parent_init):
|
|
651
665
|
"""Test fetch_compliance_data with existing report file."""
|
|
652
666
|
mock_auth.return_value = "test-token"
|
|
653
667
|
|
|
@@ -678,7 +692,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
678
692
|
|
|
679
693
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager")
|
|
680
694
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate")
|
|
681
|
-
def test_fetch_compliance_data_report_creation(self, mock_auth, mock_report_manager):
|
|
695
|
+
def test_fetch_compliance_data_report_creation(self, mock_auth, mock_report_manager, mock_parent_init):
|
|
682
696
|
"""Test fetch_compliance_data creates new report when none exists."""
|
|
683
697
|
mock_auth.return_value = "test-token"
|
|
684
698
|
|
|
@@ -706,7 +720,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
706
720
|
finally:
|
|
707
721
|
os.unlink(temp_file_path)
|
|
708
722
|
|
|
709
|
-
def test_fetch_compliance_data_file_read_error(self):
|
|
723
|
+
def test_fetch_compliance_data_file_read_error(self, mock_parent_init):
|
|
710
724
|
"""Test fetch_compliance_data handles file read errors."""
|
|
711
725
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
712
726
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -723,7 +737,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
723
737
|
raw_data = processor.fetch_compliance_data()
|
|
724
738
|
self.assertEqual(len(raw_data), 0)
|
|
725
739
|
|
|
726
|
-
def test_create_compliance_item(self):
|
|
740
|
+
def test_create_compliance_item(self, mock_parent_init):
|
|
727
741
|
"""Test create_compliance_item creates WizComplianceReportItem."""
|
|
728
742
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
729
743
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -740,7 +754,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
740
754
|
|
|
741
755
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager")
|
|
742
756
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate")
|
|
743
|
-
def test_process_compliance_data_bypass_filtering(self, mock_auth, mock_report_manager):
|
|
757
|
+
def test_process_compliance_data_bypass_filtering(self, mock_auth, mock_report_manager, mock_parent_init):
|
|
744
758
|
"""Test process_compliance_data with bypass_control_filtering=True."""
|
|
745
759
|
mock_auth.return_value = "test-token"
|
|
746
760
|
|
|
@@ -758,7 +772,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
758
772
|
|
|
759
773
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager")
|
|
760
774
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate")
|
|
761
|
-
def test_process_compliance_data_normal_filtering(self, mock_auth, mock_report_manager):
|
|
775
|
+
def test_process_compliance_data_normal_filtering(self, mock_auth, mock_report_manager, mock_parent_init):
|
|
762
776
|
"""Test process_compliance_data with normal filtering."""
|
|
763
777
|
mock_auth.return_value = "test-token"
|
|
764
778
|
|
|
@@ -775,7 +789,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
775
789
|
processor.process_compliance_data()
|
|
776
790
|
mock_parent.assert_called_once()
|
|
777
791
|
|
|
778
|
-
def test_process_compliance_data_without_filtering_categorization(self):
|
|
792
|
+
def test_process_compliance_data_without_filtering_categorization(self, mock_parent_init):
|
|
779
793
|
"""Test _process_compliance_data_without_filtering categorizes controls correctly."""
|
|
780
794
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
781
795
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -785,6 +799,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
785
799
|
client_id=self.client_id,
|
|
786
800
|
client_secret=self.client_secret,
|
|
787
801
|
)
|
|
802
|
+
self._initialize_processor_attributes(processor)
|
|
788
803
|
|
|
789
804
|
# Mock fetch_compliance_data to return our test data
|
|
790
805
|
with patch.object(processor, "fetch_compliance_data", return_value=self.sample_csv_data):
|
|
@@ -798,7 +813,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
798
813
|
# Should call fail-first categorization
|
|
799
814
|
mock_categorize.assert_called_once()
|
|
800
815
|
|
|
801
|
-
def test_process_compliance_sync(self):
|
|
816
|
+
def test_process_compliance_sync(self, mock_parent_init):
|
|
802
817
|
"""Test process_compliance_sync calls sync_compliance."""
|
|
803
818
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
804
819
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -813,7 +828,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
813
828
|
processor.process_compliance_sync()
|
|
814
829
|
mock_sync.assert_called_once()
|
|
815
830
|
|
|
816
|
-
def test_get_or_create_report_existing_recent_report(self):
|
|
831
|
+
def test_get_or_create_report_existing_recent_report(self, mock_parent_init):
|
|
817
832
|
"""Test _get_or_create_report uses existing recent report."""
|
|
818
833
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
819
834
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -828,7 +843,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
828
843
|
result = processor._get_or_create_report()
|
|
829
844
|
self.assertEqual(result, "existing_report.csv")
|
|
830
845
|
|
|
831
|
-
def test_get_or_create_report_creates_new_report(self):
|
|
846
|
+
def test_get_or_create_report_creates_new_report(self, mock_parent_init):
|
|
832
847
|
"""Test _get_or_create_report creates new report when none exists."""
|
|
833
848
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
834
849
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -844,7 +859,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
844
859
|
result = processor._get_or_create_report()
|
|
845
860
|
self.assertEqual(result, "new_report.csv")
|
|
846
861
|
|
|
847
|
-
def test_find_recent_report_no_artifacts_dir(self):
|
|
862
|
+
def test_find_recent_report_no_artifacts_dir(self, mock_parent_init):
|
|
848
863
|
"""Test _find_recent_report returns None when artifacts directory doesn't exist."""
|
|
849
864
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
850
865
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -859,7 +874,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
859
874
|
result = processor._find_recent_report()
|
|
860
875
|
self.assertIsNone(result)
|
|
861
876
|
|
|
862
|
-
def test_find_recent_report_finds_recent_file(self):
|
|
877
|
+
def test_find_recent_report_finds_recent_file(self, mock_parent_init):
|
|
863
878
|
"""Test _find_recent_report finds and returns recent file."""
|
|
864
879
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
865
880
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -880,7 +895,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
880
895
|
expected_path = f"artifacts/wiz/{expected_filename}"
|
|
881
896
|
self.assertEqual(result, expected_path)
|
|
882
897
|
|
|
883
|
-
def test_find_recent_report_ignores_old_files(self):
|
|
898
|
+
def test_find_recent_report_ignores_old_files(self, mock_parent_init):
|
|
884
899
|
"""Test _find_recent_report ignores files older than max_age_hours."""
|
|
885
900
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
886
901
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.WizReportManager"):
|
|
@@ -903,7 +918,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
903
918
|
|
|
904
919
|
@patch("regscale.integrations.commercial.wizv2.compliance_report.ReportFileCleanup")
|
|
905
920
|
@patch("os.makedirs")
|
|
906
|
-
def test_create_and_download_report_success(self, mock_makedirs, mock_cleanup):
|
|
921
|
+
def test_create_and_download_report_success(self, mock_makedirs, mock_cleanup, mock_parent_init):
|
|
907
922
|
"""Test _create_and_download_report successful report creation."""
|
|
908
923
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
909
924
|
mock_report_manager = MagicMock()
|
|
@@ -931,7 +946,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
931
946
|
mock_makedirs.assert_called_once()
|
|
932
947
|
mock_cleanup.cleanup_old_files.assert_called_once()
|
|
933
948
|
|
|
934
|
-
def test_create_and_download_report_creation_failure(self):
|
|
949
|
+
def test_create_and_download_report_creation_failure(self, mock_parent_init):
|
|
935
950
|
"""Test _create_and_download_report handles report creation failure."""
|
|
936
951
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
937
952
|
mock_report_manager = MagicMock()
|
|
@@ -952,7 +967,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
952
967
|
result = processor._create_and_download_report()
|
|
953
968
|
self.assertIsNone(result)
|
|
954
969
|
|
|
955
|
-
def test_create_and_download_report_download_failure(self):
|
|
970
|
+
def test_create_and_download_report_download_failure(self, mock_parent_init):
|
|
956
971
|
"""Test _create_and_download_report handles download failure."""
|
|
957
972
|
with patch("regscale.integrations.commercial.wizv2.compliance_report.wiz_authenticate", return_value="token"):
|
|
958
973
|
mock_report_manager = MagicMock()
|
|
@@ -978,6 +993,7 @@ class TestWizComplianceReportProcessor(unittest.TestCase):
|
|
|
978
993
|
|
|
979
994
|
|
|
980
995
|
@pytest.mark.no_parallel
|
|
996
|
+
@patch("regscale.integrations.compliance_integration.ComplianceIntegration.__init__", return_value=None)
|
|
981
997
|
class TestWizComplianceStatusMatching(unittest.TestCase):
|
|
982
998
|
"""Test suite for status matching and case-insensitive logic."""
|
|
983
999
|
|
|
@@ -1000,7 +1016,17 @@ class TestWizComplianceStatusMatching(unittest.TestCase):
|
|
|
1000
1016
|
"Remediation Steps": "Fix this",
|
|
1001
1017
|
}
|
|
1002
1018
|
|
|
1003
|
-
def
|
|
1019
|
+
def _initialize_processor_attributes(self, processor):
|
|
1020
|
+
"""Initialize parent class attributes that would normally be set by __init__."""
|
|
1021
|
+
from collections import defaultdict
|
|
1022
|
+
|
|
1023
|
+
processor.all_compliance_items = []
|
|
1024
|
+
processor.failed_compliance_items = []
|
|
1025
|
+
processor.passing_controls = {}
|
|
1026
|
+
processor.failing_controls = {}
|
|
1027
|
+
processor.asset_compliance_map = defaultdict(list)
|
|
1028
|
+
|
|
1029
|
+
def test_pass_status_matching_case_insensitive(self, mock_parent_init):
|
|
1004
1030
|
"""Test that pass statuses are matched case-insensitively."""
|
|
1005
1031
|
# Current implementation supports: Pass, PASS, pass but not Passed, PASSED, passed
|
|
1006
1032
|
pass_values = ["Pass", "PASS", "pass"]
|
|
@@ -1025,7 +1051,7 @@ class TestWizComplianceStatusMatching(unittest.TestCase):
|
|
|
1025
1051
|
self.assertEqual(item.get_status(), "Other Than Satisfied")
|
|
1026
1052
|
self.assertEqual(item.get_implementation_status(), "In Remediation")
|
|
1027
1053
|
|
|
1028
|
-
def test_fail_status_matching_case_insensitive(self):
|
|
1054
|
+
def test_fail_status_matching_case_insensitive(self, mock_parent_init):
|
|
1029
1055
|
"""Test that fail statuses are matched case-insensitively."""
|
|
1030
1056
|
fail_values = ["Fail", "FAIL", "fail", "Failed", "FAILED", "failed"]
|
|
1031
1057
|
|
|
@@ -1037,7 +1063,7 @@ class TestWizComplianceStatusMatching(unittest.TestCase):
|
|
|
1037
1063
|
self.assertEqual(item.get_status(), "Other Than Satisfied")
|
|
1038
1064
|
self.assertEqual(item.get_implementation_status(), "In Remediation")
|
|
1039
1065
|
|
|
1040
|
-
def test_status_categorization_in_processor(self):
|
|
1066
|
+
def test_status_categorization_in_processor(self, mock_parent_init):
|
|
1041
1067
|
"""Test that WizComplianceReportProcessor correctly categorizes statuses."""
|
|
1042
1068
|
# Test data with mixed case statuses
|
|
1043
1069
|
test_data = [
|
|
@@ -1058,6 +1084,7 @@ class TestWizComplianceStatusMatching(unittest.TestCase):
|
|
|
1058
1084
|
client_secret="secret",
|
|
1059
1085
|
bypass_control_filtering=False, # Use threshold-based logic
|
|
1060
1086
|
)
|
|
1087
|
+
self._initialize_processor_attributes(processor)
|
|
1061
1088
|
|
|
1062
1089
|
# Mock fetch_compliance_data to return test data
|
|
1063
1090
|
with patch.object(processor, "fetch_compliance_data", return_value=test_data):
|
|
@@ -1074,10 +1101,21 @@ class TestWizComplianceStatusMatching(unittest.TestCase):
|
|
|
1074
1101
|
|
|
1075
1102
|
|
|
1076
1103
|
@pytest.mark.no_parallel
|
|
1104
|
+
@patch("regscale.integrations.compliance_integration.ComplianceIntegration.__init__", return_value=None)
|
|
1077
1105
|
class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
1078
1106
|
"""Test suite for control categorization and aggregation logic."""
|
|
1079
1107
|
|
|
1080
|
-
def
|
|
1108
|
+
def _initialize_processor_attributes(self, processor):
|
|
1109
|
+
"""Initialize parent class attributes that would normally be set by __init__."""
|
|
1110
|
+
from collections import defaultdict
|
|
1111
|
+
|
|
1112
|
+
processor.all_compliance_items = []
|
|
1113
|
+
processor.failed_compliance_items = []
|
|
1114
|
+
processor.passing_controls = {}
|
|
1115
|
+
processor.failing_controls = {}
|
|
1116
|
+
processor.asset_compliance_map = defaultdict(list)
|
|
1117
|
+
|
|
1118
|
+
def test_control_categorization_all_pass(self, mock_parent_init):
|
|
1081
1119
|
"""Test control categorization when all items pass."""
|
|
1082
1120
|
test_data = [
|
|
1083
1121
|
{
|
|
@@ -1109,6 +1147,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1109
1147
|
client_secret="secret",
|
|
1110
1148
|
bypass_control_filtering=False, # Use threshold-based logic
|
|
1111
1149
|
)
|
|
1150
|
+
self._initialize_processor_attributes(processor)
|
|
1112
1151
|
|
|
1113
1152
|
# Fill in required fields for test data
|
|
1114
1153
|
full_test_data = []
|
|
@@ -1139,7 +1178,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1139
1178
|
self.assertEqual(len(processor.failing_controls), 0)
|
|
1140
1179
|
self.assertIn("ac-2(1)", processor.passing_controls)
|
|
1141
1180
|
|
|
1142
|
-
def test_control_categorization_all_fail(self):
|
|
1181
|
+
def test_control_categorization_all_fail(self, mock_parent_init):
|
|
1143
1182
|
"""Test control categorization when all items fail."""
|
|
1144
1183
|
test_data = [
|
|
1145
1184
|
{
|
|
@@ -1171,6 +1210,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1171
1210
|
client_secret="secret",
|
|
1172
1211
|
bypass_control_filtering=False, # Use threshold-based logic
|
|
1173
1212
|
)
|
|
1213
|
+
self._initialize_processor_attributes(processor)
|
|
1174
1214
|
|
|
1175
1215
|
# Fill in required fields for test data
|
|
1176
1216
|
full_test_data = []
|
|
@@ -1201,7 +1241,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1201
1241
|
self.assertEqual(len(processor.failing_controls), 1)
|
|
1202
1242
|
self.assertIn("ac-3", processor.failing_controls)
|
|
1203
1243
|
|
|
1204
|
-
def test_control_categorization_mixed_results_high_failure_rate(self):
|
|
1244
|
+
def test_control_categorization_mixed_results_high_failure_rate(self, mock_parent_init):
|
|
1205
1245
|
"""Test control categorization with mixed results above failure threshold."""
|
|
1206
1246
|
# 5 items: 2 pass, 3 fail = 60% failure rate (above default 20% threshold)
|
|
1207
1247
|
test_data = [
|
|
@@ -1221,6 +1261,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1221
1261
|
client_secret="secret",
|
|
1222
1262
|
bypass_control_filtering=False, # Use threshold-based logic
|
|
1223
1263
|
)
|
|
1264
|
+
self._initialize_processor_attributes(processor)
|
|
1224
1265
|
|
|
1225
1266
|
# Fill in required fields - all same control
|
|
1226
1267
|
full_test_data = []
|
|
@@ -1251,7 +1292,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1251
1292
|
self.assertEqual(len(processor.failing_controls), 1)
|
|
1252
1293
|
self.assertIn("ac-4", processor.failing_controls)
|
|
1253
1294
|
|
|
1254
|
-
def test_control_categorization_mixed_results_fail_first(self):
|
|
1295
|
+
def test_control_categorization_mixed_results_fail_first(self, mock_parent_init):
|
|
1255
1296
|
"""Test control categorization with mixed results using fail-first logic."""
|
|
1256
1297
|
# 10 items: 9 pass, 1 fail - with fail-first logic, any failure makes the control fail
|
|
1257
1298
|
test_data = []
|
|
@@ -1268,6 +1309,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1268
1309
|
client_secret="secret",
|
|
1269
1310
|
bypass_control_filtering=False,
|
|
1270
1311
|
)
|
|
1312
|
+
self._initialize_processor_attributes(processor)
|
|
1271
1313
|
|
|
1272
1314
|
# Fill in required fields - all same control
|
|
1273
1315
|
full_test_data = []
|
|
@@ -1298,7 +1340,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1298
1340
|
self.assertEqual(len(processor.failing_controls), 1)
|
|
1299
1341
|
self.assertIn("si-2", processor.failing_controls)
|
|
1300
1342
|
|
|
1301
|
-
def test_control_categorization_fail_first_logic(self):
|
|
1343
|
+
def test_control_categorization_fail_first_logic(self, mock_parent_init):
|
|
1302
1344
|
"""Test that Wiz compliance uses fail-first logic regardless of bypass_control_filtering setting."""
|
|
1303
1345
|
# 10 items: 7 pass, 3 fail - with fail-first logic, this should be a failing control
|
|
1304
1346
|
test_data = []
|
|
@@ -1316,6 +1358,7 @@ class TestWizComplianceControlCategorization(unittest.TestCase):
|
|
|
1316
1358
|
client_secret="secret",
|
|
1317
1359
|
bypass_control_filtering=False,
|
|
1318
1360
|
)
|
|
1361
|
+
self._initialize_processor_attributes(processor)
|
|
1319
1362
|
|
|
1320
1363
|
# Fill in required fields - all same control
|
|
1321
1364
|
full_test_data = []
|