regscale-cli 6.20.9.1__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.

Files changed (56) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/application.py +12 -5
  3. regscale/core/app/internal/set_permissions.py +58 -27
  4. regscale/integrations/commercial/defender.py +9 -0
  5. regscale/integrations/commercial/nessus/scanner.py +2 -0
  6. regscale/integrations/commercial/sonarcloud.py +35 -36
  7. regscale/integrations/commercial/synqly/ticketing.py +51 -0
  8. regscale/integrations/commercial/wizv2/async_client.py +325 -0
  9. regscale/integrations/commercial/wizv2/constants.py +756 -0
  10. regscale/integrations/commercial/wizv2/scanner.py +1301 -89
  11. regscale/integrations/commercial/wizv2/utils.py +280 -36
  12. regscale/integrations/commercial/wizv2/variables.py +2 -10
  13. regscale/integrations/integration_override.py +15 -6
  14. regscale/integrations/scanner_integration.py +221 -37
  15. regscale/integrations/variables.py +1 -0
  16. regscale/models/integration_models/amazon_models/inspector_scan.py +32 -57
  17. regscale/models/integration_models/aqua.py +92 -78
  18. regscale/models/integration_models/cisa_kev_data.json +47 -4
  19. regscale/models/integration_models/defenderimport.py +64 -59
  20. regscale/models/integration_models/ecr_models/ecr.py +100 -147
  21. regscale/models/integration_models/flat_file_importer/__init__.py +52 -38
  22. regscale/models/integration_models/ibm.py +29 -47
  23. regscale/models/integration_models/nexpose.py +156 -68
  24. regscale/models/integration_models/prisma.py +46 -66
  25. regscale/models/integration_models/qualys.py +99 -93
  26. regscale/models/integration_models/snyk.py +229 -158
  27. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  28. regscale/models/integration_models/veracode.py +15 -20
  29. regscale/models/integration_models/xray.py +276 -82
  30. regscale/models/regscale_models/__init__.py +13 -0
  31. regscale/models/regscale_models/classification.py +23 -0
  32. regscale/models/regscale_models/control_implementation.py +14 -12
  33. regscale/models/regscale_models/cryptography.py +56 -0
  34. regscale/models/regscale_models/deviation.py +4 -4
  35. regscale/models/regscale_models/group.py +3 -2
  36. regscale/models/regscale_models/interconnection.py +1 -1
  37. regscale/models/regscale_models/issue.py +140 -41
  38. regscale/models/regscale_models/milestone.py +40 -0
  39. regscale/models/regscale_models/property.py +0 -1
  40. regscale/models/regscale_models/rbac.py +22 -0
  41. regscale/models/regscale_models/regscale_model.py +29 -18
  42. regscale/models/regscale_models/team.py +55 -0
  43. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/METADATA +1 -1
  44. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/RECORD +56 -49
  45. tests/fixtures/test_fixture.py +58 -2
  46. tests/regscale/core/test_app.py +5 -3
  47. tests/regscale/integrations/test_integration_mapping.py +522 -40
  48. tests/regscale/integrations/test_issue_due_date.py +1 -1
  49. tests/regscale/integrations/test_property_and_milestone_creation.py +684 -0
  50. tests/regscale/integrations/test_update_finding_dates.py +336 -0
  51. tests/regscale/models/test_asset.py +406 -50
  52. tests/regscale/models/test_report.py +105 -29
  53. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/LICENSE +0 -0
  54. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/WHEEL +0 -0
  55. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/entry_points.txt +0 -0
  56. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/top_level.txt +0 -0
@@ -10,10 +10,12 @@ from regscale.core.app.application import Application
10
10
  from regscale.core.app.logz import create_logger
11
11
  from regscale.core.app.utils.app_utils import get_current_datetime, is_valid_fqdn
12
12
  from regscale.core.utils.date import datetime_str
13
+ from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
14
+ from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
13
15
  from regscale.models.app_models import ImportValidater
14
16
  from regscale.models.integration_models.flat_file_importer import FlatFileImporter
15
- from regscale.models.regscale_models.asset import Asset
16
- from regscale.models.regscale_models.vulnerability import Vulnerability
17
+ from regscale.models.regscale_models import AssetStatus, IssueSeverity, IssueStatus
18
+ from regscale.models.regscale_models import AssetStatus, IssueSeverity, IssueStatus
17
19
 
18
20
 
19
21
  class Aqua(FlatFileImporter):
@@ -36,6 +38,7 @@ class Aqua(FlatFileImporter):
36
38
  self.vendor_cvss_v2_severity = "Vendor CVSS v2 Severity"
37
39
  self.vendor_cvss_v3_severity = "Vendor CVSS v3 Severity"
38
40
  self.vendor_cvss_v3_score = "Vendor CVSS v3 Score"
41
+ self.vendor_cvss_v2_score = "Vendor CVSS v2 Score"
39
42
  self.nvd_cvss_v2_severity = "NVD CVSS v2 Severity"
40
43
  self.nvd_cvss_v3_severity = "NVD CVSS v3 Severity"
41
44
  self.required_headers = [
@@ -63,40 +66,32 @@ class Aqua(FlatFileImporter):
63
66
  **kwargs,
64
67
  )
65
68
 
66
- def create_asset(self, dat: Optional[dict] = None) -> Optional[Asset]:
69
+ def create_asset(self, dat: Optional[dict] = None) -> Optional[IntegrationAsset]:
67
70
  """
68
- Create an asset from a row in the Aqua file
71
+ Create an IntegrationAsset from a row in the Aqua file
69
72
 
70
73
  :param Optional[dict] dat: Data row from CSV file, defaults to None
71
- :return: RegScale Asset object or None
72
- :rtype: Optional[Asset]
74
+ :return: RegScale IntegrationAsset object or None
75
+ :rtype: Optional[IntegrationAsset]
73
76
  """
74
77
  name = self.mapping.get_value(dat, self.image_name)
75
78
  if not name:
76
79
  return None
77
80
  os = self.mapping.get_value(dat, self.OS)
78
- return Asset(
79
- **{
80
- "id": 0,
81
- "name": name,
82
- "description": "",
83
- "operatingSystem": Asset.find_os(os),
84
- "operatingSystemVersion": os,
85
- "ipAddress": "0.0.0.0",
86
- "isPublic": True,
87
- "status": "Active (On Network)",
88
- "assetCategory": "Hardware",
89
- "bLatestScan": True,
90
- "bAuthenticatedScan": True,
91
- "scanningTool": self.name,
92
- "assetOwnerId": self.config["userId"],
93
- "assetType": "Other",
94
- "fqdn": name if is_valid_fqdn(name) else None,
95
- "systemAdministratorId": self.config["userId"],
96
- "parentId": self.attributes.parent_id,
97
- "parentModule": self.attributes.parent_module,
98
- "extra_data": {"software_inventory": self.generate_software_inventory(name)},
99
- }
81
+ return IntegrationAsset(
82
+ identifier=name,
83
+ name=name,
84
+ ip_address="0.0.0.0",
85
+ cpu=0,
86
+ ram=0,
87
+ status=AssetStatus.Active.value,
88
+ asset_type="Other",
89
+ asset_category="Hardware",
90
+ scanning_tool=self.name,
91
+ fqdn=name if is_valid_fqdn(name) else None,
92
+ operating_system=os,
93
+ other_tracking_number=name,
94
+ software_inventory=self.generate_software_inventory(name),
100
95
  )
101
96
 
102
97
  def generate_software_inventory(self, name: str) -> List[dict]:
@@ -137,64 +132,83 @@ class Aqua(FlatFileImporter):
137
132
  :rtype: str
138
133
  """
139
134
  self.logger.info(f"Unable to determine date for the '{field}' field, falling back to current date and time.")
140
- return get_current_datetime()
135
+ return self.scan_date
136
+
137
+ def determine_first_seen(self, dat: dict) -> str:
138
+ """
139
+ Determine the first seen date and time of the vulnerability
140
+
141
+ :param dict dat: Data row from CSV file
142
+ :return: The first seen date and time
143
+ :rtype: str
144
+ """
145
+ first_detected = datetime_str(
146
+ self.mapping.get_value(dat, self.integration_mapping.load("aqua", "dateFirstDetected"))
147
+ )
148
+ ffi = datetime_str(self.mapping.get_value(dat, self.ffi)) or self.current_datetime_w_log(self.ffi)
149
+ if first_detected and first_detected != ffi:
150
+ ffi = first_detected
151
+ return ffi
141
152
 
142
- def create_vuln(self, dat: Optional[dict] = None, **kwargs: dict) -> Optional[Vulnerability]:
153
+ def create_vuln(self, dat: Optional[dict] = None, **kwargs: dict) -> Optional[IntegrationFinding]:
143
154
  """
144
- Create a vulnerability from a row in the Aqua csv file
155
+ Create a IntegrationFinding from a row in the Aqua csv file
145
156
 
146
157
  :param Optional[dict] dat: Data row from CSV file, defaults to None
147
158
  :param dict **kwargs: Additional keyword arguments
148
- :return: RegScale Vulnerability object or None
149
- :rtype: Optional[Vulnerability]
159
+ :return: RegScale IntegrationFinding object or None
160
+ :rtype: Optional[IntegrationFinding]
150
161
  """
151
162
 
152
- hostname = self.mapping.get_value(dat, self.image_name)
163
+ try:
164
+ hostname = self.mapping.get_value(dat, self.image_name)
153
165
 
154
- # Custom Integration Mapping fields
155
- remediation = self.mapping.get_value(dat, self.integration_mapping.load("aqua", "remediation")) or (
156
- self.mapping.get_value(dat, self.description) or "Upgrade affected package"
157
- ) # OLDTODO: BMC would like this to use "Solution" column
158
- description = self.mapping.get_value(dat, self.integration_mapping.load("aqua", "description")) or (
159
- self.mapping.get_value(dat, self.description)
160
- )
161
- title = self.mapping.get_value(dat, self.integration_mapping.load("aqua", "title")) or (
162
- description[:255] if description else f"Vulnerability on {hostname}"
163
- ) # OLDTODO: BMC Would like the CVE here
164
-
165
- regscale_vuln = None
166
- severity = self.determine_cvss_severity(dat)
167
- config = self.attributes.app.config
168
- asset_match = [asset for asset in self.data["assets"] if asset.name == hostname]
169
- asset = asset_match[0] if asset_match else None
170
- if asset_match and self.validate(ix=kwargs.get("index"), dat=dat):
171
- regscale_vuln = Vulnerability(
172
- id=0,
173
- scanId=0,
174
- parentId=asset.id,
175
- parentModule="assets",
176
- ipAddress="0.0.0.0",
177
- lastSeen=datetime_str(self.mapping.get_value(dat, self.last_image_scan))
178
- or self.current_datetime_w_log(self.last_image_scan),
179
- firstSeen=datetime_str(self.mapping.get_value(dat, self.ffi)) or self.current_datetime_w_log(self.ffi),
180
- daysOpen=None,
181
- dns=hostname,
182
- mitigated=None,
183
- operatingSystem=asset.operatingSystem,
184
- severity=severity,
185
- plugInName=description,
186
- cve=self.mapping.get_value(dat, self.vuln_title),
187
- cvsSv3BaseScore=self.mapping.get_value(dat, self.vendor_cvss_v3_score, 0.0),
188
- tenantsId=0,
189
- title=title,
190
- description=description,
191
- plugInText=self.mapping.get_value(dat, self.vuln_title),
192
- createdById=config["userId"],
193
- lastUpdatedById=config["userId"],
194
- dateCreated=get_current_datetime(),
195
- extra_data={"solution": remediation},
166
+ # Custom Integration Mapping fields
167
+ remediation = self.mapping.get_value(dat, self.integration_mapping.load("aqua", "remediation")) or (
168
+ self.mapping.get_value(dat, self.description) or "Upgrade affected package"
169
+ ) # OLDTODO: BMC would like this to use "Solution" column
170
+ description = self.mapping.get_value(dat, self.integration_mapping.load("aqua", "description")) or (
171
+ self.mapping.get_value(dat, self.description)
196
172
  )
197
- return regscale_vuln
173
+ title = self.mapping.get_value(dat, self.integration_mapping.load("aqua", "title")) or (
174
+ description[:255] if description else f"Vulnerability on {hostname}"
175
+ ) # OLDTODO: BMC Would like the CVE here
176
+
177
+ cvss3_score = self.mapping.get_value(dat, self.vendor_cvss_v3_score) or 0.0
178
+ cvss_v2_score = self.mapping.get_value(dat, self.vendor_cvss_v2_score) or 0.0
179
+
180
+ regscale_finding = None
181
+ severity = self.determine_cvss_severity(dat)
182
+ # Create IntegrationFinding if we have valid data and asset match
183
+
184
+ if dat:
185
+ return IntegrationFinding(
186
+ control_labels=[], # Add an empty list for control_labels
187
+ title=title,
188
+ description=description,
189
+ ip_address="0.0.0.0",
190
+ cve=self.mapping.get_value(dat, self.vuln_title, "").upper(),
191
+ severity=severity,
192
+ asset_identifier=hostname,
193
+ plugin_name=description,
194
+ plugin_id=self.mapping.get_value(dat, self.vuln_title),
195
+ cvss_score=cvss_v2_score or 0.0,
196
+ cvss_v3_score=cvss3_score or 0.0,
197
+ cvss_v2_score=cvss_v2_score or 0.0,
198
+ plugin_text=self.mapping.get_value(dat, self.vuln_title),
199
+ remediation=remediation,
200
+ category="Hardware",
201
+ status=IssueStatus.Open,
202
+ first_seen=self.determine_first_seen(dat),
203
+ last_seen=datetime_str(self.mapping.get_value(dat, self.last_image_scan))
204
+ or self.current_datetime_w_log(self.last_image_scan),
205
+ vulnerability_type="Vulnerability Scan",
206
+ baseline=f"{self.name} Host",
207
+ )
208
+ return regscale_finding
209
+ except AttributeError as e:
210
+ self.logger.error(f"Error creating finding: {e}")
211
+ return None
198
212
 
199
213
  def determine_cvss_severity(self, dat: dict) -> str:
200
214
  """
@@ -217,7 +231,7 @@ class Aqua(FlatFileImporter):
217
231
  severity = self.mapping.get_value(dat, key).lower()
218
232
  break
219
233
 
220
- return severity
234
+ return self.determine_severity(severity)
221
235
 
222
236
  def validate(self, ix: Optional[int], dat: dict) -> bool:
223
237
  """
@@ -1,9 +1,52 @@
1
1
  {
2
2
  "title": "CISA Catalog of Known Exploited Vulnerabilities",
3
- "catalogVersion": "2025.07.29",
4
- "dateReleased": "2025-07-29T12:46:00.2038Z",
5
- "count": 1391,
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": "Unknown",
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 get_current_datetime, is_valid_fqdn
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.models import Asset, ImportValidater, Vulnerability
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) -> Asset:
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 Asset(
76
- **{
77
- "id": 0,
78
- "name": name,
79
- "ipAddress": "0.0.0.0",
80
- "isPublic": True,
81
- "status": "Active (On Network)",
82
- "assetCategory": "Software",
83
- "bLatestScan": True,
84
- "bAuthenticatedScan": True,
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) -> Optional[Vulnerability]:
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 Vulnerability object or None
103
- :rtype: Optional[Vulnerability]
94
+ :return: RegScale Iterator of findings
95
+ :rtype: Iterator[IntegrationFinding]
104
96
  """
105
- regscale_vuln = None
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 and asset_match:
117
- regscale_vuln = Vulnerability(
118
- id=0,
119
- scanId=0, # set later
120
- parentId=asset.id,
121
- parentModule="assets",
122
- ipAddress="0.0.0.0", # No ip address available
123
- lastSeen=get_current_datetime(),
124
- firstSeen=self.determine_first_seen(dat),
125
- daysOpen=None,
126
- dns=hostname,
127
- mitigated=None,
128
- operatingSystem=None,
129
- severity=severity,
130
- plugInName=description,
131
- cve=", ".join(cves) if cves else self.mapping.get_value(dat, self.vuln_title),
132
- vprScore=None,
133
- cvsSv3BaseScore=cvss_v3_score,
134
- tenantsId=0,
135
- title=f"{description} on asset {asset.name}",
136
- description=description,
137
- plugInText=self.mapping.get_value(dat, self.vuln_title),
138
- createdById=config["userId"],
139
- lastUpdatedById=config["userId"],
140
- dateCreated=get_current_datetime(),
141
- extra_data={"solution": solution},
142
- )
143
- return regscale_vuln
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