regscale-cli 6.16.1.0__py3-none-any.whl → 6.16.3.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/__init__.py +1 -1
- regscale/core/app/internal/login.py +1 -1
- regscale/core/app/internal/poam_editor.py +1 -1
- regscale/core/app/utils/api_handler.py +4 -11
- regscale/integrations/commercial/__init__.py +2 -2
- regscale/integrations/commercial/ad.py +1 -1
- regscale/integrations/commercial/crowdstrike.py +0 -1
- regscale/integrations/commercial/grype/__init__.py +3 -0
- regscale/integrations/commercial/grype/commands.py +72 -0
- regscale/integrations/commercial/grype/scanner.py +390 -0
- regscale/integrations/commercial/import_all/import_all_cmd.py +2 -2
- regscale/integrations/commercial/opentext/__init__.py +6 -0
- regscale/integrations/commercial/opentext/commands.py +77 -0
- regscale/integrations/commercial/opentext/scanner.py +449 -85
- regscale/integrations/commercial/qualys.py +50 -61
- regscale/integrations/commercial/servicenow.py +1 -0
- regscale/integrations/commercial/snyk.py +2 -2
- regscale/integrations/commercial/synqly/ticketing.py +29 -0
- regscale/integrations/commercial/trivy/__init__.py +5 -0
- regscale/integrations/commercial/trivy/commands.py +74 -0
- regscale/integrations/commercial/trivy/scanner.py +276 -0
- regscale/integrations/commercial/veracode.py +1 -1
- regscale/integrations/commercial/wizv2/utils.py +1 -1
- regscale/integrations/jsonl_scanner_integration.py +869 -0
- regscale/integrations/public/fedramp/fedramp_common.py +4 -4
- regscale/integrations/public/fedramp/inventory_items.py +3 -3
- regscale/integrations/scanner_integration.py +225 -59
- regscale/models/integration_models/cisa_kev_data.json +65 -7
- regscale/models/integration_models/{flat_file_importer.py → flat_file_importer/__init__.py} +29 -8
- regscale/models/integration_models/snyk.py +141 -15
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/tenable_models/integration.py +42 -7
- regscale/models/integration_models/veracode.py +91 -48
- regscale/models/regscale_models/regscale_model.py +1 -1
- regscale/models/regscale_models/user.py +3 -4
- regscale/models/regscale_models/vulnerability.py +21 -0
- regscale/utils/version.py +3 -5
- {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/METADATA +3 -3
- {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/RECORD +43 -38
- regscale/integrations/commercial/grype.py +0 -165
- regscale/integrations/commercial/opentext/click.py +0 -99
- regscale/integrations/commercial/trivy.py +0 -162
- {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.16.1.0.dist-info → regscale_cli-6.16.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1878,11 +1878,11 @@ def check_control_list_length(ssp_obj: SSP, mapping: dict) -> Optional[list]:
|
|
|
1878
1878
|
return missing_controls
|
|
1879
1879
|
|
|
1880
1880
|
|
|
1881
|
-
def log_controls_info(ssp_obj:
|
|
1881
|
+
def log_controls_info(ssp_obj: SSP, current_imps: List[dict]) -> None:
|
|
1882
1882
|
"""
|
|
1883
1883
|
Log controls info
|
|
1884
1884
|
|
|
1885
|
-
:param
|
|
1885
|
+
:param SSP ssp_obj: SSP object
|
|
1886
1886
|
:param List[dict] current_imps: List of current implementations
|
|
1887
1887
|
:return None:
|
|
1888
1888
|
:rtype None:
|
|
@@ -2305,8 +2305,8 @@ def fetch_existing_stakeholders(api: Api, config: dict, regscale_ssp: dict) -> l
|
|
|
2305
2305
|
if response.ok:
|
|
2306
2306
|
logger.info(
|
|
2307
2307
|
f"Found {len(response.json())} existing stakeholders",
|
|
2308
|
-
record_type="
|
|
2309
|
-
model_layer="
|
|
2308
|
+
record_type="stakeholders",
|
|
2309
|
+
model_layer="stakeholders",
|
|
2310
2310
|
)
|
|
2311
2311
|
return response.json()
|
|
2312
2312
|
return []
|
|
@@ -59,7 +59,7 @@ def get_dict_value(outer_key: str, inner_key: str, source_dict: Dict) -> Optiona
|
|
|
59
59
|
outer_dict = source_dict.get(outer_key, None)
|
|
60
60
|
if outer_dict is not None and isinstance(outer_dict, dict):
|
|
61
61
|
val = outer_dict.get(inner_key, None)
|
|
62
|
-
logger.
|
|
62
|
+
logger.debug(f"{val=}")
|
|
63
63
|
return val
|
|
64
64
|
return None
|
|
65
65
|
|
|
@@ -205,8 +205,8 @@ def parse_inventory_items(trv: FedrampTraversal, components_dict: Dict):
|
|
|
205
205
|
|
|
206
206
|
for imp_component in implemented_components:
|
|
207
207
|
if not isinstance(components_dict, dict):
|
|
208
|
-
logger.
|
|
209
|
-
logger.info("
|
|
208
|
+
logger.debug(components_dict)
|
|
209
|
+
logger.info("Components do not exist yet.")
|
|
210
210
|
continue
|
|
211
211
|
comp = components_dict.get(imp_component.get("component_uuid"))
|
|
212
212
|
comp_id = comp.get("id") if comp else None
|
|
@@ -9,12 +9,12 @@ import enum
|
|
|
9
9
|
import hashlib
|
|
10
10
|
import json
|
|
11
11
|
import logging
|
|
12
|
-
import re
|
|
13
12
|
import threading
|
|
14
13
|
import time
|
|
15
14
|
from abc import ABC, abstractmethod
|
|
16
15
|
from collections import defaultdict
|
|
17
|
-
from
|
|
16
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
17
|
+
from typing import Any, Dict, Generic, Iterator, List, Optional, Set, TypeVar, Union, Callable
|
|
18
18
|
|
|
19
19
|
from rich.progress import Progress, TaskID
|
|
20
20
|
|
|
@@ -269,6 +269,10 @@ class IntegrationAsset:
|
|
|
269
269
|
other_cloud_identifier: Optional[str] = None
|
|
270
270
|
patch_level: Optional[str] = None
|
|
271
271
|
cpe: Optional[str] = None
|
|
272
|
+
is_latest_scan: Optional[bool] = None
|
|
273
|
+
is_authenticated_scan: Optional[bool] = None
|
|
274
|
+
system_administrator_id: Optional[str] = None
|
|
275
|
+
scanning_tool: Optional[str] = None
|
|
272
276
|
|
|
273
277
|
source_data: Optional[Dict[str, Any]] = None
|
|
274
278
|
url: Optional[str] = None
|
|
@@ -345,6 +349,15 @@ class IntegrationFinding:
|
|
|
345
349
|
:param Optional[str] remediation: The remediation of the finding, defaults to None.
|
|
346
350
|
:param Optional[str] source_rule_id: The source rule ID of the finding, defaults to None.
|
|
347
351
|
:param Optional[str] poam_id: The POAM ID of the finding, defaults to None.
|
|
352
|
+
:param Optional[str] cvss_v3_vector: The CVSS v3 vector of the finding, defaults to None.
|
|
353
|
+
:param Optional[str] cvss_v2_vector: The CVSS v2 vector of the finding, defaults to None.
|
|
354
|
+
:param Optional[str] affected_os: The affected OS of the finding, defaults to None.
|
|
355
|
+
:param Optional[str] image_digest: The image digest of the finding, defaults to None.
|
|
356
|
+
:param Optional[str] affected_packages: The affected packages of the finding, defaults to None.
|
|
357
|
+
:param Optional[str] installed_versions: The installed versions of the finding, defaults to None.
|
|
358
|
+
:param Optional[str] fixed_versions: The fixed versions of the finding, defaults to None.
|
|
359
|
+
:param Optional[str] fix_status: The fix status of the finding, defaults to None.
|
|
360
|
+
:param Optional[str] build_version: The build version of the finding, defaults to None.
|
|
348
361
|
"""
|
|
349
362
|
|
|
350
363
|
control_labels: List[str]
|
|
@@ -364,9 +377,20 @@ class IntegrationFinding:
|
|
|
364
377
|
cvss_v2_score: Optional[float] = None
|
|
365
378
|
ip_address: Optional[str] = None
|
|
366
379
|
plugin_id: Optional[str] = None
|
|
380
|
+
plugin_text: Optional[str] = None
|
|
367
381
|
dns: Optional[str] = None
|
|
368
382
|
severity_int: int = 0
|
|
369
383
|
security_check: Optional[str] = None
|
|
384
|
+
cvss_v3_vector: Optional[str] = None
|
|
385
|
+
cvss_v2_vector: Optional[str] = None
|
|
386
|
+
affected_os: Optional[str] = None
|
|
387
|
+
package_path: Optional[str] = None
|
|
388
|
+
image_digest: Optional[str] = None
|
|
389
|
+
affected_packages: Optional[str] = None
|
|
390
|
+
installed_versions: Optional[str] = None
|
|
391
|
+
fixed_versions: Optional[str] = None
|
|
392
|
+
fix_status: Optional[str] = None
|
|
393
|
+
build_version: Optional[str] = None
|
|
370
394
|
|
|
371
395
|
# Issues
|
|
372
396
|
issue_title: str = ""
|
|
@@ -391,6 +415,7 @@ class IntegrationFinding:
|
|
|
391
415
|
risk_adjustment: str = "No"
|
|
392
416
|
operational_requirements: Optional[str] = None
|
|
393
417
|
deviation_rationale: Optional[str] = None
|
|
418
|
+
is_cwe: bool = False
|
|
394
419
|
|
|
395
420
|
poam_comments: Optional[str] = None
|
|
396
421
|
vulnerability_id: Optional[int] = None
|
|
@@ -1048,6 +1073,10 @@ class ScannerIntegration(ABC):
|
|
|
1048
1073
|
softwareVersion=asset.software_version,
|
|
1049
1074
|
softwareName=asset.software_name,
|
|
1050
1075
|
softwareVendor=asset.software_vendor,
|
|
1076
|
+
bLatestScan=asset.is_latest_scan,
|
|
1077
|
+
bAuthenticatedScan=asset.is_authenticated_scan,
|
|
1078
|
+
systemAdministratorId=asset.system_administrator_id,
|
|
1079
|
+
scanningTool=asset.scanning_tool,
|
|
1051
1080
|
)
|
|
1052
1081
|
if self.asset_identifier_field:
|
|
1053
1082
|
setattr(new_asset, self.asset_identifier_field, asset.identifier)
|
|
@@ -1211,34 +1240,126 @@ class ScannerIntegration(ABC):
|
|
|
1211
1240
|
|
|
1212
1241
|
def _process_assets(self, assets: Iterator[IntegrationAsset], loading_assets: TaskID) -> int:
|
|
1213
1242
|
"""
|
|
1214
|
-
|
|
1243
|
+
Process assets using single or multi-threaded approach based on THREAD_MAX_WORKERS.
|
|
1215
1244
|
|
|
1216
|
-
:param Iterator[IntegrationAsset] assets:
|
|
1217
|
-
:param TaskID loading_assets:
|
|
1218
|
-
:return:
|
|
1245
|
+
:param Iterator[IntegrationAsset] assets: Assets to process
|
|
1246
|
+
:param TaskID loading_assets: Task ID for the progress bar
|
|
1247
|
+
:return: Number of assets processed
|
|
1219
1248
|
:rtype: int
|
|
1220
1249
|
"""
|
|
1221
|
-
|
|
1222
|
-
|
|
1250
|
+
self._prime_asset_cache()
|
|
1251
|
+
process_func = self._create_process_function(loading_assets)
|
|
1252
|
+
max_workers = get_thread_workers_max()
|
|
1253
|
+
|
|
1254
|
+
if max_workers == 1:
|
|
1255
|
+
return self._process_single_threaded(assets, process_func)
|
|
1256
|
+
return self._process_multi_threaded(assets, process_func, max_workers)
|
|
1257
|
+
|
|
1258
|
+
def _prime_asset_cache(self) -> None:
|
|
1259
|
+
"""
|
|
1260
|
+
Prime the asset cache by fetching assets for the given plan.
|
|
1261
|
+
|
|
1262
|
+
:rtype: None
|
|
1263
|
+
"""
|
|
1223
1264
|
regscale_models.Asset.get_all_by_parent(
|
|
1224
1265
|
parent_id=self.plan_id, parent_module=regscale_models.SecurityPlan.get_module_string()
|
|
1225
1266
|
)
|
|
1226
1267
|
|
|
1227
|
-
|
|
1268
|
+
def _create_process_function(self, loading_assets: TaskID) -> Callable[[IntegrationAsset], bool]:
|
|
1269
|
+
"""
|
|
1270
|
+
Create a function to process a single asset.
|
|
1271
|
+
|
|
1272
|
+
:param TaskID loading_assets: Task ID for the progress bar
|
|
1273
|
+
:return: Function that processes an asset and returns success status
|
|
1274
|
+
:rtype: Callable[[IntegrationAsset], bool]
|
|
1275
|
+
"""
|
|
1276
|
+
return lambda asset: self._process_single_asset(asset, loading_assets)
|
|
1277
|
+
|
|
1278
|
+
def _process_single_threaded(
|
|
1279
|
+
self, assets: Iterator[IntegrationAsset], process_func: Callable[[IntegrationAsset], bool]
|
|
1280
|
+
) -> int:
|
|
1281
|
+
"""
|
|
1282
|
+
Process assets sequentially in a single thread.
|
|
1283
|
+
|
|
1284
|
+
:param Iterator[IntegrationAsset] assets: Assets to process
|
|
1285
|
+
:param Callable[[IntegrationAsset], bool] process_func: Function to process each asset
|
|
1286
|
+
:return: Number of assets processed
|
|
1287
|
+
:rtype: int
|
|
1288
|
+
"""
|
|
1289
|
+
assets_processed = 0
|
|
1290
|
+
for asset in assets:
|
|
1291
|
+
if process_func(asset):
|
|
1292
|
+
assets_processed = self._update_processed_count(assets_processed)
|
|
1293
|
+
return assets_processed
|
|
1294
|
+
|
|
1295
|
+
def _process_multi_threaded(
|
|
1296
|
+
self, assets: Iterator[IntegrationAsset], process_func: Callable[[IntegrationAsset], bool], max_workers: int
|
|
1297
|
+
) -> int:
|
|
1298
|
+
"""
|
|
1299
|
+
Process assets in batches using multiple threads.
|
|
1300
|
+
|
|
1301
|
+
:param Iterator[IntegrationAsset] assets: Assets to process
|
|
1302
|
+
:param Callable[[IntegrationAsset], bool] process_func: Function to process each asset
|
|
1303
|
+
:param int max_workers: Maximum number of worker threads
|
|
1304
|
+
:return: Number of assets processed
|
|
1305
|
+
:rtype: int
|
|
1306
|
+
"""
|
|
1307
|
+
batch_size = max_workers * 2
|
|
1308
|
+
assets_processed = 0
|
|
1309
|
+
|
|
1310
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
1311
|
+
batch = []
|
|
1312
|
+
futures = []
|
|
1228
1313
|
|
|
1229
|
-
if get_thread_workers_max() == 1:
|
|
1230
1314
|
for asset in assets:
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1315
|
+
batch.append(asset)
|
|
1316
|
+
if len(batch) >= batch_size:
|
|
1317
|
+
assets_processed += self._submit_and_process_batch(executor, process_func, batch, futures)
|
|
1318
|
+
batch = []
|
|
1319
|
+
futures = []
|
|
1320
|
+
|
|
1321
|
+
if batch: # Process any remaining items
|
|
1322
|
+
assets_processed += self._submit_and_process_batch(executor, process_func, batch, futures)
|
|
1323
|
+
|
|
1324
|
+
return assets_processed
|
|
1325
|
+
|
|
1326
|
+
def _submit_and_process_batch(
|
|
1327
|
+
self,
|
|
1328
|
+
executor: ThreadPoolExecutor,
|
|
1329
|
+
process_func: Callable[[IntegrationAsset], bool],
|
|
1330
|
+
batch: List[IntegrationAsset],
|
|
1331
|
+
futures: List,
|
|
1332
|
+
) -> int:
|
|
1333
|
+
"""
|
|
1334
|
+
Submit a batch of assets for processing and count successful completions.
|
|
1335
|
+
|
|
1336
|
+
:param ThreadPoolExecutor executor: Thread pool executor for parallel processing
|
|
1337
|
+
:param Callable[[IntegrationAsset], bool] process_func: Function to process each asset
|
|
1338
|
+
:param List[IntegrationAsset] batch: Batch of assets to process
|
|
1339
|
+
:param List futures: List to store future objects
|
|
1340
|
+
:return: Number of assets processed in this batch
|
|
1341
|
+
:rtype: int
|
|
1342
|
+
"""
|
|
1343
|
+
assets_processed = 0
|
|
1344
|
+
for asset in batch:
|
|
1345
|
+
futures.append(executor.submit(process_func, asset))
|
|
1346
|
+
|
|
1347
|
+
for future in concurrent.futures.as_completed(futures):
|
|
1348
|
+
if future.result():
|
|
1349
|
+
assets_processed = self._update_processed_count(assets_processed)
|
|
1239
1350
|
|
|
1240
1351
|
return assets_processed
|
|
1241
1352
|
|
|
1353
|
+
def _update_processed_count(self, current_count: int) -> int:
|
|
1354
|
+
"""
|
|
1355
|
+
Increment the processed count.
|
|
1356
|
+
|
|
1357
|
+
:param int current_count: Current number of processed items
|
|
1358
|
+
:return: Updated count
|
|
1359
|
+
:rtype: int
|
|
1360
|
+
"""
|
|
1361
|
+
return current_count + 1
|
|
1362
|
+
|
|
1242
1363
|
def _process_single_asset(self, asset: IntegrationAsset, loading_assets: TaskID) -> bool:
|
|
1243
1364
|
"""
|
|
1244
1365
|
Processes a single asset and handles any exceptions.
|
|
@@ -1430,7 +1551,7 @@ class ScannerIntegration(ABC):
|
|
|
1430
1551
|
issue.issueOwnerId = self.assessor_id
|
|
1431
1552
|
issue.securityPlanId = self.plan_id
|
|
1432
1553
|
issue.identification = "Vulnerability Assessment"
|
|
1433
|
-
issue.dateFirstDetected = finding.
|
|
1554
|
+
issue.dateFirstDetected = finding.first_seen
|
|
1434
1555
|
issue.dueDate = finding.due_date
|
|
1435
1556
|
issue.description = description
|
|
1436
1557
|
issue.sourceReport = finding.source_report or self.title
|
|
@@ -1476,15 +1597,34 @@ class ScannerIntegration(ABC):
|
|
|
1476
1597
|
bulk_update=True, defaults={"otherIdentifier": self._get_other_identifier(finding, is_poam)}
|
|
1477
1598
|
)
|
|
1478
1599
|
|
|
1600
|
+
self._handle_property_creation_for_issue(issue, finding)
|
|
1601
|
+
return issue
|
|
1602
|
+
|
|
1603
|
+
def _handle_property_creation_for_issue(self, issue: regscale_models.Issue, finding: IntegrationFinding) -> None:
|
|
1604
|
+
"""
|
|
1605
|
+
Handles property creation for an issue based on the finding data
|
|
1606
|
+
|
|
1607
|
+
:param regscale_models.Issue issue: The issue to handle properties for
|
|
1608
|
+
:param IntegrationFinding finding: The finding data
|
|
1609
|
+
:rtype: None
|
|
1610
|
+
"""
|
|
1479
1611
|
if poc := finding.point_of_contact:
|
|
1480
|
-
|
|
1612
|
+
regscale_models.Property(
|
|
1481
1613
|
key="POC",
|
|
1482
1614
|
value=poc,
|
|
1483
1615
|
parentId=issue.id,
|
|
1484
1616
|
parentModule="issues",
|
|
1485
|
-
).create_or_update(
|
|
1617
|
+
).create_or_update()
|
|
1618
|
+
logger.debug("Added POC property %s to issue %s", poc, issue.id)
|
|
1486
1619
|
|
|
1487
|
-
|
|
1620
|
+
if finding.is_cwe:
|
|
1621
|
+
regscale_models.Property(
|
|
1622
|
+
key="CWE",
|
|
1623
|
+
value=finding.plugin_id,
|
|
1624
|
+
parentId=issue.id,
|
|
1625
|
+
parentModule="issues",
|
|
1626
|
+
).create_or_update()
|
|
1627
|
+
logger.debug("Added CWE property %s to issue %s", finding.plugin_id, issue.id)
|
|
1488
1628
|
|
|
1489
1629
|
@staticmethod
|
|
1490
1630
|
def get_consolidated_asset_identifier(
|
|
@@ -1608,15 +1748,16 @@ class ScannerIntegration(ABC):
|
|
|
1608
1748
|
:param IntegrationFinding finding: The finding data that has failed
|
|
1609
1749
|
:rtype: None
|
|
1610
1750
|
"""
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1751
|
+
if ScannerVariables.vulnerabilityCreation.lower() != "noissue":
|
|
1752
|
+
logger.debug("Creating issue for failing finding %s", finding.external_id)
|
|
1753
|
+
found_issue = self.create_or_update_issue_from_finding(
|
|
1754
|
+
title=issue_title,
|
|
1755
|
+
finding=finding,
|
|
1756
|
+
)
|
|
1757
|
+
# Update the control implementation status to NOT_IMPLEMENTED since we have a failing finding
|
|
1758
|
+
if found_issue.controlImplementationIds:
|
|
1759
|
+
for control_id in found_issue.controlImplementationIds:
|
|
1760
|
+
self.update_control_implementation_status_after_close(control_id)
|
|
1620
1761
|
|
|
1621
1762
|
def handle_failing_checklist(
|
|
1622
1763
|
self,
|
|
@@ -1844,9 +1985,8 @@ class ScannerIntegration(ABC):
|
|
|
1844
1985
|
scan_history = self.create_scan_history()
|
|
1845
1986
|
current_vulnerabilities: Dict[int, Set[int]] = defaultdict(set)
|
|
1846
1987
|
processed_findings_count = 0
|
|
1847
|
-
findings_to_process = self.num_findings_to_process
|
|
1848
1988
|
loading_findings = self.finding_progress.add_task(
|
|
1849
|
-
f"[#f8b737]Processing {f'{
|
|
1989
|
+
f"[#f8b737]Processing {f'{self.num_findings_to_process} ' if self.num_findings_to_process else ''}finding(s) from {self.title}",
|
|
1850
1990
|
total=self.num_findings_to_process if self.num_findings_to_process else None,
|
|
1851
1991
|
)
|
|
1852
1992
|
|
|
@@ -1865,13 +2005,11 @@ class ScannerIntegration(ABC):
|
|
|
1865
2005
|
self.process_finding(finding_to_process, scan_history, current_vulnerabilities)
|
|
1866
2006
|
with count_lock:
|
|
1867
2007
|
processed_findings_count += 1
|
|
1868
|
-
if
|
|
1869
|
-
findings_to_process
|
|
1870
|
-
):
|
|
2008
|
+
if self.num_findings_to_process:
|
|
1871
2009
|
self.finding_progress.update(
|
|
1872
2010
|
loading_findings,
|
|
1873
|
-
total=
|
|
1874
|
-
description=f"[#f8b737]Processing {
|
|
2011
|
+
total=self.num_findings_to_process,
|
|
2012
|
+
description=f"[#f8b737]Processing {self.num_findings_to_process} findings from {self.title}.",
|
|
1875
2013
|
)
|
|
1876
2014
|
self.finding_progress.advance(loading_findings, 1)
|
|
1877
2015
|
except Exception as exc:
|
|
@@ -1885,13 +2023,27 @@ class ScannerIntegration(ABC):
|
|
|
1885
2023
|
for finding in findings:
|
|
1886
2024
|
process_finding_with_progress(finding)
|
|
1887
2025
|
else:
|
|
2026
|
+
# Process findings in batches to control memory usage
|
|
2027
|
+
batch_size = get_thread_workers_max() * 2 # Set batch size based on thread count
|
|
1888
2028
|
with concurrent.futures.ThreadPoolExecutor(max_workers=get_thread_workers_max()) as executor:
|
|
1889
|
-
|
|
2029
|
+
batch = []
|
|
2030
|
+
for finding in findings:
|
|
2031
|
+
batch.append(finding)
|
|
2032
|
+
if len(batch) >= batch_size:
|
|
2033
|
+
# Process this batch
|
|
2034
|
+
list(executor.map(process_finding_with_progress, batch))
|
|
2035
|
+
# Clear the batch
|
|
2036
|
+
batch = []
|
|
2037
|
+
|
|
2038
|
+
# Process any remaining items
|
|
2039
|
+
if batch:
|
|
2040
|
+
list(executor.map(process_finding_with_progress, batch))
|
|
1890
2041
|
|
|
1891
2042
|
# Close outdated issues
|
|
1892
2043
|
self._results["scan_history"] = scan_history.save()
|
|
1893
2044
|
self.update_result_counts("issues", regscale_models.Issue.bulk_save(progress_context=self.finding_progress))
|
|
1894
2045
|
self.close_outdated_issues(current_vulnerabilities)
|
|
2046
|
+
self._perform_batch_operations(self.finding_progress)
|
|
1895
2047
|
|
|
1896
2048
|
return processed_findings_count
|
|
1897
2049
|
|
|
@@ -2068,6 +2220,9 @@ class ScannerIntegration(ABC):
|
|
|
2068
2220
|
finding.vpr_score if hasattr(finding, "vprScore") else None
|
|
2069
2221
|
), # If this is the VPR score, otherwise use a different field
|
|
2070
2222
|
cvsSv3BaseScore=finding.cvss_v3_base_score or finding.cvss_v3_score or finding.cvss_score,
|
|
2223
|
+
cvsSv2BaseScore=finding.cvss_v2_score,
|
|
2224
|
+
cvsSv3BaseVector=finding.cvss_v3_vector,
|
|
2225
|
+
cvsSv2BaseVector=finding.cvss_v2_vector,
|
|
2071
2226
|
scanId=scan_history.id,
|
|
2072
2227
|
severity=self.issue_to_vulnerability_map.get(finding.severity, regscale_models.VulnerabilitySeverity.Low),
|
|
2073
2228
|
description=finding.description,
|
|
@@ -2082,27 +2237,35 @@ class ScannerIntegration(ABC):
|
|
|
2082
2237
|
plugInName=finding.cve or finding.plugin_name, # Use CVE if available, otherwise use plugin name
|
|
2083
2238
|
plugInId=finding.plugin_id,
|
|
2084
2239
|
exploitAvailable=None, # Set this if you have information about exploit availability
|
|
2085
|
-
plugInText=finding.
|
|
2240
|
+
plugInText=finding.plugin_text
|
|
2241
|
+
or finding.observations, # or finding.evidence, whichever is more appropriate
|
|
2086
2242
|
port=finding.port if hasattr(finding, "port") else None,
|
|
2087
2243
|
protocol=finding.protocol if hasattr(finding, "protocol") else None,
|
|
2088
2244
|
operatingSystem=asset.operating_system if hasattr(asset, "operating_system") else None,
|
|
2245
|
+
fixedVersions=finding.fixed_versions,
|
|
2246
|
+
buildVersion=finding.build_version,
|
|
2247
|
+
fixStatus=finding.fix_status,
|
|
2248
|
+
installedVersions=finding.installed_versions,
|
|
2249
|
+
affectedOS=finding.affected_os,
|
|
2250
|
+
packagePath=finding.package_path,
|
|
2251
|
+
imageDigest=finding.image_digest,
|
|
2252
|
+
affectedPackages=finding.affected_packages,
|
|
2089
2253
|
)
|
|
2090
2254
|
|
|
2091
2255
|
vulnerability = vulnerability.create_or_update()
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
).create_unique()
|
|
2256
|
+
regscale_models.VulnerabilityMapping(
|
|
2257
|
+
vulnerabilityId=vulnerability.id,
|
|
2258
|
+
assetId=asset.id,
|
|
2259
|
+
scanId=scan_history.id,
|
|
2260
|
+
securityPlansId=self.plan_id,
|
|
2261
|
+
createdById=self.assessor_id,
|
|
2262
|
+
tenantsId=self.tenant_id,
|
|
2263
|
+
isPublic=True,
|
|
2264
|
+
dateCreated=get_current_datetime(),
|
|
2265
|
+
firstSeen=finding.first_seen,
|
|
2266
|
+
lastSeen=finding.last_seen,
|
|
2267
|
+
status=finding.status,
|
|
2268
|
+
).create_unique()
|
|
2106
2269
|
return vulnerability
|
|
2107
2270
|
|
|
2108
2271
|
def handle_vulnerability(
|
|
@@ -2131,11 +2294,12 @@ class ScannerIntegration(ABC):
|
|
|
2131
2294
|
vulnerability = self.create_vulnerability_from_finding(finding, asset, scan_history)
|
|
2132
2295
|
finding.vulnerability_id = vulnerability.id
|
|
2133
2296
|
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2297
|
+
if ScannerVariables.vulnerabilityCreation.lower() != "noissue":
|
|
2298
|
+
# Handle associated issue
|
|
2299
|
+
self.create_or_update_issue_from_finding(
|
|
2300
|
+
title=finding.title,
|
|
2301
|
+
finding=finding,
|
|
2302
|
+
)
|
|
2139
2303
|
|
|
2140
2304
|
return vulnerability.id
|
|
2141
2305
|
|
|
@@ -2492,6 +2656,8 @@ class ScannerIntegration(ABC):
|
|
|
2492
2656
|
created_count = instance._results.get("assets", {}).get("created_count", 0)
|
|
2493
2657
|
updated_count = instance._results.get("assets", {}).get("updated_count", 0)
|
|
2494
2658
|
dedupe_count = assets_processed - (created_count + updated_count)
|
|
2659
|
+
# Ensure dedupe_count is always a positive value
|
|
2660
|
+
dedupe_count = dedupe_count if dedupe_count >= 0 else dedupe_count * -1
|
|
2495
2661
|
logger.info(
|
|
2496
2662
|
"%d assets processed and %d asset(s) deduped. %d asset(s) created & %d asset(s) updated in RegScale.",
|
|
2497
2663
|
assets_processed,
|
|
@@ -1,9 +1,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "CISA Catalog of Known Exploited Vulnerabilities",
|
|
3
|
-
"catalogVersion": "2025.03.
|
|
4
|
-
"dateReleased": "2025-03-
|
|
5
|
-
"count":
|
|
3
|
+
"catalogVersion": "2025.03.27",
|
|
4
|
+
"dateReleased": "2025-03-27T17:55:47.8204Z",
|
|
5
|
+
"count": 1311,
|
|
6
6
|
"vulnerabilities": [
|
|
7
|
+
{
|
|
8
|
+
"cveID": "CVE-2025-2783",
|
|
9
|
+
"vendorProject": "Google",
|
|
10
|
+
"product": "Chromium Mojo",
|
|
11
|
+
"vulnerabilityName": "Google Chromium Mojo Sandbox Escape Vulnerability",
|
|
12
|
+
"dateAdded": "2025-03-27",
|
|
13
|
+
"shortDescription": "Google Chromium Mojo on Windows contains a sandbox escape vulnerability caused by a logic error, which results from an incorrect handle being provided in unspecified circumstances. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera.",
|
|
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-04-17",
|
|
16
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
+
"notes": "https:\/\/chromereleases.googleblog.com\/2025\/03\/stable-channel-update-for-desktop_25.html ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-2783",
|
|
18
|
+
"cwes": []
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cveID": "CVE-2019-9875",
|
|
22
|
+
"vendorProject": "Sitecore",
|
|
23
|
+
"product": "CMS and Experience Platform (XP)",
|
|
24
|
+
"vulnerabilityName": "Sitecore CMS and Experience Platform (XP) Deserialization Vulnerability",
|
|
25
|
+
"dateAdded": "2025-03-26",
|
|
26
|
+
"shortDescription": "Sitecore CMS and Experience Platform (XP) contain a deserialization vulnerability in the Sitecore.Security.AntiCSRF module that allows an authenticated attacker to execute arbitrary code by sending a serialized .NET object in the HTTP POST parameter __CSRFTOKEN.",
|
|
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-04-16",
|
|
29
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
30
|
+
"notes": "https:\/\/support.sitecore.com\/kb?id=kb_article_view&sysparm_article=KB0038556 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-9875",
|
|
31
|
+
"cwes": [
|
|
32
|
+
"CWE-502"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"cveID": "CVE-2019-9874",
|
|
37
|
+
"vendorProject": "Sitecore",
|
|
38
|
+
"product": "CMS and Experience Platform (XP)",
|
|
39
|
+
"vulnerabilityName": "Sitecore CMS and Experience Platform (XP) Deserialization Vulnerability",
|
|
40
|
+
"dateAdded": "2025-03-26",
|
|
41
|
+
"shortDescription": "Sitecore CMS and Experience Platform (XP) contain a deserialization vulnerability in the Sitecore.Security.AntiCSRF module that allows an unauthenticated attacker to execute arbitrary code by sending a serialized .NET object in the HTTP POST parameter __CSRFTOKEN.",
|
|
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-04-16",
|
|
44
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
45
|
+
"notes": "https:\/\/support.sitecore.com\/kb?id=kb_article_view&sysparm_article=KB0334035 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-9874",
|
|
46
|
+
"cwes": [
|
|
47
|
+
"CWE-502"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"cveID": "CVE-2025-30154",
|
|
52
|
+
"vendorProject": "reviewdog",
|
|
53
|
+
"product": "action-setup GitHub Action",
|
|
54
|
+
"vulnerabilityName": "reviewdog\/action-setup GitHub Action Embedded Malicious Code Vulnerability",
|
|
55
|
+
"dateAdded": "2025-03-24",
|
|
56
|
+
"shortDescription": "reviewdog action-setup GitHub Action contains an embedded malicious code vulnerability that dumps exposed secrets to Github Actions Workflow Logs.",
|
|
57
|
+
"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.",
|
|
58
|
+
"dueDate": "2025-04-14",
|
|
59
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
60
|
+
"notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/03\/18\/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ; Additional References: https:\/\/github.com\/reviewdog\/reviewdog\/security\/advisories\/GHSA-qmg3-hpqr-gqvc ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30154",
|
|
61
|
+
"cwes": [
|
|
62
|
+
"CWE-506"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
7
65
|
{
|
|
8
66
|
"cveID": "CVE-2017-12637",
|
|
9
67
|
"vendorProject": "SAP",
|
|
@@ -55,11 +113,11 @@
|
|
|
55
113
|
"product": "changed-files GitHub Action",
|
|
56
114
|
"vulnerabilityName": "tj-actions\/changed-files GitHub Action Embedded Malicious Code Vulnerability",
|
|
57
115
|
"dateAdded": "2025-03-18",
|
|
58
|
-
"shortDescription": "
|
|
116
|
+
"shortDescription": "tj-actions\/changed-files GitHub Action contains an embedded malicious code vulnerability that allows a remote attacker to discover secrets by reading Github Actions Workflow Logs. These secrets may include, but are not limited to, valid AWS access keys, GitHub personal access tokens (PATs), npm tokens, and private RSA keys.",
|
|
59
117
|
"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.",
|
|
60
118
|
"dueDate": "2025-04-08",
|
|
61
119
|
"knownRansomwareCampaignUse": "Unknown",
|
|
62
|
-
"notes": "https:\/\/github.com\/tj-actions\/changed-files\/blob\/45fb12d7a8bedb4da42342e52fe054c6c2c3fd73\/README.md?plain=1#L20-L28 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30066",
|
|
120
|
+
"notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/03\/18\/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ; Additional References: https:\/\/github.com\/tj-actions\/changed-files\/blob\/45fb12d7a8bedb4da42342e52fe054c6c2c3fd73\/README.md?plain=1#L20-L28 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30066",
|
|
63
121
|
"cwes": [
|
|
64
122
|
"CWE-506"
|
|
65
123
|
]
|
|
@@ -2949,7 +3007,7 @@
|
|
|
2949
3007
|
{
|
|
2950
3008
|
"cveID": "CVE-2024-4761",
|
|
2951
3009
|
"vendorProject": "Google",
|
|
2952
|
-
"product": "Chromium
|
|
3010
|
+
"product": "Chromium V8",
|
|
2953
3011
|
"vulnerabilityName": "Google Chromium V8 Out-of-Bounds Memory Write Vulnerability",
|
|
2954
3012
|
"dateAdded": "2024-05-16",
|
|
2955
3013
|
"shortDescription": "Google Chromium V8 Engine contains an unspecified out-of-bounds memory write vulnerability via a crafted HTML page. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera. ",
|
|
@@ -14604,7 +14662,7 @@
|
|
|
14604
14662
|
"cveID": "CVE-2020-6572",
|
|
14605
14663
|
"vendorProject": "Google",
|
|
14606
14664
|
"product": "Chrome Media",
|
|
14607
|
-
"vulnerabilityName": "Google Chrome Media
|
|
14665
|
+
"vulnerabilityName": "Google Chrome Media Use-After-Free Vulnerability",
|
|
14608
14666
|
"dateAdded": "2022-01-10",
|
|
14609
14667
|
"shortDescription": "Google Chrome Media contains a use-after-free vulnerability that allows a remote attacker to execute code via a crafted HTML page.",
|
|
14610
14668
|
"requiredAction": "Apply updates per vendor instructions.",
|