regscale-cli 6.25.1.0__py3-none-any.whl → 6.26.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of regscale-cli might be problematic. Click here for more details.
- regscale/_version.py +1 -1
- regscale/airflow/hierarchy.py +2 -2
- regscale/core/app/application.py +18 -3
- regscale/core/app/internal/login.py +0 -1
- regscale/core/app/utils/catalog_utils/common.py +1 -1
- regscale/integrations/commercial/sicura/api.py +14 -13
- regscale/integrations/commercial/sicura/commands.py +8 -2
- regscale/integrations/commercial/sicura/scanner.py +49 -39
- regscale/integrations/commercial/stigv2/ckl_parser.py +5 -5
- regscale/integrations/commercial/wizv2/click.py +26 -26
- regscale/integrations/commercial/wizv2/compliance_report.py +152 -157
- regscale/integrations/commercial/wizv2/scanner.py +3 -3
- regscale/integrations/compliance_integration.py +67 -2
- regscale/integrations/control_matcher.py +358 -0
- regscale/integrations/milestone_manager.py +291 -0
- regscale/integrations/public/__init__.py +1 -0
- regscale/integrations/public/cci_importer.py +37 -38
- regscale/integrations/public/fedramp/click.py +60 -2
- regscale/integrations/public/fedramp/poam_export_v5.py +888 -0
- regscale/integrations/scanner_integration.py +150 -96
- regscale/models/integration_models/cisa_kev_data.json +154 -4
- regscale/models/integration_models/nexpose.py +36 -10
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/locking.py +12 -8
- regscale/models/platform.py +1 -2
- regscale/models/regscale_models/control_implementation.py +46 -21
- regscale/models/regscale_models/issue.py +256 -94
- regscale/models/regscale_models/milestone.py +1 -1
- regscale/models/regscale_models/regscale_model.py +6 -1
- regscale/templates/__init__.py +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.26.0.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.26.0.0.dist-info}/RECORD +80 -33
- tests/regscale/integrations/commercial/__init__.py +0 -0
- tests/regscale/integrations/commercial/conftest.py +28 -0
- tests/regscale/integrations/commercial/microsoft_defender/__init__.py +1 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender.py +1517 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_api.py +1748 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_constants.py +327 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_scanner.py +487 -0
- tests/regscale/integrations/commercial/test_aws.py +3731 -0
- tests/regscale/integrations/commercial/test_burp.py +48 -0
- tests/regscale/integrations/commercial/test_crowdstrike.py +49 -0
- tests/regscale/integrations/commercial/test_dependabot.py +341 -0
- tests/regscale/integrations/commercial/test_gcp.py +1543 -0
- tests/regscale/integrations/commercial/test_gitlab.py +549 -0
- tests/regscale/integrations/commercial/test_ip_mac_address_length.py +84 -0
- tests/regscale/integrations/commercial/test_jira.py +1814 -0
- tests/regscale/integrations/commercial/test_npm_audit.py +42 -0
- tests/regscale/integrations/commercial/test_okta.py +1228 -0
- tests/regscale/integrations/commercial/test_sarif_converter.py +251 -0
- tests/regscale/integrations/commercial/test_sicura.py +350 -0
- tests/regscale/integrations/commercial/test_snow.py +423 -0
- tests/regscale/integrations/commercial/test_sonarcloud.py +394 -0
- tests/regscale/integrations/commercial/test_sqlserver.py +186 -0
- tests/regscale/integrations/commercial/test_stig.py +33 -0
- tests/regscale/integrations/commercial/test_stig_mapper.py +153 -0
- tests/regscale/integrations/commercial/test_stigv2.py +406 -0
- tests/regscale/integrations/commercial/test_wiz.py +1469 -0
- tests/regscale/integrations/commercial/test_wiz_inventory.py +256 -0
- tests/regscale/integrations/commercial/wizv2/__init__.py +339 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +343 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +165 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +1351 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_unit.py +341 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_policy_compliance.py +750 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_status_mapping.py +149 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +264 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +624 -0
- tests/regscale/integrations/public/fedramp/__init__.py +1 -0
- tests/regscale/integrations/public/fedramp/test_poam_export_v5.py +1293 -0
- tests/regscale/integrations/test_control_matcher.py +1314 -0
- tests/regscale/integrations/test_control_matching.py +155 -0
- tests/regscale/integrations/test_milestone_manager.py +408 -0
- tests/regscale/models/test_issue.py +378 -1
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.26.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.26.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.26.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.25.1.0.dist-info → regscale_cli-6.26.0.0.dist-info}/top_level.txt +0 -0
|
@@ -27,6 +27,7 @@ from regscale.integrations.commercial.durosuite.process_devices import scan_duro
|
|
|
27
27
|
from regscale.integrations.commercial.durosuite.variables import DuroSuiteVariables
|
|
28
28
|
from regscale.integrations.commercial.stig_mapper_integration.mapping_engine import StigMappingEngine as STIGMapper
|
|
29
29
|
from regscale.integrations.due_date_handler import DueDateHandler
|
|
30
|
+
from regscale.integrations.milestone_manager import MilestoneManager
|
|
30
31
|
from regscale.integrations.public.cisa import pull_cisa_kev
|
|
31
32
|
from regscale.integrations.variables import ScannerVariables
|
|
32
33
|
from regscale.models import DateTimeEncoder, OpenIssueDict, Property, regscale_models
|
|
@@ -672,6 +673,9 @@ class ScannerIntegration(ABC):
|
|
|
672
673
|
# Initialize due date handler for this integration
|
|
673
674
|
self.due_date_handler = DueDateHandler(self.title, config=self.app.config)
|
|
674
675
|
|
|
676
|
+
# Initialize milestone manager for this integration
|
|
677
|
+
self.milestone_manager = None # Lazy initialization after scan_date is set
|
|
678
|
+
|
|
675
679
|
if self.is_component:
|
|
676
680
|
self.component = regscale_models.Component.get_object(self.plan_id)
|
|
677
681
|
self.parent_module: str = regscale_models.Component.get_module_string()
|
|
@@ -737,6 +741,21 @@ class ScannerIntegration(ABC):
|
|
|
737
741
|
cls._lock_registry[key] = lock
|
|
738
742
|
return lock
|
|
739
743
|
|
|
744
|
+
def get_milestone_manager(self) -> MilestoneManager:
|
|
745
|
+
"""
|
|
746
|
+
Get or initialize the milestone manager.
|
|
747
|
+
|
|
748
|
+
:return: MilestoneManager instance
|
|
749
|
+
:rtype: MilestoneManager
|
|
750
|
+
"""
|
|
751
|
+
if self.milestone_manager is None:
|
|
752
|
+
self.milestone_manager = MilestoneManager(
|
|
753
|
+
integration_title=self.title,
|
|
754
|
+
assessor_id=self.assessor_id,
|
|
755
|
+
scan_date=self.scan_date or get_current_datetime(),
|
|
756
|
+
)
|
|
757
|
+
return self.milestone_manager
|
|
758
|
+
|
|
740
759
|
@staticmethod
|
|
741
760
|
def load_stig_mapper() -> Optional[STIGMapper]:
|
|
742
761
|
"""
|
|
@@ -997,15 +1016,18 @@ class ScannerIntegration(ABC):
|
|
|
997
1016
|
return res[:450]
|
|
998
1017
|
return prefix[:450]
|
|
999
1018
|
|
|
1000
|
-
def get_or_create_assessment(
|
|
1019
|
+
def get_or_create_assessment(
|
|
1020
|
+
self, control_implementation_id: int, status: Optional[regscale_models.AssessmentResultsStatus] = None
|
|
1021
|
+
) -> regscale_models.Assessment:
|
|
1001
1022
|
"""
|
|
1002
|
-
Gets or creates a RegScale assessment
|
|
1023
|
+
Gets or creates a RegScale assessment.
|
|
1003
1024
|
|
|
1004
1025
|
:param int control_implementation_id: The ID of the control implementation
|
|
1026
|
+
:param Optional[regscale_models.AssessmentResultsStatus] status: Optional status override (used by cci_assessment)
|
|
1005
1027
|
:return: The assessment
|
|
1006
1028
|
:rtype: regscale_models.Assessment
|
|
1007
1029
|
"""
|
|
1008
|
-
logger.
|
|
1030
|
+
logger.debug("Getting or create assessment for control implementation %d", control_implementation_id)
|
|
1009
1031
|
assessment: Optional[regscale_models.Assessment] = self.assessment_map.get(control_implementation_id)
|
|
1010
1032
|
if assessment:
|
|
1011
1033
|
logger.debug(
|
|
@@ -1017,7 +1039,7 @@ class ScannerIntegration(ABC):
|
|
|
1017
1039
|
plannedStart=get_current_datetime(),
|
|
1018
1040
|
plannedFinish=get_current_datetime(),
|
|
1019
1041
|
status=regscale_models.AssessmentStatus.COMPLETE.value,
|
|
1020
|
-
assessmentResult=regscale_models.AssessmentResultsStatus.FAIL.value,
|
|
1042
|
+
assessmentResult=status.value if status else regscale_models.AssessmentResultsStatus.FAIL.value,
|
|
1021
1043
|
actualFinish=get_current_datetime(),
|
|
1022
1044
|
leadAssessorId=self.assessor_id,
|
|
1023
1045
|
parentId=control_implementation_id,
|
|
@@ -2284,87 +2306,26 @@ class ScannerIntegration(ABC):
|
|
|
2284
2306
|
"""
|
|
2285
2307
|
Create milestones for an issue based on status transitions.
|
|
2286
2308
|
|
|
2309
|
+
Delegates to MilestoneManager for cleaner separation of concerns.
|
|
2310
|
+
Also ensures existing issues have creation milestones (backfills if missing).
|
|
2311
|
+
|
|
2287
2312
|
:param regscale_models.Issue issue: The issue to create milestones for
|
|
2288
2313
|
:param IntegrationFinding finding: The finding data
|
|
2289
2314
|
:param Optional[regscale_models.Issue] existing_issue: Existing issue for comparison
|
|
2290
2315
|
"""
|
|
2291
|
-
|
|
2292
|
-
return
|
|
2293
|
-
|
|
2294
|
-
if self._should_create_reopened_milestone(existing_issue, issue):
|
|
2295
|
-
self._create_milestone_safe(
|
|
2296
|
-
issue, finding, "Issue reopened from", get_current_datetime(), "reopened milestone"
|
|
2297
|
-
)
|
|
2298
|
-
elif self._should_create_closed_milestone(existing_issue, issue):
|
|
2299
|
-
self._create_milestone_safe(issue, finding, "Issue closed from", issue.dateCompleted, "closed milestone")
|
|
2300
|
-
elif not existing_issue:
|
|
2301
|
-
self._create_milestone_safe(issue, finding, "Issue created from", self.scan_date, "new issue milestone")
|
|
2302
|
-
else:
|
|
2303
|
-
logger.debug("No milestone created for issue %s from finding %s", issue.id, finding.external_id)
|
|
2316
|
+
milestone_manager = self.get_milestone_manager()
|
|
2304
2317
|
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
"""
|
|
2309
|
-
Check if a reopened milestone should be created.
|
|
2310
|
-
|
|
2311
|
-
:param Optional[regscale_models.Issue] existing_issue: The existing issue
|
|
2312
|
-
:param regscale_models.Issue issue: The current issue
|
|
2313
|
-
:return: True if reopened milestone should be created
|
|
2314
|
-
:rtype: bool
|
|
2315
|
-
"""
|
|
2316
|
-
return (
|
|
2317
|
-
existing_issue
|
|
2318
|
-
and existing_issue.status == regscale_models.IssueStatus.Closed
|
|
2319
|
-
and issue.status == regscale_models.IssueStatus.Open
|
|
2320
|
-
)
|
|
2321
|
-
|
|
2322
|
-
def _should_create_closed_milestone(
|
|
2323
|
-
self, existing_issue: Optional[regscale_models.Issue], issue: regscale_models.Issue
|
|
2324
|
-
) -> bool:
|
|
2325
|
-
"""
|
|
2326
|
-
Check if a closed milestone should be created.
|
|
2318
|
+
# For existing issues, ensure they have a creation milestone (backfill if missing)
|
|
2319
|
+
if existing_issue:
|
|
2320
|
+
milestone_manager.ensure_creation_milestone_exists(issue=issue, finding=finding)
|
|
2327
2321
|
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
return (
|
|
2334
|
-
existing_issue
|
|
2335
|
-
and existing_issue.status == regscale_models.IssueStatus.Open
|
|
2336
|
-
and issue.status == regscale_models.IssueStatus.Closed
|
|
2322
|
+
# Handle status transition milestones
|
|
2323
|
+
milestone_manager.create_milestones_for_issue(
|
|
2324
|
+
issue=issue,
|
|
2325
|
+
finding=finding,
|
|
2326
|
+
existing_issue=existing_issue,
|
|
2337
2327
|
)
|
|
2338
2328
|
|
|
2339
|
-
def _create_milestone_safe(
|
|
2340
|
-
self,
|
|
2341
|
-
issue: regscale_models.Issue,
|
|
2342
|
-
finding: IntegrationFinding,
|
|
2343
|
-
title_prefix: str,
|
|
2344
|
-
milestone_date: str,
|
|
2345
|
-
milestone_type: str,
|
|
2346
|
-
) -> None:
|
|
2347
|
-
"""
|
|
2348
|
-
Safely create a milestone with error handling.
|
|
2349
|
-
|
|
2350
|
-
:param regscale_models.Issue issue: The issue to create milestone for
|
|
2351
|
-
:param IntegrationFinding finding: The finding data
|
|
2352
|
-
:param str title_prefix: Prefix for milestone title
|
|
2353
|
-
:param str milestone_date: Date for the milestone
|
|
2354
|
-
:param str milestone_type: Description for logging purposes
|
|
2355
|
-
"""
|
|
2356
|
-
try:
|
|
2357
|
-
regscale_models.Milestone(
|
|
2358
|
-
title=f"{title_prefix} {self.title} scan",
|
|
2359
|
-
milestoneDate=milestone_date,
|
|
2360
|
-
responsiblePersonId=self.assessor_id,
|
|
2361
|
-
parentID=issue.id,
|
|
2362
|
-
parentModule="issues",
|
|
2363
|
-
).create_or_update()
|
|
2364
|
-
logger.debug("Added milestone for issue %s from finding %s", issue.id, finding.external_id)
|
|
2365
|
-
except Exception as e:
|
|
2366
|
-
logger.warning("Failed to create %s: %s", milestone_type, str(e))
|
|
2367
|
-
|
|
2368
2329
|
@staticmethod
|
|
2369
2330
|
def extra_data_to_properties(finding: IntegrationFinding, issue_id: int) -> None:
|
|
2370
2331
|
"""
|
|
@@ -2530,6 +2491,8 @@ class ScannerIntegration(ABC):
|
|
|
2530
2491
|
if found_issue.controlImplementationIds:
|
|
2531
2492
|
for control_id in found_issue.controlImplementationIds:
|
|
2532
2493
|
self.update_control_implementation_status_after_close(control_id)
|
|
2494
|
+
# Update assessment status to reflect the control implementation status
|
|
2495
|
+
self.update_assessment_status_from_control_implementation(control_id)
|
|
2533
2496
|
|
|
2534
2497
|
def handle_failing_checklist(
|
|
2535
2498
|
self,
|
|
@@ -2554,11 +2517,13 @@ class ScannerIntegration(ABC):
|
|
|
2554
2517
|
if failing_objective.name.lower().startswith("cci-"):
|
|
2555
2518
|
implementation_id = self.get_control_implementation_id_for_cci(failing_objective.name)
|
|
2556
2519
|
else:
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2520
|
+
implementation_id = self._fallback_implementation_id(failing_objective)
|
|
2521
|
+
|
|
2522
|
+
if not implementation_id or implementation_id is None:
|
|
2523
|
+
logger.warning(
|
|
2524
|
+
"Could not map objective to a Control Implementation for objective #%i.", failing_objective.id
|
|
2525
|
+
)
|
|
2526
|
+
continue
|
|
2562
2527
|
|
|
2563
2528
|
failing_option = regscale_models.ImplementationOption(
|
|
2564
2529
|
name="Failed STIG",
|
|
@@ -2580,13 +2545,36 @@ class ScannerIntegration(ABC):
|
|
|
2580
2545
|
).create_or_update()
|
|
2581
2546
|
|
|
2582
2547
|
# Create assessment and control test result
|
|
2583
|
-
assessment = self.get_or_create_assessment(
|
|
2548
|
+
assessment = self.get_or_create_assessment(
|
|
2549
|
+
implementation_id, status=regscale_models.AssessmentResultsStatus.FAIL
|
|
2550
|
+
)
|
|
2584
2551
|
if implementation_id:
|
|
2585
2552
|
control_test = self.create_or_get_control_test(finding, implementation_id)
|
|
2586
2553
|
self.create_control_test_result(
|
|
2587
2554
|
finding, control_test, assessment, regscale_models.ControlTestResultStatus.FAIL
|
|
2588
2555
|
)
|
|
2589
2556
|
|
|
2557
|
+
def _fallback_implementation_id(self, objective: regscale_models.ControlObjective) -> Optional[int]:
|
|
2558
|
+
"""
|
|
2559
|
+
Fallback method to get control implementation ID from objective name if CCI mapping fails.
|
|
2560
|
+
|
|
2561
|
+
:param regscale_models.ControlObjective objective: The control objective
|
|
2562
|
+
:return: The control implementation ID if found, None otherwise
|
|
2563
|
+
:rtype: Optional[int]
|
|
2564
|
+
"""
|
|
2565
|
+
control_label = objective_to_control_dot(objective.name)
|
|
2566
|
+
if implementation_id := self.control_implementation_id_map.get(control_label):
|
|
2567
|
+
return implementation_id
|
|
2568
|
+
|
|
2569
|
+
if control_id := self.control_id_to_implementation_map.get(objective.securityControlId):
|
|
2570
|
+
if control_label := self.control_map.get(control_id):
|
|
2571
|
+
implementation_id = self.control_implementation_id_map.get(control_label)
|
|
2572
|
+
if not implementation_id:
|
|
2573
|
+
print("No dice.")
|
|
2574
|
+
return implementation_id
|
|
2575
|
+
logger.debug("Could not find fallback implementation ID for objective #%i", objective.id)
|
|
2576
|
+
return None
|
|
2577
|
+
|
|
2590
2578
|
def handle_passing_checklist(
|
|
2591
2579
|
self,
|
|
2592
2580
|
finding: IntegrationFinding,
|
|
@@ -2610,15 +2598,12 @@ class ScannerIntegration(ABC):
|
|
|
2610
2598
|
if passing_objective.name.lower().startswith("cci-"):
|
|
2611
2599
|
implementation_id = self.get_control_implementation_id_for_cci(passing_objective.name)
|
|
2612
2600
|
else:
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
# Skip if we couldn't determine the implementation ID
|
|
2620
|
-
if implementation_id is None:
|
|
2621
|
-
logger.warning("Could not determine implementation ID for objective %s", passing_objective.name)
|
|
2601
|
+
implementation_id = self._fallback_implementation_id(passing_objective)
|
|
2602
|
+
|
|
2603
|
+
if not implementation_id or implementation_id is None:
|
|
2604
|
+
logger.warning(
|
|
2605
|
+
"Could not map objective to a Control Implementation for objective #%i.", passing_objective.id
|
|
2606
|
+
)
|
|
2622
2607
|
continue
|
|
2623
2608
|
|
|
2624
2609
|
passing_option = regscale_models.ImplementationOption(
|
|
@@ -2641,7 +2626,9 @@ class ScannerIntegration(ABC):
|
|
|
2641
2626
|
).create_or_update()
|
|
2642
2627
|
|
|
2643
2628
|
# Create assessment and control test result
|
|
2644
|
-
assessment = self.get_or_create_assessment(
|
|
2629
|
+
assessment = self.get_or_create_assessment(
|
|
2630
|
+
implementation_id, status=regscale_models.AssessmentResultsStatus.PASS
|
|
2631
|
+
)
|
|
2645
2632
|
control_test = self.create_or_get_control_test(finding, implementation_id)
|
|
2646
2633
|
self.create_control_test_result(
|
|
2647
2634
|
finding, control_test, assessment, regscale_models.ControlTestResultStatus.PASS
|
|
@@ -2706,7 +2693,11 @@ class ScannerIntegration(ABC):
|
|
|
2706
2693
|
logger.error("2. Asset not found for identifier %s", finding.asset_identifier)
|
|
2707
2694
|
return 0
|
|
2708
2695
|
|
|
2709
|
-
tool =
|
|
2696
|
+
tool = (
|
|
2697
|
+
regscale_models.ChecklistTool.CISBenchmarks
|
|
2698
|
+
if "simp.cis" in str(finding.vulnerability_number).lower()
|
|
2699
|
+
else regscale_models.ChecklistTool.STIGs
|
|
2700
|
+
)
|
|
2710
2701
|
if finding.vulnerability_type == "Vulnerability Scan":
|
|
2711
2702
|
tool = regscale_models.ChecklistTool.VulnerabilityScanner
|
|
2712
2703
|
|
|
@@ -3381,6 +3372,8 @@ class ScannerIntegration(ABC):
|
|
|
3381
3372
|
|
|
3382
3373
|
for control_id in affected_control_ids:
|
|
3383
3374
|
self.update_control_implementation_status_after_close(control_id)
|
|
3375
|
+
# Update assessment status to reflect the control implementation status
|
|
3376
|
+
self.update_assessment_status_from_control_implementation(control_id)
|
|
3384
3377
|
|
|
3385
3378
|
(
|
|
3386
3379
|
logger.info("Closed %d outdated issues.", closed_count)
|
|
@@ -3483,9 +3476,70 @@ class ScannerIntegration(ABC):
|
|
|
3483
3476
|
if control_implementation.status != new_status:
|
|
3484
3477
|
control_implementation.status = new_status
|
|
3485
3478
|
self.control_implementation_map[control_id] = control_implementation.save()
|
|
3486
|
-
logger.
|
|
3479
|
+
logger.debug("Updated control implementation %d status to %s", control_id, new_status)
|
|
3480
|
+
|
|
3481
|
+
def update_assessment_status_from_control_implementation(self, control_implementation_id: int) -> None:
|
|
3482
|
+
"""
|
|
3483
|
+
Updates the assessment status based on the control implementation status.
|
|
3484
|
+
Treats the ControlImplementation status as the source of truth.
|
|
3487
3485
|
|
|
3488
|
-
|
|
3486
|
+
Sets assessment to PASS if ControlImplementation status is FULLY_IMPLEMENTED,
|
|
3487
|
+
otherwise sets it to FAIL.
|
|
3488
|
+
|
|
3489
|
+
This method should be called after update_control_implementation_status_after_close
|
|
3490
|
+
to ensure assessments reflect the final control implementation state.
|
|
3491
|
+
|
|
3492
|
+
:param int control_implementation_id: The ID of the control implementation
|
|
3493
|
+
:rtype: None
|
|
3494
|
+
"""
|
|
3495
|
+
# Get the cached assessment for this control implementation
|
|
3496
|
+
assessment = self.assessment_map.get(control_implementation_id)
|
|
3497
|
+
|
|
3498
|
+
if not assessment:
|
|
3499
|
+
logger.debug(
|
|
3500
|
+
"No assessment found in cache for control implementation %d, skipping assessment update",
|
|
3501
|
+
control_implementation_id,
|
|
3502
|
+
)
|
|
3503
|
+
return
|
|
3504
|
+
|
|
3505
|
+
# Get the control implementation to check its status
|
|
3506
|
+
control_implementation = self.control_implementation_map.get(
|
|
3507
|
+
control_implementation_id
|
|
3508
|
+
) or regscale_models.ControlImplementation.get_object(object_id=control_implementation_id)
|
|
3509
|
+
|
|
3510
|
+
if not control_implementation:
|
|
3511
|
+
logger.warning("Control implementation %d not found, cannot update assessment", control_implementation_id)
|
|
3512
|
+
return
|
|
3513
|
+
|
|
3514
|
+
# Determine assessment result based on control implementation status
|
|
3515
|
+
# Treat ControlImplementation status as the source of truth
|
|
3516
|
+
new_assessment_result = (
|
|
3517
|
+
regscale_models.AssessmentResultsStatus.PASS
|
|
3518
|
+
if control_implementation.status == regscale_models.ImplementationStatus.FULLY_IMPLEMENTED.value
|
|
3519
|
+
else regscale_models.AssessmentResultsStatus.FAIL
|
|
3520
|
+
)
|
|
3521
|
+
|
|
3522
|
+
# Only update if the status has changed
|
|
3523
|
+
if assessment.assessmentResult != new_assessment_result.value:
|
|
3524
|
+
assessment.assessmentResult = new_assessment_result.value
|
|
3525
|
+
assessment.save()
|
|
3526
|
+
logger.debug(
|
|
3527
|
+
"Updated assessment %d for control implementation %d: assessmentResult=%s (based on control status: %s)",
|
|
3528
|
+
assessment.id,
|
|
3529
|
+
control_implementation_id,
|
|
3530
|
+
new_assessment_result.value,
|
|
3531
|
+
control_implementation.status,
|
|
3532
|
+
)
|
|
3533
|
+
else:
|
|
3534
|
+
logger.debug(
|
|
3535
|
+
"Assessment %d already has correct status %s for control implementation %d",
|
|
3536
|
+
assessment.id,
|
|
3537
|
+
assessment.assessmentResult,
|
|
3538
|
+
control_implementation_id,
|
|
3539
|
+
)
|
|
3540
|
+
|
|
3541
|
+
@staticmethod
|
|
3542
|
+
def is_issue_protected_from_auto_close(issue: regscale_models.Issue) -> bool:
|
|
3489
3543
|
"""
|
|
3490
3544
|
Check if an issue is protected from automatic closure.
|
|
3491
3545
|
|
|
@@ -1,9 +1,159 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "CISA Catalog of Known Exploited Vulnerabilities",
|
|
3
|
-
"catalogVersion": "2025.
|
|
4
|
-
"dateReleased": "2025-
|
|
5
|
-
"count":
|
|
3
|
+
"catalogVersion": "2025.10.02",
|
|
4
|
+
"dateReleased": "2025-10-02T14:59:13.7696Z",
|
|
5
|
+
"count": 1427,
|
|
6
6
|
"vulnerabilities": [
|
|
7
|
+
{
|
|
8
|
+
"cveID": "CVE-2014-6278",
|
|
9
|
+
"vendorProject": "GNU",
|
|
10
|
+
"product": "GNU Bash",
|
|
11
|
+
"vulnerabilityName": "GNU Bash OS Command Injection Vulnerability",
|
|
12
|
+
"dateAdded": "2025-10-02",
|
|
13
|
+
"shortDescription": "GNU Bash contains an OS command injection vulnerability which allows remote attackers to execute arbitrary commands via a crafted environment.",
|
|
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-10-23",
|
|
16
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
+
"notes": "This vulnerability could affect an open-source component, third-party library, protocol, or proprietary implementation that could be used by different products. For more information, please see: http:\/\/ftp.gnu.org\/gnu\/bash\/bash-4.3-patches\/bash43-027 ; https:\/\/support.broadcom.com\/web\/ecx\/support-content-notification\/-\/external\/content\/SecurityAdvisories\/0\/23467 ; https:\/\/sec.cloudapps.cisco.com\/security\/center\/content\/CiscoSecurityAdvisory\/cisco-sa-20140926-bash ; https:\/\/www.ibm.com\/support\/pages\/security-bulletin-update-vulnerabilities-bash-affect-aix-toolbox-linux-applications-cve-2014-6271-cve-2014-6277-cve-2014-6278-cve-2014-7169-cve-2014-7186-and-cve-2014-7187 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2014-6278",
|
|
18
|
+
"cwes": [
|
|
19
|
+
"CWE-78"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"cveID": "CVE-2017-1000353",
|
|
24
|
+
"vendorProject": "Jenkins",
|
|
25
|
+
"product": "Jenkins",
|
|
26
|
+
"vulnerabilityName": "Jenkins Remote Code Execution Vulnerability",
|
|
27
|
+
"dateAdded": "2025-10-02",
|
|
28
|
+
"shortDescription": "Jenkins contains a remote code execution vulnerability. This vulnerability that could allowed attackers to transfer a serialized Java SignedObject object to the remoting-based Jenkins CLI, that would be deserialized using a new ObjectInputStream, bypassing the existing blocklist-based protection mechanism.",
|
|
29
|
+
"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.",
|
|
30
|
+
"dueDate": "2025-10-23",
|
|
31
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
32
|
+
"notes": "https:\/\/www.jenkins.io\/security\/advisory\/2017-04-26\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2017-1000353",
|
|
33
|
+
"cwes": []
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"cveID": "CVE-2015-7755",
|
|
37
|
+
"vendorProject": "Juniper",
|
|
38
|
+
"product": "ScreenOS",
|
|
39
|
+
"vulnerabilityName": "Juniper ScreenOS Improper Authentication Vulnerability",
|
|
40
|
+
"dateAdded": "2025-10-02",
|
|
41
|
+
"shortDescription": "Juniper ScreenOS contains an improper authentication vulnerability that could allow unauthorized remote administrative access to the device.",
|
|
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-10-23",
|
|
44
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
45
|
+
"notes": "https:\/\/supportportal.juniper.net\/s\/article\/2015-12-Out-of-Cycle-Security-Bulletin-ScreenOS-Multiple-Security-issues-with-ScreenOS-CVE-2015-7755-CVE-2015-7756 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2015-7755",
|
|
46
|
+
"cwes": [
|
|
47
|
+
"CWE-287"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"cveID": "CVE-2025-21043",
|
|
52
|
+
"vendorProject": "Samsung",
|
|
53
|
+
"product": "Mobile Devices",
|
|
54
|
+
"vulnerabilityName": "Samsung Mobile Devices Out-of-Bounds Write Vulnerability",
|
|
55
|
+
"dateAdded": "2025-10-02",
|
|
56
|
+
"shortDescription": "Samsung mobile devices contain an out-of-bounds write vulnerability in libimagecodec.quram.so which allows remote attackers to execute arbitrary code.",
|
|
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-10-23",
|
|
59
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
60
|
+
"notes": "https:\/\/security.samsungmobile.com\/securityUpdate.smsb?year=2025&month=09 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-21043",
|
|
61
|
+
"cwes": [
|
|
62
|
+
"CWE-787"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"cveID": "CVE-2025-4008",
|
|
67
|
+
"vendorProject": "Smartbedded",
|
|
68
|
+
"product": "Meteobridge",
|
|
69
|
+
"vulnerabilityName": "Smartbedded Meteobridge Command Injection Vulnerability",
|
|
70
|
+
"dateAdded": "2025-10-02",
|
|
71
|
+
"shortDescription": "Smartbedded Meteobridge contains a command injection vulnerability that could allow remote unauthenticated attackers to gain arbitrary command execution with elevated privileges (root) on affected devices.",
|
|
72
|
+
"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.",
|
|
73
|
+
"dueDate": "2025-10-23",
|
|
74
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
75
|
+
"notes": "https:\/\/forum.meteohub.de\/viewtopic.php?t=18687 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-4008",
|
|
76
|
+
"cwes": [
|
|
77
|
+
"CWE-306",
|
|
78
|
+
"CWE-77"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"cveID": "CVE-2025-32463",
|
|
83
|
+
"vendorProject": "Sudo",
|
|
84
|
+
"product": "Sudo",
|
|
85
|
+
"vulnerabilityName": "Sudo Inclusion of Functionality from Untrusted Control Sphere Vulnerability",
|
|
86
|
+
"dateAdded": "2025-09-29",
|
|
87
|
+
"shortDescription": "Sudo contains an inclusion of functionality from untrusted control sphere vulnerability. This vulnerability could allow local attacker to leverage sudo\u2019s -R (--chroot) option to run arbitrary commands as root, even if they are not listed in the sudoers file.",
|
|
88
|
+
"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.",
|
|
89
|
+
"dueDate": "2025-10-20",
|
|
90
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
91
|
+
"notes": "This vulnerability could affect an open-source component, third-party library, protocol, or proprietary implementation that could be used by different products. For more information, please see: https:\/\/www.sudo.ws\/security\/advisories\/chroot_bug\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-32463",
|
|
92
|
+
"cwes": [
|
|
93
|
+
"CWE-829"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"cveID": "CVE-2025-59689",
|
|
98
|
+
"vendorProject": "Libraesva",
|
|
99
|
+
"product": "Email Security Gateway",
|
|
100
|
+
"vulnerabilityName": "Libraesva Email Security Gateway Command Injection Vulnerability",
|
|
101
|
+
"dateAdded": "2025-09-29",
|
|
102
|
+
"shortDescription": "Libraesva Email Security Gateway (ESG) contains a command injection vulnerability which allows command injection via a compressed e-mail attachment.",
|
|
103
|
+
"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.",
|
|
104
|
+
"dueDate": "2025-10-20",
|
|
105
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
106
|
+
"notes": "https:\/\/docs.libraesva.com\/knowledgebase\/security-advisory-command-injection-vulnerability-cve-2025-59689\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-59689",
|
|
107
|
+
"cwes": [
|
|
108
|
+
"CWE-77"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"cveID": "CVE-2025-10035",
|
|
113
|
+
"vendorProject": "Fortra",
|
|
114
|
+
"product": "GoAnywhere MFT",
|
|
115
|
+
"vulnerabilityName": "Fortra GoAnywhere MFT Deserialization of Untrusted Data Vulnerability",
|
|
116
|
+
"dateAdded": "2025-09-29",
|
|
117
|
+
"shortDescription": "Fortra GoAnywhere MFT contains a deserialization of untrusted data vulnerability allows an actor with a validly forged license response signature to deserialize an arbitrary actor-controlled object, possibly leading to command injection.",
|
|
118
|
+
"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.",
|
|
119
|
+
"dueDate": "2025-10-20",
|
|
120
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
121
|
+
"notes": "https:\/\/www.fortra.com\/security\/advisories\/product-security\/fi-2025-012 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-10035",
|
|
122
|
+
"cwes": [
|
|
123
|
+
"CWE-502",
|
|
124
|
+
"CWE-77"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"cveID": "CVE-2025-20352",
|
|
129
|
+
"vendorProject": "Cisco",
|
|
130
|
+
"product": "IOS and IOS XE",
|
|
131
|
+
"vulnerabilityName": "Cisco IOS and IOS XE Software SNMP Denial of Service and Remote Code Execution Vulnerability",
|
|
132
|
+
"dateAdded": "2025-09-29",
|
|
133
|
+
"shortDescription": "Cisco IOS and IOS XE contains a stack-based buffer overflow vulnerability in the Simple Network Management Protocol (SNMP) subsystem that could allow for denial of service or remote code execution. A successful exploit could allow a low-privileged attacker to cause the affected system to reload, resulting in a DoS condition, or allow a high-privileged attacker to execute arbitrary code as the root user and obtain full control of the affected system.",
|
|
134
|
+
"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.",
|
|
135
|
+
"dueDate": "2025-10-20",
|
|
136
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
137
|
+
"notes": "https:\/\/sec.cloudapps.cisco.com\/security\/center\/content\/CiscoSecurityAdvisory\/cisco-sa-snmp-x4LPhte ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-20352",
|
|
138
|
+
"cwes": [
|
|
139
|
+
"CWE-121"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"cveID": "CVE-2021-21311",
|
|
144
|
+
"vendorProject": "Adminer",
|
|
145
|
+
"product": "Adminer",
|
|
146
|
+
"vulnerabilityName": "Adminer Server-Side Request Forgery Vulnerability",
|
|
147
|
+
"dateAdded": "2025-09-29",
|
|
148
|
+
"shortDescription": "Adminer contains a server-side request forgery vulnerability that, when exploited, allows a remote attacker to obtain potentially sensitive information.",
|
|
149
|
+
"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.",
|
|
150
|
+
"dueDate": "2025-10-20",
|
|
151
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
152
|
+
"notes": "https:\/\/github.com\/vrana\/adminer\/security\/advisories\/GHSA-x5r2-hj5c-8jx6 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-21311",
|
|
153
|
+
"cwes": [
|
|
154
|
+
"CWE-918"
|
|
155
|
+
]
|
|
156
|
+
},
|
|
7
157
|
{
|
|
8
158
|
"cveID": "CVE-2025-20362",
|
|
9
159
|
"vendorProject": "Cisco",
|
|
@@ -2489,7 +2639,7 @@
|
|
|
2489
2639
|
"requiredAction": "Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.",
|
|
2490
2640
|
"dueDate": "2025-02-13",
|
|
2491
2641
|
"knownRansomwareCampaignUse": "Unknown",
|
|
2492
|
-
"notes": "https:\/\/blog.jquery.com\/2020\/04\/10\/jquery-3-5-0-released\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2020-11023",
|
|
2642
|
+
"notes": "This vulnerability could affect an open-source component, third-party library, protocol, or proprietary implementation that could be used by different products. For more information, please see: https:\/\/github.com\/jquery\/jquery\/security\/advisories\/GHSA-jpcq-cgw6-v4j6 ; https:\/\/blog.jquery.com\/2020\/04\/10\/jquery-3-5-0-released\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2020-11023",
|
|
2493
2643
|
"cwes": [
|
|
2494
2644
|
"CWE-79"
|
|
2495
2645
|
]
|
|
@@ -25,11 +25,11 @@ CVE = "CVEs"
|
|
|
25
25
|
|
|
26
26
|
class Nexpose(FlatFileImporter): # pylint: disable=too-many-instance-attributes
|
|
27
27
|
"""
|
|
28
|
-
Nexpose Scan information
|
|
28
|
+
Nexpose Scan information with FedRAMP POAM export support
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
def __init__(self, **kwargs): # pylint: disable=R0902
|
|
32
|
-
self.name = kwargs.get("name")
|
|
32
|
+
self.name: str = kwargs.get("name", "Nexpose")
|
|
33
33
|
self.vuln_title = VULNERABILITY_TITLE
|
|
34
34
|
self.vuln_id = VULNERABILITY_ID
|
|
35
35
|
self.cvss3_score = CVSS3_SCORE
|
|
@@ -46,13 +46,18 @@ class Nexpose(FlatFileImporter): # pylint: disable=too-many-instance-attributes
|
|
|
46
46
|
"Solution",
|
|
47
47
|
"CVEs",
|
|
48
48
|
]
|
|
49
|
-
self.mapping_file = kwargs.get("mappings_path")
|
|
50
|
-
self.disable_mapping = kwargs.get("disable_mapping")
|
|
49
|
+
self.mapping_file: Optional[str] = kwargs.get("mappings_path")
|
|
50
|
+
self.disable_mapping: Optional[bool] = kwargs.get("disable_mapping")
|
|
51
|
+
file_path: Optional[str] = kwargs.get("file_path")
|
|
51
52
|
self.validater = ImportValidater(
|
|
52
|
-
self.required_headers,
|
|
53
|
+
self.required_headers, file_path or "", self.mapping_file or "", self.disable_mapping or False
|
|
53
54
|
)
|
|
54
55
|
self.headers = self.validater.parsed_headers
|
|
55
56
|
self.mapping = self.validater.mapping
|
|
57
|
+
|
|
58
|
+
# Store file path for property generation
|
|
59
|
+
self.file_path = kwargs.get("file_path")
|
|
60
|
+
|
|
56
61
|
logger = create_logger()
|
|
57
62
|
super().__init__(
|
|
58
63
|
logger=logger,
|
|
@@ -127,6 +132,8 @@ class Nexpose(FlatFileImporter): # pylint: disable=too-many-instance-attributes
|
|
|
127
132
|
:return: IssueSeverity or None
|
|
128
133
|
:rtype: Optional[IssueSeverity]
|
|
129
134
|
"""
|
|
135
|
+
if not text_severity:
|
|
136
|
+
return None
|
|
130
137
|
if text_severity.lower() == "low":
|
|
131
138
|
return IssueSeverity.Low
|
|
132
139
|
if text_severity.lower() in ["medium", "moderate"]:
|
|
@@ -170,9 +177,30 @@ class Nexpose(FlatFileImporter): # pylint: disable=too-many-instance-attributes
|
|
|
170
177
|
|
|
171
178
|
return severity
|
|
172
179
|
|
|
173
|
-
def
|
|
180
|
+
def get_source_file_path(self) -> Optional[str]:
|
|
174
181
|
"""
|
|
175
|
-
|
|
182
|
+
Get source file path for POAM ID generation
|
|
183
|
+
|
|
184
|
+
Returns file_path if set, None otherwise.
|
|
185
|
+
This supports FedRAMP POAM export logic that generates POAM IDs
|
|
186
|
+
based on source file path properties (e.g., pdf, signatures, campaign, etc.)
|
|
187
|
+
|
|
188
|
+
Note: Properties must be created separately after Issue creation using
|
|
189
|
+
Property.create() or bulk operations, as IntegrationFinding doesn't
|
|
190
|
+
directly support properties.
|
|
191
|
+
|
|
192
|
+
:return: Source file path string or None
|
|
193
|
+
:rtype: Optional[str]
|
|
194
|
+
"""
|
|
195
|
+
if not self.file_path:
|
|
196
|
+
return None
|
|
197
|
+
return str(self.file_path)
|
|
198
|
+
|
|
199
|
+
def create_vuln(
|
|
200
|
+
self, dat: Optional[dict] = None, **kwargs
|
|
201
|
+
) -> Optional[IntegrationFinding]: # pylint: disable=unused-argument
|
|
202
|
+
"""
|
|
203
|
+
Create an IntegrationFinding from a row in the Nexpose csv file
|
|
176
204
|
|
|
177
205
|
:param Optional[dict] dat: Data row from CSV file, defaults to None
|
|
178
206
|
:param kwargs: Additional keyword arguments
|
|
@@ -189,8 +217,6 @@ class Nexpose(FlatFileImporter): # pylint: disable=too-many-instance-attributes
|
|
|
189
217
|
# Determine severity using priority logic
|
|
190
218
|
severity = self._determine_severity(dat)
|
|
191
219
|
|
|
192
|
-
# Find matching asset
|
|
193
|
-
|
|
194
220
|
# Extract date information
|
|
195
221
|
first_seen = (
|
|
196
222
|
self.mapping.get_value(dat, self.first_seen)
|
|
@@ -216,7 +242,7 @@ class Nexpose(FlatFileImporter): # pylint: disable=too-many-instance-attributes
|
|
|
216
242
|
cvss_score=cvss_score or 0.0,
|
|
217
243
|
cvss_v3_score=cvss3_score or 0.0,
|
|
218
244
|
cvss_v2_score=cvss_score or 0.0,
|
|
219
|
-
plugin_text=description[:255],
|
|
245
|
+
plugin_text=description[:255] if description else "",
|
|
220
246
|
remediation=self.mapping.get_value(dat, "Solution"),
|
|
221
247
|
category="Hardware",
|
|
222
248
|
status=IssueStatus.Open,
|