regscale-cli 6.20.10.0__py3-none-any.whl → 6.21.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 +12 -5
- regscale/core/app/internal/set_permissions.py +58 -27
- regscale/integrations/commercial/nessus/scanner.py +2 -0
- regscale/integrations/commercial/sonarcloud.py +35 -36
- regscale/integrations/commercial/synqly/ticketing.py +51 -0
- regscale/integrations/integration_override.py +15 -6
- regscale/integrations/scanner_integration.py +163 -35
- regscale/models/integration_models/amazon_models/inspector_scan.py +32 -57
- regscale/models/integration_models/aqua.py +92 -78
- regscale/models/integration_models/cisa_kev_data.json +47 -4
- regscale/models/integration_models/defenderimport.py +64 -59
- regscale/models/integration_models/ecr_models/ecr.py +100 -147
- regscale/models/integration_models/flat_file_importer/__init__.py +52 -38
- regscale/models/integration_models/ibm.py +29 -47
- regscale/models/integration_models/nexpose.py +156 -68
- regscale/models/integration_models/prisma.py +46 -66
- regscale/models/integration_models/qualys.py +99 -93
- regscale/models/integration_models/snyk.py +229 -158
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/veracode.py +15 -20
- regscale/models/integration_models/xray.py +276 -82
- regscale/models/regscale_models/control_implementation.py +14 -12
- regscale/models/regscale_models/milestone.py +1 -1
- regscale/models/regscale_models/rbac.py +22 -0
- {regscale_cli-6.20.10.0.dist-info → regscale_cli-6.21.0.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.20.10.0.dist-info → regscale_cli-6.21.0.0.dist-info}/RECORD +37 -36
- tests/fixtures/test_fixture.py +58 -2
- tests/regscale/core/test_app.py +5 -3
- tests/regscale/integrations/test_integration_mapping.py +522 -40
- tests/regscale/integrations/test_issue_due_date.py +1 -1
- tests/regscale/integrations/test_update_finding_dates.py +336 -0
- tests/regscale/models/test_asset.py +406 -50
- {regscale_cli-6.20.10.0.dist-info → regscale_cli-6.21.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.20.10.0.dist-info → regscale_cli-6.21.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.20.10.0.dist-info → regscale_cli-6.21.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.20.10.0.dist-info → regscale_cli-6.21.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "CISA Catalog of Known Exploited Vulnerabilities",
|
|
3
|
-
"catalogVersion": "2025.
|
|
4
|
-
"dateReleased": "2025-
|
|
5
|
-
"count":
|
|
3
|
+
"catalogVersion": "2025.08.05",
|
|
4
|
+
"dateReleased": "2025-08-05T18:03:16.7522Z",
|
|
5
|
+
"count": 1394,
|
|
6
6
|
"vulnerabilities": [
|
|
7
|
+
{
|
|
8
|
+
"cveID": "CVE-2020-25078",
|
|
9
|
+
"vendorProject": "D-Link",
|
|
10
|
+
"product": "DCS-2530L and DCS-2670L Devices",
|
|
11
|
+
"vulnerabilityName": "D-Link DCS-2530L and DCS-2670L Devices Unspecified Vulnerability",
|
|
12
|
+
"dateAdded": "2025-08-05",
|
|
13
|
+
"shortDescription": "D-Link DCS-2530L and DCS-2670L devices contains an unspecified vulnerability that could allow for remote administrator password disclosure. The impacted products could be end-of-life (EoL) and\/or end-of-service (EoS). Users should discontinue product utilization.",
|
|
14
|
+
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
15
|
+
"dueDate": "2025-08-26",
|
|
16
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
+
"notes": "https:\/\/support.dlink.com\/productinfo.aspx?m=DCS-2530L ; https:\/\/supportannouncement.us.dlink.com\/announcement\/publication.aspx?name=SAP10180 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2020-25078",
|
|
18
|
+
"cwes": []
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cveID": "CVE-2020-25079",
|
|
22
|
+
"vendorProject": "D-Link",
|
|
23
|
+
"product": "DCS-2530L and DCS-2670L Devices",
|
|
24
|
+
"vulnerabilityName": "D-Link DCS-2530L and DCS-2670L Command Injection Vulnerability",
|
|
25
|
+
"dateAdded": "2025-08-05",
|
|
26
|
+
"shortDescription": "D-Link DCS-2530L and DCS-2670L devices contains a command injection vulnerability in the cgi-bin\/ddns_enc.cgi. The impacted products could be end-of-life (EoL) and\/or end-of-service (EoS). Users should discontinue product utilization.",
|
|
27
|
+
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
28
|
+
"dueDate": "2025-08-26",
|
|
29
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
30
|
+
"notes": "https:\/\/support.dlink.com\/productinfo.aspx?m=DCS-2530L ; https:\/\/supportannouncement.us.dlink.com\/announcement\/publication.aspx?name=SAP10180 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2020-25079",
|
|
31
|
+
"cwes": [
|
|
32
|
+
"CWE-77"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"cveID": "CVE-2022-40799",
|
|
37
|
+
"vendorProject": "D-Link",
|
|
38
|
+
"product": "DNR-322L",
|
|
39
|
+
"vulnerabilityName": "D-Link DNR-322L Download of Code Without Integrity Check Vulnerability",
|
|
40
|
+
"dateAdded": "2025-08-05",
|
|
41
|
+
"shortDescription": "D-Link DNR-322L contains a download of code without integrity check vulnerability that could allow an authenticated attacker to execute OS level commands on the device. The impacted products could be end-of-life (EoL) and\/or end-of-service (EoS). Users should discontinue product utilization.",
|
|
42
|
+
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
43
|
+
"dueDate": "2025-08-26",
|
|
44
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
45
|
+
"notes": "https:\/\/www.dlink.com\/uk\/en\/products\/dnr-322l-cloud-network-video-recorder ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-40799",
|
|
46
|
+
"cwes": [
|
|
47
|
+
"CWE-494"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
7
50
|
{
|
|
8
51
|
"cveID": "CVE-2023-2533",
|
|
9
52
|
"vendorProject": "PaperCut",
|
|
@@ -148,7 +191,7 @@
|
|
|
148
191
|
"shortDescription": "Microsoft SharePoint Server on-premises contains a deserialization of untrusted data vulnerability that could allow an unauthorized attacker to execute code over a network. This vulnerability could be chained with CVE-2025-53771. CVE-2025-53770 is a patch bypass for CVE-2025-49704, and the updates for CVE-2025-53770 include more robust protection than those for CVE-2025-49704.",
|
|
149
192
|
"requiredAction": "Disconnect public-facing versions of SharePoint Server that have reached their end-of-life (EOL) or end-of-service (EOS) to include SharePoint Server 2013 and earlier versions. For supported versions, please follow the mitigations according to CISA (URL listed below in Notes) and vendor instructions (URL listed below in Notes). Adhere to the applicable BOD 22-01 guidance for cloud services or discontinue use of the product if mitigations are not available.",
|
|
150
193
|
"dueDate": "2025-07-21",
|
|
151
|
-
"knownRansomwareCampaignUse": "
|
|
194
|
+
"knownRansomwareCampaignUse": "Known",
|
|
152
195
|
"notes": "CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/07\/20\/microsoft-releases-guidance-exploitation-sharepoint-vulnerability-cve-2025-53770; https:\/\/www.microsoft.com\/en-us\/security\/blog\/2025\/07\/22\/disrupting-active-exploitation-of-on-premises-sharepoint-vulnerabilities\/ ; https:\/\/msrc.microsoft.com\/update-guide\/vulnerability\/CVE-2025-53770 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-53770",
|
|
153
196
|
"cwes": [
|
|
154
197
|
"CWE-502"
|
|
@@ -3,13 +3,14 @@ Integration model to import data from Defender .csv export
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import Iterator, List, Optional
|
|
7
7
|
|
|
8
8
|
from regscale.core.app.application import Application
|
|
9
9
|
from regscale.core.app.logz import create_logger
|
|
10
|
-
from regscale.core.app.utils.app_utils import
|
|
10
|
+
from regscale.core.app.utils.app_utils import is_valid_fqdn
|
|
11
11
|
from regscale.core.utils.date import datetime_obj, datetime_str
|
|
12
|
-
from regscale.
|
|
12
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
13
|
+
from regscale.models import Asset, ImportValidater, IssueSeverity, IssueStatus
|
|
13
14
|
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
14
15
|
|
|
15
16
|
|
|
@@ -60,7 +61,7 @@ class DefenderImport(FlatFileImporter):
|
|
|
60
61
|
|
|
61
62
|
return datetime_str(dt_object, self.dt_format)
|
|
62
63
|
|
|
63
|
-
def create_asset(self, dat: Optional[dict] = None) ->
|
|
64
|
+
def create_asset(self, dat: Optional[dict] = None) -> IntegrationAsset:
|
|
64
65
|
"""
|
|
65
66
|
Create an asset from a row in the Snyk file
|
|
66
67
|
|
|
@@ -72,72 +73,76 @@ class DefenderImport(FlatFileImporter):
|
|
|
72
73
|
os = Asset.find_os(additional_data.get("imageDetails", {}).get("osDetails", ""))
|
|
73
74
|
name = additional_data.get("repositoryName", "")
|
|
74
75
|
valid_name = is_valid_fqdn(name)
|
|
75
|
-
return
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"scanningTool": self.name,
|
|
86
|
-
"assetOwnerId": self.config["userId"],
|
|
87
|
-
"assetType": "Other",
|
|
88
|
-
"fqdn": name if valid_name else None,
|
|
89
|
-
"systemAdministratorId": self.config["userId"],
|
|
90
|
-
"parentId": self.attributes.parent_id,
|
|
91
|
-
"parentModule": self.attributes.parent_module,
|
|
92
|
-
"operatingSystem": os,
|
|
93
|
-
}
|
|
76
|
+
return IntegrationAsset(
|
|
77
|
+
identifier=name,
|
|
78
|
+
name=name,
|
|
79
|
+
ip_address="0.0.0.0",
|
|
80
|
+
status="Active (On Network)",
|
|
81
|
+
asset_category="Software",
|
|
82
|
+
scanning_tool=self.name,
|
|
83
|
+
asset_type="Other",
|
|
84
|
+
fqdn=name if valid_name else None,
|
|
85
|
+
operating_system=os,
|
|
94
86
|
)
|
|
95
87
|
|
|
96
|
-
def create_vuln(self, dat: Optional[dict] = None, **kwargs: dict) ->
|
|
88
|
+
def create_vuln(self, dat: Optional[dict] = None, **kwargs: dict) -> Iterator[IntegrationFinding]:
|
|
97
89
|
"""
|
|
98
90
|
Create a vulnerability from a row in the Snyk csv file
|
|
99
91
|
|
|
100
92
|
:param Optional[dict] dat: Data row from CSV file, defaults to None
|
|
101
93
|
:param dict **kwargs: Additional keyword arguments
|
|
102
|
-
:return: RegScale
|
|
103
|
-
:rtype:
|
|
94
|
+
:return: RegScale Iterator of findings
|
|
95
|
+
:rtype: Iterator[IntegrationFinding]
|
|
104
96
|
"""
|
|
105
|
-
|
|
106
|
-
severity = self.mapping.get_value(dat, "SEVERITY", "").lower()
|
|
97
|
+
regscale_findings: List[IntegrationFinding] = []
|
|
98
|
+
severity = self.determine_severity(self.mapping.get_value(dat, "SEVERITY", "").lower())
|
|
107
99
|
additional_data = json.loads(self.mapping.get_value(dat, "ADDITIONALDATA", {}))
|
|
108
100
|
hostname = additional_data.get("repositoryName", "")
|
|
109
101
|
description = self.mapping.get_value(dat, self.vuln_title)
|
|
110
102
|
solution = self.mapping.get_value(dat, self.vuln_id)
|
|
111
|
-
config = self.attributes.app.config
|
|
112
|
-
asset_match = [asset for asset in self.data["assets"] if asset.name == hostname]
|
|
113
|
-
asset = asset_match[0] if asset_match else None
|
|
114
103
|
cves = [cve.get("title", "") for cve in additional_data.get("cve", [])]
|
|
115
104
|
cvss_v3_score = float(additional_data.get("cvssV30Score", 0))
|
|
116
|
-
if dat
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
105
|
+
if dat:
|
|
106
|
+
if cves and isinstance(cves, list):
|
|
107
|
+
for cve in cves:
|
|
108
|
+
regscale_finding = IntegrationFinding(
|
|
109
|
+
title=f"{description} on asset {hostname}",
|
|
110
|
+
asset_identifier=hostname,
|
|
111
|
+
description=description,
|
|
112
|
+
severity=severity,
|
|
113
|
+
status=IssueStatus.Open.value,
|
|
114
|
+
cvss_v3_score=cvss_v3_score,
|
|
115
|
+
cvss_v3_base_score=cvss_v3_score,
|
|
116
|
+
plugin_name=description,
|
|
117
|
+
plugin_text=self.mapping.get_value(dat, self.vuln_title),
|
|
118
|
+
cve=cve,
|
|
119
|
+
recommendation_for_mitigation=solution,
|
|
120
|
+
first_seen=self.determine_first_seen(dat),
|
|
121
|
+
last_seen=self.scan_date,
|
|
122
|
+
scan_date=self.scan_date,
|
|
123
|
+
category="Software",
|
|
124
|
+
control_labels=[],
|
|
125
|
+
)
|
|
126
|
+
regscale_findings.append(regscale_finding)
|
|
127
|
+
else:
|
|
128
|
+
regscale_finding = IntegrationFinding(
|
|
129
|
+
title=f"{description} on asset {hostname}",
|
|
130
|
+
description=description,
|
|
131
|
+
severity=severity,
|
|
132
|
+
status=IssueStatus.Open.value,
|
|
133
|
+
cvss_v3_score=cvss_v3_score,
|
|
134
|
+
cvss_v3_base_score=cvss_v3_score,
|
|
135
|
+
plugin_name=description,
|
|
136
|
+
plugin_text=self.mapping.get_value(dat, self.vuln_title),
|
|
137
|
+
asset_identifier=hostname,
|
|
138
|
+
cve=self.mapping.get_value(dat, self.vuln_title),
|
|
139
|
+
recommendation_for_mitigation=solution,
|
|
140
|
+
first_seen=self.determine_first_seen(dat),
|
|
141
|
+
last_seen=self.scan_date,
|
|
142
|
+
scan_date=self.scan_date,
|
|
143
|
+
category="Software",
|
|
144
|
+
control_labels=[],
|
|
145
|
+
)
|
|
146
|
+
regscale_findings.append(regscale_finding)
|
|
147
|
+
|
|
148
|
+
yield from regscale_findings
|
|
@@ -2,39 +2,45 @@
|
|
|
2
2
|
ECR Scan information
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Any, List, Optional, Sequence, Union
|
|
5
|
+
from typing import List, Optional, Union
|
|
8
6
|
|
|
9
7
|
from regscale.core.app.application import Application
|
|
10
8
|
from regscale.core.app.logz import create_logger
|
|
11
|
-
from regscale.
|
|
12
|
-
from regscale.exceptions import ValidationException
|
|
9
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
13
10
|
from regscale.models import ImportValidater
|
|
14
11
|
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
12
|
+
from regscale.models.regscale_models import AssetStatus, IssueSeverity, IssueStatus
|
|
15
13
|
from regscale.models.regscale_models.asset import Asset
|
|
16
|
-
from regscale.models.regscale_models.vulnerability import Vulnerability
|
|
17
14
|
|
|
18
15
|
|
|
19
16
|
class ECR(FlatFileImporter):
|
|
20
17
|
"""ECR Scan information"""
|
|
21
18
|
|
|
22
19
|
def __init__(self, **kwargs):
|
|
23
|
-
|
|
24
|
-
self.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
# Group related attributes to reduce instance attribute count
|
|
21
|
+
self.scanner_config = {
|
|
22
|
+
"name": kwargs.get("name"),
|
|
23
|
+
"vuln_title": "name",
|
|
24
|
+
"fmt": "%m/%d/%y",
|
|
25
|
+
"dt_format": "%Y-%m-%d %H:%M:%S",
|
|
26
|
+
"image_name": "Name",
|
|
27
|
+
}
|
|
28
|
+
self.mapping_config = {
|
|
29
|
+
"mapping_file": kwargs.get("mappings_path"),
|
|
30
|
+
"disable_mapping": kwargs.get("disable_mapping"),
|
|
31
|
+
}
|
|
32
|
+
self.file_config = {
|
|
33
|
+
"file_type": kwargs.get("file_type"),
|
|
34
|
+
"raw_dict": {},
|
|
35
|
+
}
|
|
36
|
+
self.required_headers = [self.scanner_config["image_name"]]
|
|
37
|
+
keys = ["imageScanFindings", "findings"] if self.file_config["file_type"] == ".json" else None
|
|
36
38
|
self.validater = ImportValidater(
|
|
37
|
-
self.required_headers,
|
|
39
|
+
self.required_headers,
|
|
40
|
+
kwargs.get("file_path"),
|
|
41
|
+
self.mapping_config["mapping_file"],
|
|
42
|
+
self.mapping_config["disable_mapping"],
|
|
43
|
+
keys=keys,
|
|
38
44
|
)
|
|
39
45
|
self.headers = self.validater.parsed_headers
|
|
40
46
|
self.mapping = self.validater.mapping
|
|
@@ -48,92 +54,55 @@ class ECR(FlatFileImporter):
|
|
|
48
54
|
**kwargs,
|
|
49
55
|
)
|
|
50
56
|
|
|
51
|
-
def
|
|
52
|
-
self,
|
|
53
|
-
) -> tuple[Optional[Sequence[str]], Union[dict, list[Any]]]:
|
|
57
|
+
def create_asset(self, dat: Optional[dict] = None) -> IntegrationAsset:
|
|
54
58
|
"""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
:raises ValidationException: If the headers in the csv/xlsx file do not match the expected headers
|
|
58
|
-
:return: Tuple of header and data from csv file
|
|
59
|
-
:rtype: tuple[Optional[Sequence[str]], Union[dict, list[Any]]]
|
|
60
|
-
"""
|
|
61
|
-
header: Optional[Sequence[str]] = []
|
|
62
|
-
data: dict = {}
|
|
63
|
-
with open(self.attributes.file_path, encoding="utf-8") as file:
|
|
64
|
-
if file.name.endswith(".csv"):
|
|
65
|
-
data, header = self.convert_csv_to_dict(file)
|
|
66
|
-
elif file.name.endswith(".json"):
|
|
67
|
-
try:
|
|
68
|
-
# Filter possible null values
|
|
69
|
-
self.raw_dict = json.load(file)
|
|
70
|
-
if not isinstance(self.raw_dict, dict):
|
|
71
|
-
raise ValidationException(
|
|
72
|
-
f"Invalid JSON file. Must be a dictionary, it is {type(self.raw_dict)}"
|
|
73
|
-
)
|
|
74
|
-
data = self.raw_dict.get("imageScanFindings", {}).get("findings", [])
|
|
75
|
-
except json.JSONDecodeError:
|
|
76
|
-
raise ValidationException("Invalid JSON file. Encountered a JSONDecodeError.")
|
|
77
|
-
else:
|
|
78
|
-
raise ValidationException(
|
|
79
|
-
f"Unsupported file type. Must be a .csv or .json file.\nProvided: {self.file_type}"
|
|
80
|
-
)
|
|
81
|
-
return header, data
|
|
82
|
-
|
|
83
|
-
def create_asset(self, dat: Optional[dict] = None) -> Asset:
|
|
84
|
-
"""
|
|
85
|
-
Create an asset from a row in the ECR file
|
|
59
|
+
Create an integration asset from a row in the ECR file
|
|
86
60
|
|
|
87
61
|
:param Optional[dict] dat: Data row from file, defaults to None
|
|
88
|
-
:return: RegScale
|
|
89
|
-
:rtype:
|
|
62
|
+
:return: RegScale IntegrationAsset object
|
|
63
|
+
:rtype: IntegrationAsset
|
|
90
64
|
"""
|
|
91
65
|
name = self.mapping.get_value(dat, "Name") or self.mapping.get_value(dat, "name")
|
|
92
|
-
if repository_name := self.mapping.get_value(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
66
|
+
if repository_name := self.mapping.get_value(
|
|
67
|
+
dat, "repositoryName", self.file_config["raw_dict"].get("repositoryName", "")
|
|
68
|
+
):
|
|
69
|
+
image_id_data = self.file_config["raw_dict"].get("imageId", {}).get("imageDigest", "").split(":")
|
|
70
|
+
if image_id_data and len(image_id_data) > 1:
|
|
96
71
|
image_id = image_id_data[1]
|
|
97
72
|
else:
|
|
98
73
|
image_id = image_id_data[0]
|
|
99
74
|
name = f"{repository_name}:{image_id}"
|
|
100
75
|
|
|
101
76
|
# Check if string has a forward slash
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"bLatestScan": True,
|
|
114
|
-
"bAuthenticatedScan": True,
|
|
115
|
-
"scanningTool": self.name,
|
|
116
|
-
"assetOwnerId": self.config["userId"],
|
|
117
|
-
"assetType": "Other",
|
|
118
|
-
"fqdn": name if is_valid_fqdn(name) else None,
|
|
119
|
-
"systemAdministratorId": self.config["userId"],
|
|
120
|
-
"parentId": self.attributes.parent_id,
|
|
121
|
-
"parentModule": self.attributes.parent_module,
|
|
122
|
-
}
|
|
77
|
+
return IntegrationAsset(
|
|
78
|
+
identifier=name,
|
|
79
|
+
name=name,
|
|
80
|
+
ip_address="0.0.0.0",
|
|
81
|
+
cpu=0,
|
|
82
|
+
ram=0,
|
|
83
|
+
scanning_tool=self.scanner_config["name"],
|
|
84
|
+
status=AssetStatus.Active.value,
|
|
85
|
+
asset_type="Other",
|
|
86
|
+
asset_category="Software",
|
|
87
|
+
operating_system="Linux",
|
|
123
88
|
)
|
|
124
89
|
|
|
125
|
-
def create_vuln(
|
|
90
|
+
def create_vuln(
|
|
91
|
+
self, dat: Optional[dict] = None, **_kwargs
|
|
92
|
+
) -> Union[IntegrationFinding, List[IntegrationFinding], None]:
|
|
126
93
|
"""
|
|
127
|
-
Create a
|
|
94
|
+
Create a finding from a row in the ECR csv file
|
|
128
95
|
|
|
129
96
|
:param Optional[dict] dat: Data row from file, defaults to None
|
|
130
|
-
:return: RegScale
|
|
131
|
-
:rtype: Union[
|
|
97
|
+
:return: RegScale IntegrationFinding object, a list of RegScale IntegrationFinding objects or None
|
|
98
|
+
:rtype: Union[IntegrationFinding, List[IntegrationFinding], None]
|
|
132
99
|
"""
|
|
133
|
-
vulns: List[
|
|
100
|
+
vulns: List[IntegrationFinding] = []
|
|
134
101
|
hostname = dat.get("Name") or dat.get("name")
|
|
135
|
-
if repository_name := self.mapping.get_value(
|
|
136
|
-
|
|
102
|
+
if repository_name := self.mapping.get_value(
|
|
103
|
+
dat, "repositoryName", self.file_config["raw_dict"].get("repositoryName", "")
|
|
104
|
+
):
|
|
105
|
+
image_id_data = self.file_config["raw_dict"].get("imageId", {}).get("imageDigest", "").split(":")
|
|
137
106
|
if len(image_id_data) > 1:
|
|
138
107
|
image_id = image_id_data[1]
|
|
139
108
|
else:
|
|
@@ -147,89 +116,73 @@ class ECR(FlatFileImporter):
|
|
|
147
116
|
return single_vuln
|
|
148
117
|
return vulns
|
|
149
118
|
|
|
150
|
-
def
|
|
151
|
-
"""
|
|
152
|
-
Get the asset by hostname
|
|
153
|
-
|
|
154
|
-
:param str hostname: The hostname
|
|
155
|
-
:return: The asset if found, otherwise None
|
|
156
|
-
:rtype: Optional[Asset]
|
|
157
|
-
"""
|
|
158
|
-
asset_match = [asset for asset in self.data["assets"] if asset.name == hostname]
|
|
159
|
-
return asset_match[0] if asset_match else None
|
|
160
|
-
|
|
161
|
-
def create_vulnerability_object(
|
|
162
|
-
self, asset: Asset, hostname: str, cve: str, severity: str, description: str
|
|
163
|
-
) -> Vulnerability:
|
|
119
|
+
def create_finding(self, finding_data: dict) -> IntegrationFinding:
|
|
164
120
|
"""
|
|
165
|
-
Create
|
|
121
|
+
Create an IntegrationFinding from finding data
|
|
166
122
|
|
|
167
|
-
:param
|
|
168
|
-
:
|
|
169
|
-
:
|
|
170
|
-
:param str severity: The severity
|
|
171
|
-
:param str description: The description
|
|
172
|
-
:return: The vulnerability
|
|
173
|
-
:rtype: Vulnerability
|
|
123
|
+
:param dict finding_data: Dictionary containing finding data
|
|
124
|
+
:return: The IntegrationFinding
|
|
125
|
+
:rtype: IntegrationFinding
|
|
174
126
|
"""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
tenantsId=0,
|
|
193
|
-
title=f"{cve} on asset {asset.name}",
|
|
194
|
-
description=cve,
|
|
195
|
-
plugInText=description,
|
|
196
|
-
createdById=config["userId"],
|
|
197
|
-
lastUpdatedById=config["userId"],
|
|
198
|
-
dateCreated=get_current_datetime(),
|
|
127
|
+
title = f"{finding_data['cve']} on asset {finding_data['hostname']}"
|
|
128
|
+
return IntegrationFinding(
|
|
129
|
+
title=title,
|
|
130
|
+
dns=finding_data["hostname"],
|
|
131
|
+
description=finding_data["cve"],
|
|
132
|
+
severity=self.determine_severity(finding_data["severity"]),
|
|
133
|
+
status=IssueStatus.Open.value,
|
|
134
|
+
plugin_name=finding_data["cve"],
|
|
135
|
+
plugin_id=finding_data["cve"],
|
|
136
|
+
plugin_text=finding_data["description"],
|
|
137
|
+
asset_identifier=finding_data["hostname"],
|
|
138
|
+
cve=finding_data["cve"],
|
|
139
|
+
first_seen=self.scan_date,
|
|
140
|
+
last_seen=self.scan_date,
|
|
141
|
+
scan_date=self.scan_date,
|
|
142
|
+
category="Software",
|
|
143
|
+
control_labels=[],
|
|
199
144
|
)
|
|
200
145
|
|
|
201
|
-
def process_csv_vulns(self, dat: dict, hostname: str) -> Optional[
|
|
146
|
+
def process_csv_vulns(self, dat: dict, hostname: str) -> Optional[IntegrationFinding]:
|
|
202
147
|
"""
|
|
203
148
|
Process the CSV findings from the ECR scan
|
|
204
149
|
|
|
205
150
|
:param dict dat: The data from the ECR scan
|
|
206
151
|
:param str hostname: The hostname
|
|
207
152
|
:return: The vulnerability or None
|
|
208
|
-
:rtype: Optional[
|
|
153
|
+
:rtype: Optional[IntegrationFinding]
|
|
209
154
|
|
|
210
155
|
"""
|
|
211
156
|
cve = dat.get("CVE", "")
|
|
212
157
|
severity = self.determine_severity(dat.get("Severity", "Info"))
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
158
|
+
finding_data = {
|
|
159
|
+
"hostname": hostname,
|
|
160
|
+
"cve": cve,
|
|
161
|
+
"severity": severity,
|
|
162
|
+
"description": dat.get("uri", ""),
|
|
163
|
+
}
|
|
164
|
+
return self.create_finding(finding_data)
|
|
165
|
+
|
|
166
|
+
def process_json_vulns(self, dat: dict, hostname: str) -> List[IntegrationFinding]:
|
|
218
167
|
"""
|
|
219
168
|
Process the JSON findings from the ECR scan
|
|
220
169
|
|
|
221
170
|
:param dict dat: The data from the ECR scan
|
|
222
171
|
:param str hostname: The hostname
|
|
223
172
|
:return: The list of vulnerabilities
|
|
224
|
-
:rtype: List[
|
|
173
|
+
:rtype: List[IntegrationFinding]
|
|
225
174
|
"""
|
|
226
|
-
vulns: List[
|
|
175
|
+
vulns: List[IntegrationFinding] = []
|
|
227
176
|
if findings := dat.get("imageScanFindings", {}).get("findings"):
|
|
228
177
|
for finding in findings:
|
|
229
178
|
cve = finding.get("name")
|
|
230
179
|
severity = self.determine_severity(finding["severity"])
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
180
|
+
finding_data = {
|
|
181
|
+
"hostname": hostname,
|
|
182
|
+
"cve": cve,
|
|
183
|
+
"severity": severity,
|
|
184
|
+
"description": finding.get("uri", ""),
|
|
185
|
+
}
|
|
186
|
+
vuln = self.create_finding(finding_data)
|
|
187
|
+
vulns.append(vuln)
|
|
235
188
|
return vulns
|