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.
- regscale/_version.py +1 -1
- regscale/core/app/application.py +12 -5
- regscale/core/app/internal/set_permissions.py +58 -27
- regscale/integrations/commercial/defender.py +9 -0
- 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/commercial/wizv2/async_client.py +325 -0
- regscale/integrations/commercial/wizv2/constants.py +756 -0
- regscale/integrations/commercial/wizv2/scanner.py +1301 -89
- regscale/integrations/commercial/wizv2/utils.py +280 -36
- regscale/integrations/commercial/wizv2/variables.py +2 -10
- regscale/integrations/integration_override.py +15 -6
- regscale/integrations/scanner_integration.py +221 -37
- regscale/integrations/variables.py +1 -0
- 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/__init__.py +13 -0
- regscale/models/regscale_models/classification.py +23 -0
- regscale/models/regscale_models/control_implementation.py +14 -12
- regscale/models/regscale_models/cryptography.py +56 -0
- regscale/models/regscale_models/deviation.py +4 -4
- regscale/models/regscale_models/group.py +3 -2
- regscale/models/regscale_models/interconnection.py +1 -1
- regscale/models/regscale_models/issue.py +140 -41
- regscale/models/regscale_models/milestone.py +40 -0
- regscale/models/regscale_models/property.py +0 -1
- regscale/models/regscale_models/rbac.py +22 -0
- regscale/models/regscale_models/regscale_model.py +29 -18
- regscale/models/regscale_models/team.py +55 -0
- {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/RECORD +56 -49
- 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_property_and_milestone_creation.py +684 -0
- tests/regscale/integrations/test_update_finding_dates.py +336 -0
- tests/regscale/models/test_asset.py +406 -50
- tests/regscale/models/test_report.py +105 -29
- {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/top_level.txt +0 -0
|
@@ -2,8 +2,8 @@ from typing import List, Optional, Union
|
|
|
2
2
|
|
|
3
3
|
from regscale.core.app.logz import create_logger
|
|
4
4
|
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
5
|
-
from regscale.integrations.scanner_integration import IntegrationFinding
|
|
6
|
-
from regscale.models import Asset,
|
|
5
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
6
|
+
from regscale.models import Asset, ImportValidater, IssueStatus, Vulnerability
|
|
7
7
|
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
8
8
|
|
|
9
9
|
APP_NAME = "@app_name"
|
|
@@ -77,31 +77,26 @@ class Veracode(FlatFileImporter):
|
|
|
77
77
|
else:
|
|
78
78
|
name = self.mapping.get_value(dat, "Source", "")
|
|
79
79
|
account_id = str(self.mapping.get_value(dat, "ID", ""))
|
|
80
|
-
asset =
|
|
80
|
+
asset = IntegrationAsset(
|
|
81
81
|
**{
|
|
82
|
-
"id": 0,
|
|
83
82
|
"name": name,
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
83
|
+
"ip_address": "0.0.0.0",
|
|
84
|
+
"identifier": name,
|
|
85
|
+
"other_tracking_number": account_id,
|
|
87
86
|
"status": "Active (On Network)",
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"softwareVendor": "Veracode",
|
|
95
|
-
"softwareName": name,
|
|
96
|
-
"softwareVersion": version,
|
|
97
|
-
"systemAdministratorId": self.config["userId"],
|
|
98
|
-
"parentId": self.attributes.parent_id,
|
|
99
|
-
"parentModule": self.attributes.parent_module,
|
|
87
|
+
"asset_category": "Hardware",
|
|
88
|
+
"software_vendor": "Veracode",
|
|
89
|
+
"software_name": name,
|
|
90
|
+
"software_version": version,
|
|
91
|
+
"asset_type": "Other",
|
|
92
|
+
"scanning_tool": self.name,
|
|
100
93
|
}
|
|
101
94
|
)
|
|
102
95
|
return [asset]
|
|
103
96
|
|
|
104
|
-
def create_vuln(
|
|
97
|
+
def create_vuln(
|
|
98
|
+
self, dat: Optional[dict] = None, **kwargs
|
|
99
|
+
) -> Union[List[IntegrationFinding], List[IntegrationFinding]]:
|
|
105
100
|
"""
|
|
106
101
|
Create a RegScale vulnerability from a vulnerability in the Veracode export file
|
|
107
102
|
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
JFrog Xray Scan information
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import logging
|
|
6
|
+
import traceback
|
|
7
|
+
from typing import Callable, Iterator, Optional
|
|
6
8
|
|
|
7
9
|
from regscale.core.app.application import Application
|
|
8
10
|
from regscale.core.app.logz import create_logger
|
|
9
|
-
from regscale.core.app.utils.app_utils import epoch_to_datetime, get_current_datetime
|
|
10
|
-
from regscale.
|
|
11
|
+
from regscale.core.app.utils.app_utils import epoch_to_datetime, get_current_datetime, is_valid_fqdn
|
|
12
|
+
from regscale.exceptions import ValidationException
|
|
13
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
14
|
+
from regscale.models import ImportValidater
|
|
11
15
|
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
12
|
-
from regscale.models.regscale_models
|
|
13
|
-
|
|
16
|
+
from regscale.models.regscale_models import IssueStatus, Vulnerability
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
class XRay(FlatFileImporter):
|
|
@@ -25,31 +30,46 @@ class XRay(FlatFileImporter):
|
|
|
25
30
|
def __init__(self, **kwargs):
|
|
26
31
|
self.name = kwargs.get("name")
|
|
27
32
|
regscale_ssp_id = kwargs.get("regscale_ssp_id")
|
|
28
|
-
|
|
29
|
-
self.
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
# Combine related attributes to reduce instance attribute count
|
|
34
|
+
self.scanner_config = {
|
|
35
|
+
"cvss3_score": "cvss_v3_score",
|
|
36
|
+
"vuln_title": "cve",
|
|
37
|
+
"required_headers": ["impacted_artifact"],
|
|
38
|
+
}
|
|
39
|
+
# Combine mapping-related attributes
|
|
40
|
+
self.mapping_config = {
|
|
41
|
+
"mapping_file": kwargs.get("mappings_path"),
|
|
42
|
+
"disable_mapping": kwargs.get("disable_mapping"),
|
|
43
|
+
}
|
|
35
44
|
self.validater = ImportValidater(
|
|
36
|
-
self.required_headers
|
|
45
|
+
self.scanner_config["required_headers"],
|
|
46
|
+
kwargs.get("file_path"),
|
|
47
|
+
self.mapping_config["mapping_file"],
|
|
48
|
+
self.mapping_config["disable_mapping"],
|
|
37
49
|
)
|
|
38
50
|
self.headers = self.validater.parsed_headers
|
|
39
51
|
self.mapping = self.validater.mapping
|
|
40
|
-
|
|
52
|
+
xray_logger = create_logger()
|
|
53
|
+
# set vuln count and asset count in constructor
|
|
54
|
+
vuln_count = 0
|
|
55
|
+
asset_count = 0
|
|
56
|
+
for dat in self.validater.data:
|
|
57
|
+
vuln_count += len(self.mapping.get_value(dat, "cves", []))
|
|
58
|
+
asset_count += 1
|
|
41
59
|
super().__init__(
|
|
42
|
-
logger=
|
|
60
|
+
logger=xray_logger,
|
|
43
61
|
app=Application(),
|
|
44
62
|
headers=None,
|
|
45
63
|
parent_id=regscale_ssp_id,
|
|
46
64
|
parent_module="securityplans",
|
|
47
65
|
asset_func=self.create_asset,
|
|
48
66
|
vuln_func=self.create_vuln,
|
|
67
|
+
vuln_count=vuln_count,
|
|
68
|
+
asset_count=asset_count,
|
|
49
69
|
**kwargs,
|
|
50
70
|
)
|
|
51
71
|
|
|
52
|
-
def create_asset(self, dat: Optional[dict] = None) -> Optional[
|
|
72
|
+
def create_asset(self, dat: Optional[dict] = None) -> Optional[IntegrationAsset]:
|
|
53
73
|
"""
|
|
54
74
|
Create an asset from a row in the Xray JSON file
|
|
55
75
|
|
|
@@ -59,77 +79,251 @@ class XRay(FlatFileImporter):
|
|
|
59
79
|
"""
|
|
60
80
|
|
|
61
81
|
if asset_name := self.mapping.get_value(dat, "impacted_artifact") if isinstance(dat, dict) else dat:
|
|
62
|
-
return
|
|
82
|
+
return IntegrationAsset(
|
|
63
83
|
**{
|
|
64
|
-
"id": 0,
|
|
65
84
|
"name": asset_name,
|
|
66
|
-
"
|
|
67
|
-
"
|
|
85
|
+
"ip_address": "0.0.0.0",
|
|
86
|
+
"identifier": asset_name,
|
|
87
|
+
"other_tracking_number": asset_name,
|
|
68
88
|
"status": "Active (On Network)",
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"assetType": "Other",
|
|
75
|
-
"fqdn": None,
|
|
76
|
-
"operatingSystem": "Linux",
|
|
77
|
-
"systemAdministratorId": self.config["userId"],
|
|
78
|
-
"parentId": self.attributes.parent_id,
|
|
79
|
-
"parentModule": self.attributes.parent_module,
|
|
89
|
+
"asset_category": "Hardware",
|
|
90
|
+
"asset_type": "Other",
|
|
91
|
+
"scanning_tool": self.name,
|
|
92
|
+
"fqdn": asset_name if is_valid_fqdn(asset_name) else None,
|
|
93
|
+
"operating_system": "Linux",
|
|
80
94
|
}
|
|
81
95
|
)
|
|
82
96
|
return None
|
|
83
97
|
|
|
84
|
-
def
|
|
98
|
+
def create_asset_from_name(self, asset_name: str) -> IntegrationAsset:
|
|
99
|
+
"""Create an IntegrationAsset from an asset name
|
|
100
|
+
|
|
101
|
+
:param str asset_name: The name of the asset
|
|
102
|
+
:return: IntegrationAsset object
|
|
103
|
+
:rtype: IntegrationAsset
|
|
85
104
|
"""
|
|
86
|
-
|
|
105
|
+
return IntegrationAsset(
|
|
106
|
+
**{
|
|
107
|
+
"name": asset_name,
|
|
108
|
+
"ip_address": "0.0.0.0",
|
|
109
|
+
"identifier": asset_name,
|
|
110
|
+
"other_tracking_number": asset_name,
|
|
111
|
+
"status": "Active (On Network)",
|
|
112
|
+
"asset_category": "Hardware",
|
|
113
|
+
"asset_type": "Other",
|
|
114
|
+
"scanning_tool": self.name,
|
|
115
|
+
"fqdn": asset_name if is_valid_fqdn(asset_name) else None,
|
|
116
|
+
"operating_system": "Linux",
|
|
117
|
+
}
|
|
118
|
+
)
|
|
87
119
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
120
|
+
def _extract_asset_name(self, data_item) -> Optional[str]:
|
|
121
|
+
"""Extract asset name from data item
|
|
122
|
+
|
|
123
|
+
:param data_item: Data item to extract asset name from
|
|
124
|
+
:return: Asset name if found, None otherwise
|
|
125
|
+
:rtype: Optional[str]
|
|
126
|
+
"""
|
|
127
|
+
if isinstance(data_item, dict):
|
|
128
|
+
return self.mapping.get_value(data_item, "impacted_artifact")
|
|
129
|
+
return data_item if data_item else None
|
|
130
|
+
|
|
131
|
+
def _process_list_data(self) -> Iterator[IntegrationAsset]:
|
|
132
|
+
"""Process list data and yield assets
|
|
133
|
+
|
|
134
|
+
:return: Iterator of IntegrationAsset objects
|
|
135
|
+
:rtype: Iterator[IntegrationAsset]
|
|
136
|
+
"""
|
|
137
|
+
for data_item in self.file_data:
|
|
138
|
+
if asset_name := self._extract_asset_name(data_item):
|
|
139
|
+
yield self.create_asset_from_name(asset_name)
|
|
140
|
+
|
|
141
|
+
def _process_dict_data(self) -> Iterator[IntegrationAsset]:
|
|
142
|
+
"""Process dict data and yield assets
|
|
143
|
+
|
|
144
|
+
:return: Iterator of IntegrationAsset objects
|
|
145
|
+
:rtype: Iterator[IntegrationAsset]
|
|
146
|
+
"""
|
|
147
|
+
if asset_name := self._extract_asset_name(self.file_data):
|
|
148
|
+
yield self.create_asset_from_name(asset_name)
|
|
149
|
+
|
|
150
|
+
def asset_generator(self) -> Iterator[IntegrationAsset]:
|
|
151
|
+
"""Generate IntegrationAsset objects from the data
|
|
152
|
+
|
|
153
|
+
:return: Iterator of IntegrationAsset objects
|
|
154
|
+
:rtype: Iterator[IntegrationAsset]
|
|
155
|
+
"""
|
|
156
|
+
if isinstance(self.file_data, list):
|
|
157
|
+
yield from self._process_list_data()
|
|
158
|
+
elif isinstance(self.file_data, dict):
|
|
159
|
+
yield from self._process_dict_data()
|
|
160
|
+
|
|
161
|
+
def process_assets(self, func: Callable) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Process the assets in the data and create an iterator of IntegrationAsset objects
|
|
164
|
+
|
|
165
|
+
:param Callable func: Function to create asset (not used)
|
|
166
|
+
:return: None
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
# Set the assets as an iterator directly
|
|
170
|
+
self.data["assets"] = self.asset_generator()
|
|
171
|
+
self.integration_assets = self.data["assets"]
|
|
172
|
+
|
|
173
|
+
def create_vuln(self, _dat: Optional[dict] = None, **kwargs) -> Iterator[IntegrationFinding]:
|
|
174
|
+
"""
|
|
175
|
+
Fetches findings from the processed json files
|
|
176
|
+
|
|
177
|
+
:param Optional[dict] _dat: Data row from JSON file (unused, kept for compatibility)
|
|
178
|
+
:param **kwargs: Additional keyword arguments including index
|
|
179
|
+
:return: A list of findings
|
|
180
|
+
:rtype: Iterator[IntegrationFinding]
|
|
181
|
+
"""
|
|
182
|
+
if findings := self.fetch_findings(**kwargs):
|
|
183
|
+
yield from findings
|
|
184
|
+
|
|
185
|
+
def _validate_cve_data(self, cve_data) -> bool:
|
|
186
|
+
"""Validate CVE data structure
|
|
187
|
+
|
|
188
|
+
:param cve_data: CVE data to validate
|
|
189
|
+
:return: True if valid, False otherwise
|
|
190
|
+
:rtype: bool
|
|
191
|
+
"""
|
|
192
|
+
if not isinstance(cve_data, list):
|
|
193
|
+
logger.warning("CVE data is not a list, skipping vulnerability creation")
|
|
194
|
+
return False
|
|
195
|
+
return True
|
|
196
|
+
|
|
197
|
+
def _get_valid_cve_data(self, cve_data: list) -> list:
|
|
198
|
+
"""Filter CVE data to only include valid entries
|
|
199
|
+
|
|
200
|
+
:param list cve_data: Raw CVE data
|
|
201
|
+
:return: Filtered CVE data with actual CVE IDs
|
|
202
|
+
:rtype: list
|
|
203
|
+
"""
|
|
204
|
+
return [c for c in cve_data if c.get("cve")]
|
|
205
|
+
|
|
206
|
+
def _determine_severity_from_cve(self, cve_dat: dict) -> str:
|
|
207
|
+
"""Determine severity from CVE data
|
|
208
|
+
|
|
209
|
+
:param dict cve_dat: CVE data dictionary
|
|
210
|
+
:return: Severity string
|
|
211
|
+
:rtype: str
|
|
212
|
+
"""
|
|
213
|
+
cvss3_score = cve_dat.get("cvss_v3_score", 0.0)
|
|
214
|
+
if cve_dat.get(self.scanner_config["cvss3_score"]):
|
|
215
|
+
return Vulnerability.determine_cvss3_severity_text(float(cvss3_score))
|
|
216
|
+
return "low"
|
|
217
|
+
|
|
218
|
+
def _extract_plugin_id(self, data_item: dict) -> int:
|
|
219
|
+
"""Extract plugin ID from issue ID
|
|
220
|
+
|
|
221
|
+
:param dict data_item: Data item containing issue information
|
|
222
|
+
:return: Plugin ID as integer
|
|
223
|
+
:rtype: int
|
|
224
|
+
"""
|
|
225
|
+
issue_id = self.mapping.get_value(data_item, "issue_id", "Xray-0000")
|
|
226
|
+
try:
|
|
227
|
+
if len(issue_id) > 5:
|
|
228
|
+
return int(issue_id[5:])
|
|
229
|
+
return 0
|
|
230
|
+
except (ValueError, TypeError):
|
|
231
|
+
logger.warning("Could not parse plugin_id from issue_id: %s", issue_id)
|
|
232
|
+
return 0
|
|
233
|
+
|
|
234
|
+
def _get_title_base(self, data_item: dict) -> str:
|
|
235
|
+
"""Get title base for the finding
|
|
236
|
+
|
|
237
|
+
:param dict data_item: Data item containing issue information
|
|
238
|
+
:return: Title base string
|
|
239
|
+
:rtype: str
|
|
240
|
+
"""
|
|
241
|
+
return self.mapping.get_value(data_item, "issue_id") or self.mapping.get_value(
|
|
242
|
+
data_item, "summary", f"XRay Vulnerability from Import {get_current_datetime()}"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
def _create_finding_from_cve(self, data_item: dict, asset_name: str, cve_dat: dict) -> IntegrationFinding:
|
|
246
|
+
"""Create a single finding from CVE data
|
|
247
|
+
|
|
248
|
+
:param dict data_item: Data item containing vulnerability information
|
|
249
|
+
:param str asset_name: Asset name for the finding
|
|
250
|
+
:param dict cve_dat: CVE data dictionary
|
|
251
|
+
:return: IntegrationFinding object
|
|
252
|
+
:rtype: IntegrationFinding
|
|
253
|
+
"""
|
|
254
|
+
cve = cve_dat.get("cve")
|
|
255
|
+
cvss3_score = cve_dat.get("cvss_v3_score", 0.0)
|
|
256
|
+
severity = self._determine_severity_from_cve(cve_dat)
|
|
257
|
+
plugin_id = self._extract_plugin_id(data_item)
|
|
258
|
+
title_base = self._get_title_base(data_item)
|
|
259
|
+
|
|
260
|
+
return IntegrationFinding(
|
|
261
|
+
title=f"{title_base} on asset {asset_name}",
|
|
262
|
+
description=self.mapping.get_value(data_item, "summary"),
|
|
263
|
+
severity=self.determine_severity(severity),
|
|
264
|
+
status=IssueStatus.Open.value,
|
|
265
|
+
cvss_v3_score=cvss3_score,
|
|
266
|
+
cvss_v3_vector=cve_dat.get("cvss_v3_vector", ""),
|
|
267
|
+
plugin_name=self.mapping.get_value(data_item, "issue_id", "XRay"),
|
|
268
|
+
plugin_id=plugin_id,
|
|
269
|
+
asset_identifier=asset_name,
|
|
270
|
+
cve=cve,
|
|
271
|
+
first_seen=epoch_to_datetime(self.create_epoch),
|
|
272
|
+
last_seen=self.scan_date,
|
|
273
|
+
scan_date=self.scan_date,
|
|
274
|
+
category="Software",
|
|
275
|
+
control_labels=[],
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
def _create_findings_from_data_item(self, data_item: dict, asset_name: str) -> Iterator[IntegrationFinding]:
|
|
279
|
+
"""Create findings from a single data item
|
|
280
|
+
|
|
281
|
+
:param dict data_item: The data item containing vulnerability information
|
|
282
|
+
:param str asset_name: The asset name for the finding
|
|
283
|
+
:yields: IntegrationFinding objects
|
|
284
|
+
"""
|
|
285
|
+
cve_data = self.mapping.get_value(data_item, "cves", [])
|
|
286
|
+
if not self._validate_cve_data(cve_data):
|
|
287
|
+
return
|
|
288
|
+
|
|
289
|
+
valid_cve_data = self._get_valid_cve_data(cve_data)
|
|
290
|
+
for cve_dat in valid_cve_data:
|
|
291
|
+
yield self._create_finding_from_cve(data_item, asset_name, cve_dat)
|
|
292
|
+
|
|
293
|
+
def _process_list_findings(self) -> Iterator[IntegrationFinding]:
|
|
294
|
+
"""Process findings from list data
|
|
295
|
+
|
|
296
|
+
:yields: IntegrationFinding objects
|
|
297
|
+
"""
|
|
298
|
+
for data_item in self.file_data:
|
|
299
|
+
if isinstance(data_item, list):
|
|
300
|
+
continue
|
|
301
|
+
asset_name = self._extract_asset_name(data_item)
|
|
302
|
+
if asset_name:
|
|
303
|
+
yield from self._create_findings_from_data_item(data_item, asset_name)
|
|
304
|
+
|
|
305
|
+
def _process_dict_findings(self) -> Iterator[IntegrationFinding]:
|
|
306
|
+
"""Process findings from dict data
|
|
307
|
+
|
|
308
|
+
:yields: IntegrationFinding objects
|
|
309
|
+
"""
|
|
310
|
+
asset_name = self._extract_asset_name(self.file_data)
|
|
311
|
+
if asset_name:
|
|
312
|
+
yield from self._create_findings_from_data_item(self.file_data, asset_name)
|
|
313
|
+
|
|
314
|
+
def fetch_findings(self, **_) -> Iterator[IntegrationFinding]:
|
|
315
|
+
"""
|
|
316
|
+
Fetch findings from Xray scan data.
|
|
317
|
+
|
|
318
|
+
:raises ValidationException: If there is an error fetching/parsing findings
|
|
319
|
+
:yields: Iterator[IntegrationFinding]
|
|
320
|
+
"""
|
|
321
|
+
try:
|
|
322
|
+
if isinstance(self.file_data, list):
|
|
323
|
+
yield from self._process_list_findings()
|
|
324
|
+
elif isinstance(self.file_data, dict):
|
|
325
|
+
yield from self._process_dict_findings()
|
|
326
|
+
except Exception as exc:
|
|
327
|
+
error_message = traceback.format_exc()
|
|
328
|
+
logger.error("Error fetching findings: %s", error_message)
|
|
329
|
+
raise ValidationException(f"Error fetching findings: {error_message}") from exc
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""RegScale models."""
|
|
2
2
|
|
|
3
3
|
from .assessment_plan import *
|
|
4
|
+
from .assessment_result import *
|
|
4
5
|
from .assessment import *
|
|
5
6
|
from .asset import *
|
|
6
7
|
from .asset_mapping import *
|
|
@@ -10,6 +11,7 @@ from .case import *
|
|
|
10
11
|
from .cci import *
|
|
11
12
|
from .change import *
|
|
12
13
|
from .checklist import *
|
|
14
|
+
from .classification import *
|
|
13
15
|
from .comment import *
|
|
14
16
|
from .compliance_settings import *
|
|
15
17
|
from .component import *
|
|
@@ -21,23 +23,32 @@ from .control_parameter import *
|
|
|
21
23
|
from .control_test import *
|
|
22
24
|
from .control_test_plan import *
|
|
23
25
|
from .control_test_result import *
|
|
26
|
+
from .cryptography import *
|
|
24
27
|
from .custom_field import *
|
|
25
28
|
from .data import *
|
|
26
29
|
from .data_center import *
|
|
30
|
+
from .deviation import *
|
|
27
31
|
from .email import *
|
|
28
32
|
from .evidence import *
|
|
29
33
|
from .evidence_mapping import *
|
|
30
34
|
from .facility import *
|
|
31
35
|
from .file import *
|
|
36
|
+
from .filetag import *
|
|
37
|
+
from .form_field_value import *
|
|
38
|
+
from .functional_roles import *
|
|
39
|
+
from .group import *
|
|
32
40
|
from .implementation_objective import *
|
|
33
41
|
from .implementation_option import *
|
|
42
|
+
from .implementation_role import *
|
|
34
43
|
from .incident import *
|
|
35
44
|
from .inherited_control import *
|
|
36
45
|
from .interconnection import *
|
|
37
46
|
from .issue import *
|
|
38
47
|
from .leveraged_authorization import *
|
|
48
|
+
from .line_of_inquiry import *
|
|
39
49
|
from .link import *
|
|
40
50
|
from .master_assessment import *
|
|
51
|
+
from .milestone import *
|
|
41
52
|
from .meta_data import *
|
|
42
53
|
from .objective import *
|
|
43
54
|
from .parameter import *
|
|
@@ -52,6 +63,7 @@ from .property import *
|
|
|
52
63
|
from .question import *
|
|
53
64
|
from .questionnaire import *
|
|
54
65
|
from .questionnaire_instance import *
|
|
66
|
+
from .rbac import *
|
|
55
67
|
from .reference import *
|
|
56
68
|
from .requirement import *
|
|
57
69
|
from .risk import *
|
|
@@ -69,6 +81,7 @@ from .system_role import *
|
|
|
69
81
|
from .system_role_external_assignment import *
|
|
70
82
|
from .task import *
|
|
71
83
|
from .threat import *
|
|
84
|
+
from .team import *
|
|
72
85
|
from .user import *
|
|
73
86
|
from .vulnerability import *
|
|
74
87
|
from .vulnerability_mapping import *
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Model for Classification Records in the application"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Union
|
|
6
|
+
|
|
7
|
+
from pydantic import ConfigDict
|
|
8
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ClassifiedRecord(RegScaleModel):
|
|
12
|
+
_module_slug = "classifiedRecords"
|
|
13
|
+
|
|
14
|
+
id: Optional[int] = None
|
|
15
|
+
parentRecordId: Optional[int] = 0
|
|
16
|
+
parentModule: Optional[str] = None
|
|
17
|
+
classificationTypeId: Optional[int] = 0
|
|
18
|
+
adjustedConfidentiality: Optional[str] = None
|
|
19
|
+
confidentialityJustification: Optional[str] = None
|
|
20
|
+
adjustedAvailability: Optional[str] = None
|
|
21
|
+
availabilityJustification: Optional[str] = None
|
|
22
|
+
adjustedIntegrity: Optional[str] = None
|
|
23
|
+
integrityJustification: Optional[str] = None
|
|
@@ -70,6 +70,7 @@ class ControlImplementation(RegScaleModel):
|
|
|
70
70
|
|
|
71
71
|
_module_slug = "controlImplementation"
|
|
72
72
|
_module_string = "controls"
|
|
73
|
+
_unique_fields = [["controlID", "parentId", "parentModule"]]
|
|
73
74
|
_get_objects_for_list = True
|
|
74
75
|
|
|
75
76
|
controlOwnerId: str = Field(default_factory=RegScaleModel.get_user_id)
|
|
@@ -248,18 +249,19 @@ class ControlImplementation(RegScaleModel):
|
|
|
248
249
|
return response.json()
|
|
249
250
|
return None
|
|
250
251
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
252
|
+
# Removed for now, will need to be added back once platform changes are made
|
|
253
|
+
# def find_by_unique(self, **kwargs: dict) -> Optional["ControlImplementation"]:
|
|
254
|
+
# """
|
|
255
|
+
# Find an object by unique query.
|
|
256
|
+
#
|
|
257
|
+
# :param dict **kwargs: The unique query parameters
|
|
258
|
+
# :return: The object or None if not found
|
|
259
|
+
# :rtype: Optional[ControlImplementation]
|
|
260
|
+
# """
|
|
261
|
+
#
|
|
262
|
+
# for instance in self.get_by_security_control_id(security_control_id=self.controlID):
|
|
263
|
+
# return instance
|
|
264
|
+
# return None
|
|
263
265
|
|
|
264
266
|
def _get_status_enum(self) -> List["ControlImplementationStatus"]:
|
|
265
267
|
"""
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Model for Cryptography in the application"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from pydantic import ConfigDict, Field
|
|
8
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
9
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Cryptography(RegScaleModel):
|
|
13
|
+
_module_slug = "cryptography"
|
|
14
|
+
|
|
15
|
+
id: Optional[int] = None
|
|
16
|
+
cryptographyType: str
|
|
17
|
+
sourceArea: Optional[str] = None
|
|
18
|
+
sourceVendorName: Optional[str] = None
|
|
19
|
+
sourceModule: Optional[str] = None
|
|
20
|
+
fipsNumber: Optional[str] = None
|
|
21
|
+
bSourceEmbedded: Optional[bool] = False
|
|
22
|
+
bSourceThirdParty: Optional[bool] = False
|
|
23
|
+
bSourceOS: Optional[bool] = False
|
|
24
|
+
bSourceFIPS: Optional[bool] = False
|
|
25
|
+
bSourceOther: Optional[bool] = False
|
|
26
|
+
sourceExplanationOther: Optional[str] = None
|
|
27
|
+
destinationArea: Optional[str] = None
|
|
28
|
+
destinationVendorName: Optional[str] = None
|
|
29
|
+
destinationModule: Optional[str] = None
|
|
30
|
+
bDestinationEmbedded: Optional[bool] = False
|
|
31
|
+
bDestinationThirdParty: Optional[bool] = False
|
|
32
|
+
bDestinationOS: Optional[bool] = False
|
|
33
|
+
bDestinationFIPS: Optional[bool] = False
|
|
34
|
+
bDestinationOther: Optional[bool] = False
|
|
35
|
+
destinationExplanationOther: Optional[str] = None
|
|
36
|
+
bUsageTLS11: Optional[bool] = False
|
|
37
|
+
bUsageTLS12: Optional[bool] = False
|
|
38
|
+
bUsageTLS13: Optional[bool] = False
|
|
39
|
+
bUsageOther: Optional[bool] = False
|
|
40
|
+
usageExplanationOther: Optional[str] = None
|
|
41
|
+
usage: str
|
|
42
|
+
bRestFullDisk: Optional[bool] = False
|
|
43
|
+
bRestFile: Optional[bool] = False
|
|
44
|
+
bRestRecord: Optional[bool] = False
|
|
45
|
+
bRestNone: Optional[bool] = False
|
|
46
|
+
encryptionExplanationOther: Optional[str] = None
|
|
47
|
+
encryptionType: Optional[str] = None
|
|
48
|
+
notes: Optional[str] = None
|
|
49
|
+
referenceUrl: Optional[str] = None
|
|
50
|
+
isPublic: Optional[bool] = False
|
|
51
|
+
parentId: Optional[int] = 0
|
|
52
|
+
parentModule: Optional[str] = None
|
|
53
|
+
dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
|
|
54
|
+
lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
|
|
55
|
+
dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
|
|
56
|
+
tenantsId: int = 1
|