regscale-cli 6.25.1.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/airflow/hierarchy.py +2 -2
- regscale/core/app/application.py +19 -4
- regscale/core/app/internal/evidence.py +419 -2
- regscale/core/app/internal/login.py +0 -1
- regscale/core/app/utils/catalog_utils/common.py +1 -1
- 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/sicura/api.py +14 -13
- regscale/integrations/commercial/sicura/commands.py +8 -2
- regscale/integrations/commercial/sicura/scanner.py +49 -39
- regscale/integrations/commercial/stigv2/ckl_parser.py +5 -5
- 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 +64 -79
- 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 +161 -165
- 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 +39 -99
- 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 +60 -41
- regscale/integrations/control_matcher.py +377 -0
- regscale/integrations/due_date_handler.py +14 -8
- regscale/integrations/milestone_manager.py +291 -0
- regscale/integrations/public/__init__.py +1 -0
- regscale/integrations/public/cci_importer.py +37 -38
- regscale/integrations/public/fedramp/click.py +60 -2
- 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/public/fedramp/poam_export_v5.py +888 -0
- regscale/integrations/scanner_integration.py +277 -153
- regscale/models/integration_models/cisa_kev_data.json +282 -9
- regscale/models/integration_models/nexpose.py +36 -10
- 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/locking.py +12 -8
- regscale/models/platform.py +1 -2
- regscale/models/regscale_models/control_implementation.py +47 -22
- regscale/models/regscale_models/issue.py +256 -95
- regscale/models/regscale_models/milestone.py +1 -1
- regscale/models/regscale_models/regscale_model.py +6 -1
- regscale/templates/__init__.py +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.27.0.0.dist-info}/METADATA +1 -17
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.27.0.0.dist-info}/RECORD +145 -65
- tests/regscale/integrations/commercial/__init__.py +0 -0
- tests/regscale/integrations/commercial/conftest.py +28 -0
- tests/regscale/integrations/commercial/microsoft_defender/__init__.py +1 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender.py +1517 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_api.py +1748 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_constants.py +327 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_scanner.py +487 -0
- tests/regscale/integrations/commercial/test_aws.py +3731 -0
- tests/regscale/integrations/commercial/test_burp.py +48 -0
- tests/regscale/integrations/commercial/test_crowdstrike.py +49 -0
- tests/regscale/integrations/commercial/test_dependabot.py +341 -0
- tests/regscale/integrations/commercial/test_gcp.py +1543 -0
- tests/regscale/integrations/commercial/test_gitlab.py +549 -0
- tests/regscale/integrations/commercial/test_ip_mac_address_length.py +84 -0
- tests/regscale/integrations/commercial/test_jira.py +2204 -0
- tests/regscale/integrations/commercial/test_npm_audit.py +42 -0
- tests/regscale/integrations/commercial/test_okta.py +1228 -0
- tests/regscale/integrations/commercial/test_sarif_converter.py +251 -0
- tests/regscale/integrations/commercial/test_sicura.py +350 -0
- tests/regscale/integrations/commercial/test_snow.py +423 -0
- tests/regscale/integrations/commercial/test_sonarcloud.py +394 -0
- tests/regscale/integrations/commercial/test_sqlserver.py +186 -0
- tests/regscale/integrations/commercial/test_stig.py +33 -0
- tests/regscale/integrations/commercial/test_stig_mapper.py +153 -0
- tests/regscale/integrations/commercial/test_stigv2.py +406 -0
- tests/regscale/integrations/commercial/test_wiz.py +1365 -0
- tests/regscale/integrations/commercial/test_wiz_inventory.py +256 -0
- tests/regscale/integrations/commercial/wizv2/__init__.py +339 -0
- 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_compliance_report_normalization.py +138 -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 +343 -0
- 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 +165 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +1394 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_unit.py +341 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py +138 -0
- 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_wiz_status_mapping.py +149 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +1132 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +519 -0
- 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/fedramp/__init__.py +1 -0
- tests/regscale/integrations/public/fedramp/test_poam_export_v5.py +1293 -0
- tests/regscale/integrations/public/test_fedramp.py +301 -0
- tests/regscale/integrations/test_control_matcher.py +1397 -0
- tests/regscale/integrations/test_control_matching.py +155 -0
- tests/regscale/integrations/test_milestone_manager.py +408 -0
- tests/regscale/models/test_issue.py +378 -1
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3543
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.27.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.27.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.27.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.27.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Test for Burp scan integration in RegScale CLI"""
|
|
4
|
+
import shutil
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from regscale.integrations.commercial.burp import import_burp_scan
|
|
9
|
+
from regscale.models.regscale_models.scan_history import ScanHistory
|
|
10
|
+
from tests import CLITestFixture
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestBurpIntegration(CLITestFixture):
|
|
14
|
+
"""Test the Burp integration"""
|
|
15
|
+
|
|
16
|
+
@pytest.fixture(autouse=True)
|
|
17
|
+
def setup_ssp(self, create_security_plan):
|
|
18
|
+
self.security_plan = create_security_plan
|
|
19
|
+
|
|
20
|
+
def test_burp_integration(self, test_data_dir):
|
|
21
|
+
"""Test the Burp integration"""
|
|
22
|
+
burp_scan_file = test_data_dir / "burp-scan.xml"
|
|
23
|
+
assert burp_scan_file.exists(), "Test data file not found"
|
|
24
|
+
processed_files = []
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
current_datetime = datetime.now().strftime("%Y-%m-%d")
|
|
28
|
+
security_plan = self.security_plan
|
|
29
|
+
|
|
30
|
+
import_burp_scan(test_data_dir, security_plan.id, current_datetime, True)
|
|
31
|
+
scan_history = ScanHistory.get_all_by_parent(security_plan.id, security_plan.get_module_string())[0]
|
|
32
|
+
|
|
33
|
+
# Verify file was processed and moved
|
|
34
|
+
processed_dir = burp_scan_file.parent / "processed"
|
|
35
|
+
assert processed_dir.exists()
|
|
36
|
+
processed_files = list(processed_dir.glob("*.xml"))
|
|
37
|
+
assert len(processed_files) > 0, "No processed files found"
|
|
38
|
+
|
|
39
|
+
assert scan_history.vInfo == 1
|
|
40
|
+
assert scan_history.vLow == 3
|
|
41
|
+
assert scan_history.vMedium == 0
|
|
42
|
+
assert scan_history.vHigh == 0
|
|
43
|
+
assert scan_history.vCritical == 0
|
|
44
|
+
|
|
45
|
+
finally:
|
|
46
|
+
for file in processed_files:
|
|
47
|
+
if "burp" in file.name:
|
|
48
|
+
shutil.move(file, test_data_dir / "burp-scan.xml")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for the CrowdStrike integration"""
|
|
4
|
+
from falconpy import OAuth2
|
|
5
|
+
|
|
6
|
+
from regscale.integrations.commercial.crowdstrike import (
|
|
7
|
+
incident_information,
|
|
8
|
+
open_sdk,
|
|
9
|
+
status_information,
|
|
10
|
+
)
|
|
11
|
+
from tests import CLITestFixture
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestCrowdstring(CLITestFixture):
|
|
15
|
+
"""
|
|
16
|
+
Test for CrowdStrike integration
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
AllowedResponses = [200, 401, 403, 429]
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def test_bad_creds():
|
|
23
|
+
"""Test bad credentials"""
|
|
24
|
+
bad_falcon = OAuth2()
|
|
25
|
+
result = bad_falcon.revoke("Will generate a 403")
|
|
26
|
+
assert result["status_code"] == 403
|
|
27
|
+
|
|
28
|
+
def test_incidents(self):
|
|
29
|
+
"""Test incidents"""
|
|
30
|
+
assert open_sdk().QueryIncidents(parameters={"limit": 1})["status_code"] in self.AllowedResponses
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def test_status_information():
|
|
34
|
+
inc_data = {"status": 30, "tags": ["tag1", "tag2"]}
|
|
35
|
+
expected_output = "[deep_sky_blue1]InProgress[/]\n \n[magenta]tag1[/]\n[magenta]tag2[/]"
|
|
36
|
+
assert status_information(inc_data) == expected_output
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def test_incident_information():
|
|
40
|
+
inc_data = {
|
|
41
|
+
"name": "Test Incident",
|
|
42
|
+
"incident_id": "12345:67890:ABCDE",
|
|
43
|
+
"start": "2022-01-01T00:00:00Z",
|
|
44
|
+
"end": "2022-01-02T00:00:00Z",
|
|
45
|
+
"assigned_to": None,
|
|
46
|
+
"description": "This is a test incident description.",
|
|
47
|
+
}
|
|
48
|
+
expected_output = "Test Incident\n[bold]ABCDE[/]\nStart: 2022-01-01 00:00:00Z\n End: 2022-01-02 00:00:00Z\n \nThis is a test incident description. "
|
|
49
|
+
assert incident_information(inc_data) == expected_output
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Test for dependabot alerts integration in RegScale CLI
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
import requests
|
|
11
|
+
from unittest.mock import MagicMock, patch
|
|
12
|
+
|
|
13
|
+
from tests import CLITestFixture
|
|
14
|
+
from regscale.integrations.commercial.dependabot import (
|
|
15
|
+
get_github_dependabot_alerts,
|
|
16
|
+
build_data,
|
|
17
|
+
build_dataframes,
|
|
18
|
+
create_alert_assessment,
|
|
19
|
+
create_alert_issues,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TestDependabot(CLITestFixture):
|
|
24
|
+
"""
|
|
25
|
+
Test for dependabot integration
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def sample_dependabot_data(self):
|
|
30
|
+
"""Fixture providing sample dependabot data for multiple tests"""
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
"number": [1],
|
|
34
|
+
"state": ["open"],
|
|
35
|
+
"summary": ["Critical vulnerability in test-package-1"],
|
|
36
|
+
"ecosystem": ["npm"],
|
|
37
|
+
"name": ["test-package-1"],
|
|
38
|
+
"severity": ["high"],
|
|
39
|
+
"published": ["2021-01-01T00:00:00Z"],
|
|
40
|
+
"days_elapsed": [5],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"number": [2],
|
|
44
|
+
"state": ["open"],
|
|
45
|
+
"summary": ["Medium severity issue in another-package"],
|
|
46
|
+
"ecosystem": ["pip"],
|
|
47
|
+
"name": ["another-package"],
|
|
48
|
+
"severity": ["medium"],
|
|
49
|
+
"published": ["2021-01-02T00:00:00Z"],
|
|
50
|
+
"days_elapsed": [3],
|
|
51
|
+
},
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
def single_dependabot_data(self):
|
|
56
|
+
"""Fixture providing single dependabot data for specific tests"""
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
"number": [1],
|
|
60
|
+
"state": ["open"],
|
|
61
|
+
"summary": ["Critical vulnerability in test-package-1"],
|
|
62
|
+
"ecosystem": ["npm"],
|
|
63
|
+
"name": ["test-package-1"],
|
|
64
|
+
"severity": ["high"],
|
|
65
|
+
"published": ["2021-01-01T00:00:00Z"],
|
|
66
|
+
"days_elapsed": [5],
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
@pytest.fixture
|
|
71
|
+
def mock_api(self):
|
|
72
|
+
"""Fixture providing a mock API with common configuration"""
|
|
73
|
+
mock_api = MagicMock()
|
|
74
|
+
mock_api.config = {"userId": "1234", "domain": "https://test.regscale.com"}
|
|
75
|
+
mock_api.logger = MagicMock()
|
|
76
|
+
mock_api.logger.info.return_value = None
|
|
77
|
+
return mock_api
|
|
78
|
+
|
|
79
|
+
@pytest.fixture
|
|
80
|
+
def mock_dependabot_api(self):
|
|
81
|
+
"""Fixture providing a mock API with dependabot configuration"""
|
|
82
|
+
mock_api = MagicMock()
|
|
83
|
+
mock_api.config = {
|
|
84
|
+
"githubDomain": "test-domain",
|
|
85
|
+
"dependabotOwner": "test-owner",
|
|
86
|
+
"dependabotRepo": "test-repo",
|
|
87
|
+
"dependabotId": "test-id",
|
|
88
|
+
"dependabotToken": "test-token",
|
|
89
|
+
}
|
|
90
|
+
return mock_api
|
|
91
|
+
|
|
92
|
+
@pytest.fixture
|
|
93
|
+
def mock_response_success(self):
|
|
94
|
+
"""Fixture providing a successful mock response"""
|
|
95
|
+
mock_response = MagicMock()
|
|
96
|
+
mock_response.status_code = 200
|
|
97
|
+
mock_response.ok = True
|
|
98
|
+
return mock_response
|
|
99
|
+
|
|
100
|
+
@pytest.fixture
|
|
101
|
+
def mock_response_error(self):
|
|
102
|
+
"""Fixture providing an error mock response"""
|
|
103
|
+
mock_response = MagicMock()
|
|
104
|
+
mock_response.status_code = 401
|
|
105
|
+
mock_response.ok = False
|
|
106
|
+
return mock_response
|
|
107
|
+
|
|
108
|
+
@pytest.fixture
|
|
109
|
+
def mock_issue_instance(self):
|
|
110
|
+
"""Fixture providing a mock issue instance"""
|
|
111
|
+
mock_issue = MagicMock()
|
|
112
|
+
mock_issue.dict.return_value = {"title": "Dependabot Alert", "description": "Test vulnerability"}
|
|
113
|
+
return mock_issue
|
|
114
|
+
|
|
115
|
+
@pytest.fixture
|
|
116
|
+
def mock_assessment_instance(self):
|
|
117
|
+
"""Fixture providing a mock assessment instance"""
|
|
118
|
+
mock_assessment = MagicMock()
|
|
119
|
+
mock_assessment.id = 12345
|
|
120
|
+
mock_assessment.create.return_value = mock_assessment
|
|
121
|
+
return mock_assessment
|
|
122
|
+
|
|
123
|
+
def test_depend(self):
|
|
124
|
+
"""Make sure values are present"""
|
|
125
|
+
self.verify_config(
|
|
126
|
+
[
|
|
127
|
+
"dependabotId",
|
|
128
|
+
"dependabotOwner",
|
|
129
|
+
"dependabotRepo",
|
|
130
|
+
"dependabotToken",
|
|
131
|
+
"domain",
|
|
132
|
+
"githubDomain",
|
|
133
|
+
],
|
|
134
|
+
compare_template=False,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def test_github(self):
|
|
138
|
+
"""Get Dependabot scans"""
|
|
139
|
+
url = "https://api.github.com"
|
|
140
|
+
try:
|
|
141
|
+
response = requests.get(url, timeout=5)
|
|
142
|
+
if response.status_code != 200:
|
|
143
|
+
pytest.skip(f"Github is down. {response.status_code}")
|
|
144
|
+
except Exception:
|
|
145
|
+
pytest.skip("Github is down.")
|
|
146
|
+
|
|
147
|
+
@patch("regscale.integrations.commercial.dependabot.requests.get")
|
|
148
|
+
def test_get_github_dependabot_alerts(self, mock_get, mock_dependabot_api):
|
|
149
|
+
"""Test get request to dependabot alerts"""
|
|
150
|
+
mock_get.return_value.status_code = 200
|
|
151
|
+
mock_json = MagicMock()
|
|
152
|
+
mock_get.return_value.json.return_value = mock_json
|
|
153
|
+
|
|
154
|
+
result = get_github_dependabot_alerts(mock_dependabot_api)
|
|
155
|
+
assert result == mock_json
|
|
156
|
+
mock_get.assert_called_once()
|
|
157
|
+
|
|
158
|
+
@patch("regscale.integrations.commercial.dependabot.get_github_dependabot_alerts")
|
|
159
|
+
def test_build_data(self, mock_get_github_dependabot_alerts):
|
|
160
|
+
"""Test build data function"""
|
|
161
|
+
mock_get_github_dependabot_alerts.return_value = [
|
|
162
|
+
{
|
|
163
|
+
"number": 1,
|
|
164
|
+
"state": "open",
|
|
165
|
+
"security_advisory": {
|
|
166
|
+
"summary": "Test Alert",
|
|
167
|
+
"published_at": "2021-01-01T00:00:00Z",
|
|
168
|
+
},
|
|
169
|
+
"security_vulnerability": {
|
|
170
|
+
"package": {"ecosystem": "test-ecosystem", "name": "test-name"},
|
|
171
|
+
"severity": "test-severity",
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"state": "closed",
|
|
176
|
+
},
|
|
177
|
+
]
|
|
178
|
+
result = build_data(MagicMock())
|
|
179
|
+
assert len(result) == 1
|
|
180
|
+
|
|
181
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
182
|
+
def test_build_dataframes(self, mock_build_data, sample_dependabot_data):
|
|
183
|
+
"""Test build_dataframes function"""
|
|
184
|
+
mock_build_data.return_value = sample_dependabot_data
|
|
185
|
+
|
|
186
|
+
mock_api = MagicMock()
|
|
187
|
+
result = build_dataframes(mock_api)
|
|
188
|
+
|
|
189
|
+
mock_build_data.assert_called_once_with(api=mock_api)
|
|
190
|
+
|
|
191
|
+
# Verify the result is an HTML table
|
|
192
|
+
assert "<table" in result
|
|
193
|
+
assert "<thead>" in result
|
|
194
|
+
assert "<tbody>" in result
|
|
195
|
+
assert "<tr>" in result
|
|
196
|
+
assert "<td>" in result
|
|
197
|
+
|
|
198
|
+
# Verify the data is present in the HTML
|
|
199
|
+
assert "test-package-1" in result
|
|
200
|
+
assert "another-package" in result
|
|
201
|
+
assert "high" in result
|
|
202
|
+
assert "medium" in result
|
|
203
|
+
assert "npm" in result
|
|
204
|
+
assert "pip" in result
|
|
205
|
+
assert "Critical vulnerability in test-package-1" in result
|
|
206
|
+
assert "Medium severity issue in another-package" in result
|
|
207
|
+
|
|
208
|
+
@patch("regscale.integrations.commercial.dependabot.Assessment.create")
|
|
209
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
210
|
+
def test_create_alert_assessment(
|
|
211
|
+
self, mock_build_data, mock_assessment_create, mock_api, sample_dependabot_data, mock_assessment_instance
|
|
212
|
+
):
|
|
213
|
+
"""Test create alert assessment function"""
|
|
214
|
+
mock_build_data.return_value = sample_dependabot_data
|
|
215
|
+
mock_assessment_create.return_value = mock_assessment_instance
|
|
216
|
+
|
|
217
|
+
result = create_alert_assessment(mock_api, parent_module="test_module", parent_id=123)
|
|
218
|
+
|
|
219
|
+
assert result == 12345
|
|
220
|
+
mock_assessment_create.assert_called_once()
|
|
221
|
+
|
|
222
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
223
|
+
@patch("regscale.integrations.commercial.dependabot.Assessment.create")
|
|
224
|
+
def test_create_alert_assessment_failure(
|
|
225
|
+
self, mock_assessment_create, mock_build_data, mock_api, sample_dependabot_data
|
|
226
|
+
):
|
|
227
|
+
"""Test the create_alert_assessment function when assessment creation fails"""
|
|
228
|
+
mock_build_data.return_value = sample_dependabot_data
|
|
229
|
+
mock_assessment_create.return_value = None
|
|
230
|
+
|
|
231
|
+
result = create_alert_assessment(mock_api)
|
|
232
|
+
|
|
233
|
+
assert result is None
|
|
234
|
+
mock_assessment_create.assert_called_once()
|
|
235
|
+
|
|
236
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
237
|
+
@patch("regscale.integrations.commercial.dependabot.Assessment")
|
|
238
|
+
def test_create_alert_assessment_high_vulnerability(
|
|
239
|
+
self, mock_assessment_class, mock_build_data, mock_api, mock_assessment_instance
|
|
240
|
+
):
|
|
241
|
+
"""Test the create_alert_assessment function with HIGH vulnerability >= 10 days"""
|
|
242
|
+
# Create high vulnerability data
|
|
243
|
+
high_vulnerability_data = [
|
|
244
|
+
{
|
|
245
|
+
"number": [1],
|
|
246
|
+
"state": ["open"],
|
|
247
|
+
"summary": ["Critical vulnerability in test-package-1"],
|
|
248
|
+
"ecosystem": ["npm"],
|
|
249
|
+
"name": ["test-package-1"],
|
|
250
|
+
"severity": ["high"],
|
|
251
|
+
"published": ["2021-01-01T00:00:00Z"],
|
|
252
|
+
"days_elapsed": [15], # >= 10 days
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
mock_build_data.return_value = high_vulnerability_data
|
|
256
|
+
mock_assessment_class.return_value = mock_assessment_instance
|
|
257
|
+
|
|
258
|
+
result = create_alert_assessment(mock_api)
|
|
259
|
+
|
|
260
|
+
assert result == 12345
|
|
261
|
+
# Verify that the assessment was created with the correct status and result
|
|
262
|
+
assert mock_assessment_instance.status == "Complete"
|
|
263
|
+
assert mock_assessment_instance.assessmentResult == "Fail"
|
|
264
|
+
assert mock_assessment_instance.actualFinish is not None
|
|
265
|
+
|
|
266
|
+
@patch("regscale.integrations.commercial.dependabot.Issue")
|
|
267
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
268
|
+
@patch("regscale.integrations.commercial.dependabot.create_alert_assessment")
|
|
269
|
+
def test_create_alert_issues(
|
|
270
|
+
self,
|
|
271
|
+
mock_create_assessment,
|
|
272
|
+
mock_build_data,
|
|
273
|
+
mock_issue_class,
|
|
274
|
+
mock_api,
|
|
275
|
+
mock_issue_instance,
|
|
276
|
+
sample_dependabot_data,
|
|
277
|
+
mock_response_success,
|
|
278
|
+
):
|
|
279
|
+
"""Test the create_alert_issues function with mocked dependencies"""
|
|
280
|
+
mock_create_assessment.return_value = 12345 # assessment_id
|
|
281
|
+
mock_build_data.return_value = sample_dependabot_data
|
|
282
|
+
mock_issue_class.return_value = mock_issue_instance
|
|
283
|
+
mock_api.post.return_value = mock_response_success
|
|
284
|
+
|
|
285
|
+
create_alert_issues(mock_api, parent_id=123, parent_module="test_module")
|
|
286
|
+
|
|
287
|
+
mock_create_assessment.assert_called_once_with(api=mock_api, parent_id=123, parent_module="test_module")
|
|
288
|
+
mock_build_data.assert_called_once_with(api=mock_api)
|
|
289
|
+
|
|
290
|
+
# Verify Issue was created for each vulnerability
|
|
291
|
+
assert mock_issue_class.call_count == 2
|
|
292
|
+
|
|
293
|
+
# Verify API post was called for each issue
|
|
294
|
+
assert mock_api.post.call_count == 2
|
|
295
|
+
|
|
296
|
+
# Verify the correct endpoint was called
|
|
297
|
+
expected_endpoint = "https://test.regscale.com/api/issues"
|
|
298
|
+
mock_api.post.assert_called_with(expected_endpoint, json=mock_issue_instance.dict())
|
|
299
|
+
|
|
300
|
+
@patch("regscale.integrations.commercial.dependabot.Issue")
|
|
301
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
302
|
+
@patch("regscale.integrations.commercial.dependabot.create_alert_assessment")
|
|
303
|
+
def test_create_alert_issues_api_failure(
|
|
304
|
+
self,
|
|
305
|
+
mock_create_assessment,
|
|
306
|
+
mock_build_data,
|
|
307
|
+
mock_issue_class,
|
|
308
|
+
mock_api,
|
|
309
|
+
mock_issue_instance,
|
|
310
|
+
single_dependabot_data,
|
|
311
|
+
mock_response_error,
|
|
312
|
+
):
|
|
313
|
+
"""Test the create_alert_issues function when API calls fail"""
|
|
314
|
+
mock_create_assessment.return_value = 12345 # assessment_id
|
|
315
|
+
mock_build_data.return_value = single_dependabot_data
|
|
316
|
+
mock_issue_class.return_value = mock_issue_instance
|
|
317
|
+
mock_api.post.return_value = mock_response_error
|
|
318
|
+
|
|
319
|
+
create_alert_issues(mock_api)
|
|
320
|
+
|
|
321
|
+
# Verify API post was called
|
|
322
|
+
mock_api.post.assert_called_once()
|
|
323
|
+
|
|
324
|
+
# Verify the correct endpoint was called
|
|
325
|
+
expected_endpoint = "https://test.regscale.com/api/issues"
|
|
326
|
+
mock_api.post.assert_called_with(expected_endpoint, json=mock_issue_instance.dict())
|
|
327
|
+
|
|
328
|
+
@patch("regscale.integrations.commercial.dependabot.build_data")
|
|
329
|
+
@patch("regscale.integrations.commercial.dependabot.create_alert_assessment")
|
|
330
|
+
def test_create_alert_issues_no_vulnerabilities(self, mock_create_assessment, mock_build_data, mock_api):
|
|
331
|
+
"""Test the create_alert_issues function when no vulnerabilities are found"""
|
|
332
|
+
mock_create_assessment.return_value = 12345 # assessment_id
|
|
333
|
+
mock_build_data.return_value = []
|
|
334
|
+
|
|
335
|
+
create_alert_issues(mock_api)
|
|
336
|
+
|
|
337
|
+
mock_create_assessment.assert_called_once_with(api=mock_api, parent_id=None, parent_module=None)
|
|
338
|
+
mock_build_data.assert_called_once_with(api=mock_api)
|
|
339
|
+
|
|
340
|
+
# Verify no API post calls were made (no vulnerabilities)
|
|
341
|
+
mock_api.post.assert_not_called()
|