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
|
@@ -28,7 +28,7 @@ from regscale.integrations.commercial.durosuite.variables import DuroSuiteVariab
|
|
|
28
28
|
from regscale.integrations.commercial.stig_mapper_integration.mapping_engine import StigMappingEngine as STIGMapper
|
|
29
29
|
from regscale.integrations.public.cisa import pull_cisa_kev
|
|
30
30
|
from regscale.integrations.variables import ScannerVariables
|
|
31
|
-
from regscale.models import DateTimeEncoder, OpenIssueDict, regscale_models
|
|
31
|
+
from regscale.models import DateTimeEncoder, OpenIssueDict, Property, regscale_models
|
|
32
32
|
from regscale.utils.threading import ThreadSafeDict, ThreadSafeList
|
|
33
33
|
|
|
34
34
|
logger = logging.getLogger(__name__)
|
|
@@ -407,7 +407,7 @@ class IntegrationFinding:
|
|
|
407
407
|
issue_type: str = "Risk"
|
|
408
408
|
date_created: str = dataclasses.field(default_factory=get_current_datetime)
|
|
409
409
|
date_last_updated: str = dataclasses.field(default_factory=get_current_datetime)
|
|
410
|
-
due_date: str = dataclasses.field(default_factory=lambda: date_str(days_from_today(60)))
|
|
410
|
+
due_date: str = "" # dataclasses.field(default_factory=lambda: date_str(days_from_today(60)))
|
|
411
411
|
external_id: str = ""
|
|
412
412
|
gaps: str = ""
|
|
413
413
|
observations: str = ""
|
|
@@ -463,6 +463,9 @@ class IntegrationFinding:
|
|
|
463
463
|
# Additional fields from Wiz integration
|
|
464
464
|
vpr_score: Optional[float] = None
|
|
465
465
|
|
|
466
|
+
# Extra data field for miscellaneous data
|
|
467
|
+
extra_data: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
|
468
|
+
|
|
466
469
|
def __post_init__(self):
|
|
467
470
|
"""Validate and adjust types after initialization."""
|
|
468
471
|
# Set default date values if empty
|
|
@@ -1646,25 +1649,34 @@ class ScannerIntegration(ABC):
|
|
|
1646
1649
|
issue.dateLastUpdated = get_current_datetime()
|
|
1647
1650
|
|
|
1648
1651
|
if finding.cve:
|
|
1649
|
-
issue = self.
|
|
1652
|
+
issue = self.lookup_kev_and_update_issue(cve=finding.cve, issue=issue, cisa_kevs=self._kev_data)
|
|
1650
1653
|
|
|
1651
1654
|
if existing_issue:
|
|
1652
|
-
logger.debug("Saving
|
|
1655
|
+
logger.debug("Saving Old Issue: %s with assetIdentifier: %s", issue.id, issue.assetIdentifier)
|
|
1653
1656
|
issue.save(bulk=True)
|
|
1657
|
+
logger.debug("Saved existing issue %s with assetIdentifier: %s", issue.id, issue.assetIdentifier)
|
|
1658
|
+
|
|
1654
1659
|
else:
|
|
1655
1660
|
issue = issue.create_or_update(
|
|
1656
1661
|
bulk_update=True, defaults={"otherIdentifier": self._get_other_identifier(finding, is_poam)}
|
|
1657
1662
|
)
|
|
1663
|
+
self.extra_data_to_properties(finding, issue.id)
|
|
1658
1664
|
|
|
1659
|
-
self.
|
|
1665
|
+
self._handle_property_and_milestone_creation(issue, finding, existing_issue)
|
|
1660
1666
|
return issue
|
|
1661
1667
|
|
|
1662
|
-
def
|
|
1668
|
+
def _handle_property_and_milestone_creation(
|
|
1669
|
+
self,
|
|
1670
|
+
issue: regscale_models.Issue,
|
|
1671
|
+
finding: IntegrationFinding,
|
|
1672
|
+
existing_issue: Optional[regscale_models.Issue] = None,
|
|
1673
|
+
) -> None:
|
|
1663
1674
|
"""
|
|
1664
1675
|
Handles property creation for an issue based on the finding data
|
|
1665
1676
|
|
|
1666
1677
|
:param regscale_models.Issue issue: The issue to handle properties for
|
|
1667
1678
|
:param IntegrationFinding finding: The finding data
|
|
1679
|
+
:param bool new_issue: Whether this is a new issue
|
|
1668
1680
|
:rtype: None
|
|
1669
1681
|
"""
|
|
1670
1682
|
if poc := finding.point_of_contact:
|
|
@@ -1685,6 +1697,74 @@ class ScannerIntegration(ABC):
|
|
|
1685
1697
|
).create_or_update()
|
|
1686
1698
|
logger.debug("Added CWE property %s to issue %s", finding.plugin_id, issue.id)
|
|
1687
1699
|
|
|
1700
|
+
if ScannerVariables.useMilestones:
|
|
1701
|
+
if (
|
|
1702
|
+
existing_issue
|
|
1703
|
+
and existing_issue.status == regscale_models.IssueStatus.Closed
|
|
1704
|
+
and issue.status == regscale_models.IssueStatus.Open
|
|
1705
|
+
):
|
|
1706
|
+
regscale_models.Milestone(
|
|
1707
|
+
title=f"Issue reopened from {self.title} scan",
|
|
1708
|
+
milestoneDate=get_current_datetime(),
|
|
1709
|
+
responsiblePersonId=self.assessor_id,
|
|
1710
|
+
parentID=issue.id,
|
|
1711
|
+
parentModule="issues",
|
|
1712
|
+
).create_or_update()
|
|
1713
|
+
logger.debug("Added milestone for issue %s from finding %s", issue.id, finding.external_id)
|
|
1714
|
+
elif (
|
|
1715
|
+
existing_issue
|
|
1716
|
+
and existing_issue.status == regscale_models.IssueStatus.Open
|
|
1717
|
+
and issue.status == regscale_models.IssueStatus.Closed
|
|
1718
|
+
):
|
|
1719
|
+
regscale_models.Milestone(
|
|
1720
|
+
title=f"Issue closed from {self.title} scan",
|
|
1721
|
+
milestoneDate=issue.dateCompleted,
|
|
1722
|
+
responsiblePersonId=self.assessor_id,
|
|
1723
|
+
parentID=issue.id,
|
|
1724
|
+
parentModule="issues",
|
|
1725
|
+
).create_or_update()
|
|
1726
|
+
logger.debug("Added milestone for issue %s from finding %s", issue.id, finding.external_id)
|
|
1727
|
+
elif not existing_issue:
|
|
1728
|
+
regscale_models.Milestone(
|
|
1729
|
+
title=f"Issue created from {self.title} scan",
|
|
1730
|
+
milestoneDate=self.scan_date,
|
|
1731
|
+
responsiblePersonId=self.assessor_id,
|
|
1732
|
+
parentID=issue.id,
|
|
1733
|
+
parentModule="issues",
|
|
1734
|
+
).create_or_update()
|
|
1735
|
+
logger.debug("Created milestone for issue %s from finding %s", issue.id, finding.external_id)
|
|
1736
|
+
else:
|
|
1737
|
+
logger.debug("No milestone created for issue %s from finding %s", issue.id, finding.external_id)
|
|
1738
|
+
|
|
1739
|
+
@staticmethod
|
|
1740
|
+
def extra_data_to_properties(finding: IntegrationFinding, issue_id: int) -> None:
|
|
1741
|
+
"""
|
|
1742
|
+
Adds extra data to properties for an issue in a separate thread
|
|
1743
|
+
|
|
1744
|
+
:param IntegrationFinding finding: The finding data
|
|
1745
|
+
:param int issue_id: The ID of the issue
|
|
1746
|
+
:rtype: None
|
|
1747
|
+
"""
|
|
1748
|
+
|
|
1749
|
+
def _create_property():
|
|
1750
|
+
"""Create the property in a separate thread"""
|
|
1751
|
+
if not finding.extra_data:
|
|
1752
|
+
return
|
|
1753
|
+
try:
|
|
1754
|
+
Property(
|
|
1755
|
+
key="source_file_path",
|
|
1756
|
+
value=finding.extra_data.get("source_file_path"),
|
|
1757
|
+
parentId=issue_id,
|
|
1758
|
+
parentModule="issues",
|
|
1759
|
+
).create()
|
|
1760
|
+
except Exception as exc:
|
|
1761
|
+
# Log any errors that occur in the thread
|
|
1762
|
+
logger.error(f"Error creating property for issue {issue_id}: {exc}")
|
|
1763
|
+
|
|
1764
|
+
# Start the property creation in a separate thread
|
|
1765
|
+
thread = threading.Thread(target=_create_property, daemon=True)
|
|
1766
|
+
thread.start()
|
|
1767
|
+
|
|
1688
1768
|
@staticmethod
|
|
1689
1769
|
def get_consolidated_asset_identifier(
|
|
1690
1770
|
finding: IntegrationFinding,
|
|
@@ -1731,7 +1811,7 @@ class ScannerIntegration(ABC):
|
|
|
1731
1811
|
return None
|
|
1732
1812
|
|
|
1733
1813
|
@staticmethod
|
|
1734
|
-
def
|
|
1814
|
+
def lookup_kev_and_update_issue(
|
|
1735
1815
|
cve: str, issue: regscale_models.Issue, cisa_kevs: Optional[ThreadSafeDict[str, Any]] = None
|
|
1736
1816
|
) -> regscale_models.Issue:
|
|
1737
1817
|
"""
|
|
@@ -1759,7 +1839,14 @@ class ScannerIntegration(ABC):
|
|
|
1759
1839
|
None,
|
|
1760
1840
|
)
|
|
1761
1841
|
if kev_data:
|
|
1762
|
-
issue
|
|
1842
|
+
# If kev due date is before the issue date created, add the difference to the date created
|
|
1843
|
+
calculated_due_date = ScannerIntegration._calculate_kev_due_date(kev_data, issue.dateCreated)
|
|
1844
|
+
if calculated_due_date:
|
|
1845
|
+
issue.dueDate = calculated_due_date
|
|
1846
|
+
else:
|
|
1847
|
+
issue.dueDate = convert_datetime_to_regscale_string(
|
|
1848
|
+
datetime.strptime(kev_data["dueDate"], "%Y-%m-%d")
|
|
1849
|
+
)
|
|
1763
1850
|
issue.kevList = "Yes"
|
|
1764
1851
|
|
|
1765
1852
|
return issue
|
|
@@ -2523,6 +2610,17 @@ class ScannerIntegration(ABC):
|
|
|
2523
2610
|
issue.dateLastUpdated = get_current_datetime()
|
|
2524
2611
|
issue.save()
|
|
2525
2612
|
|
|
2613
|
+
if ScannerVariables.useMilestones:
|
|
2614
|
+
regscale_models.Milestone(
|
|
2615
|
+
title=f"Issue closed from {self.title} scan",
|
|
2616
|
+
milestoneDate=issue.dateCompleted,
|
|
2617
|
+
responsiblePersonId=self.assessor_id,
|
|
2618
|
+
completed=True,
|
|
2619
|
+
parentID=issue.id,
|
|
2620
|
+
parentModule="issues",
|
|
2621
|
+
).create_or_update()
|
|
2622
|
+
logger.debug("Created milestone for issue %s from %s tool", issue.id, self.title)
|
|
2623
|
+
|
|
2526
2624
|
with count_lock:
|
|
2527
2625
|
self.closed_count += 1
|
|
2528
2626
|
if issue.controlImplementationIds:
|
|
@@ -2600,6 +2698,9 @@ class ScannerIntegration(ABC):
|
|
|
2600
2698
|
"""
|
|
2601
2699
|
# Do not close issues from other tools
|
|
2602
2700
|
if issue.sourceReport != self.title:
|
|
2701
|
+
logger.debug(
|
|
2702
|
+
"Skipping issue %d from different source: %s (expected: %s)", issue.id, issue.sourceReport, self.title
|
|
2703
|
+
)
|
|
2603
2704
|
return False
|
|
2604
2705
|
|
|
2605
2706
|
# If the issue has a vulnerability ID, check if it's still current for any asset
|
|
@@ -2611,14 +2712,19 @@ class ScannerIntegration(ABC):
|
|
|
2611
2712
|
|
|
2612
2713
|
# Check if the issue's vulnerability is still current for any asset
|
|
2613
2714
|
# If it is, we shouldn't close the issue
|
|
2614
|
-
|
|
2615
|
-
mapping.assetId in current_vulnerabilities
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2715
|
+
for mapping in vuln_mappings:
|
|
2716
|
+
if mapping.assetId in current_vulnerabilities:
|
|
2717
|
+
if issue.vulnerabilityId in current_vulnerabilities[mapping.assetId]:
|
|
2718
|
+
logger.debug(
|
|
2719
|
+
"Issue %d has current vulnerability %d for asset %d",
|
|
2720
|
+
issue.id,
|
|
2721
|
+
issue.vulnerabilityId,
|
|
2722
|
+
mapping.assetId,
|
|
2723
|
+
)
|
|
2724
|
+
return False
|
|
2620
2725
|
|
|
2621
2726
|
# If we've checked all conditions and found no current vulnerabilities, we should close it
|
|
2727
|
+
logger.debug("Issue %d has no current vulnerabilities, marking for closure", issue.id)
|
|
2622
2728
|
return True
|
|
2623
2729
|
|
|
2624
2730
|
@staticmethod
|
|
@@ -2901,6 +3007,65 @@ class ScannerIntegration(ABC):
|
|
|
2901
3007
|
finding.first_seen = self.scan_date
|
|
2902
3008
|
return existing_vuln
|
|
2903
3009
|
|
|
3010
|
+
def _update_first_seen_date(
|
|
3011
|
+
self, finding: IntegrationFinding, existing_vuln: Optional[regscale_models.VulnerabilityMapping]
|
|
3012
|
+
) -> None:
|
|
3013
|
+
"""
|
|
3014
|
+
Update the first_seen date based on existing vulnerability mapping or scan date.
|
|
3015
|
+
|
|
3016
|
+
:param IntegrationFinding finding: The integration finding
|
|
3017
|
+
:param Optional[regscale_models.VulnerabilityMapping] existing_vuln: The existing vulnerability mapping
|
|
3018
|
+
:return: None
|
|
3019
|
+
:rtype: None
|
|
3020
|
+
"""
|
|
3021
|
+
if existing_vuln and existing_vuln.firstSeen:
|
|
3022
|
+
finding.first_seen = existing_vuln.firstSeen
|
|
3023
|
+
elif not finding.first_seen:
|
|
3024
|
+
finding.first_seen = self.scan_date
|
|
3025
|
+
|
|
3026
|
+
def _update_date_created(self, finding: IntegrationFinding, issue: Optional[regscale_models.Issue]) -> None:
|
|
3027
|
+
"""
|
|
3028
|
+
Update the date_created based on issue or scan date.
|
|
3029
|
+
|
|
3030
|
+
:param IntegrationFinding finding: The integration finding
|
|
3031
|
+
:param Optional[regscale_models.Issue] issue: The existing issue
|
|
3032
|
+
:return: None
|
|
3033
|
+
:rtype: None
|
|
3034
|
+
"""
|
|
3035
|
+
if issue and issue.dateFirstDetected:
|
|
3036
|
+
finding.date_created = issue.dateFirstDetected
|
|
3037
|
+
elif not finding.date_created:
|
|
3038
|
+
finding.date_created = self.scan_date
|
|
3039
|
+
|
|
3040
|
+
def _update_due_date(self, finding: IntegrationFinding) -> None:
|
|
3041
|
+
"""
|
|
3042
|
+
Update the due_date based on severity and configuration.
|
|
3043
|
+
|
|
3044
|
+
:param IntegrationFinding finding: The integration finding
|
|
3045
|
+
:return: None
|
|
3046
|
+
:rtype: None
|
|
3047
|
+
"""
|
|
3048
|
+
finding.due_date = issue_due_date(
|
|
3049
|
+
severity=finding.severity,
|
|
3050
|
+
created_date=finding.date_created or self.scan_date,
|
|
3051
|
+
title=self.title,
|
|
3052
|
+
config=self.app.config,
|
|
3053
|
+
)
|
|
3054
|
+
|
|
3055
|
+
def _update_last_seen_date(self, finding: IntegrationFinding) -> None:
|
|
3056
|
+
"""
|
|
3057
|
+
Update the last_seen date if scan date is after first_seen.
|
|
3058
|
+
|
|
3059
|
+
:param IntegrationFinding finding: The integration finding
|
|
3060
|
+
:return: None
|
|
3061
|
+
:rtype: None
|
|
3062
|
+
"""
|
|
3063
|
+
scan_date = date_obj(self.scan_date)
|
|
3064
|
+
first_seen = date_obj(finding.first_seen)
|
|
3065
|
+
|
|
3066
|
+
if scan_date and first_seen and scan_date >= first_seen:
|
|
3067
|
+
finding.last_seen = self.scan_date
|
|
3068
|
+
|
|
2904
3069
|
def update_finding_dates(
|
|
2905
3070
|
self,
|
|
2906
3071
|
finding: IntegrationFinding,
|
|
@@ -2916,28 +3081,17 @@ class ScannerIntegration(ABC):
|
|
|
2916
3081
|
:return: The updated integration finding
|
|
2917
3082
|
:rtype: IntegrationFinding
|
|
2918
3083
|
"""
|
|
2919
|
-
if
|
|
2920
|
-
if
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
title=self.title,
|
|
2931
|
-
config=self.app.config,
|
|
2932
|
-
)
|
|
2933
|
-
else:
|
|
2934
|
-
finding.first_seen = existing_vuln.firstSeen if existing_vuln else finding.first_seen
|
|
2935
|
-
if issue:
|
|
2936
|
-
finding.date_created = issue.dateFirstDetected or finding.date_created
|
|
2937
|
-
scan_date = date_obj(self.scan_date)
|
|
2938
|
-
first_seen = date_obj(finding.first_seen)
|
|
2939
|
-
if scan_date and first_seen and scan_date >= first_seen:
|
|
2940
|
-
finding.last_seen = self.scan_date
|
|
3084
|
+
if finding.due_date:
|
|
3085
|
+
# If due_date is already set, only update last_seen if needed
|
|
3086
|
+
self._update_last_seen_date(finding)
|
|
3087
|
+
return finding
|
|
3088
|
+
|
|
3089
|
+
# Update dates for new findings
|
|
3090
|
+
self._update_first_seen_date(finding, existing_vuln)
|
|
3091
|
+
self._update_date_created(finding, issue)
|
|
3092
|
+
self._update_due_date(finding)
|
|
3093
|
+
self._update_last_seen_date(finding)
|
|
3094
|
+
|
|
2941
3095
|
return finding
|
|
2942
3096
|
|
|
2943
3097
|
def update_scan(self, scan_history: regscale_models.ScanHistory) -> None:
|
|
@@ -2991,7 +3145,9 @@ class ScannerIntegration(ABC):
|
|
|
2991
3145
|
:rtype: None
|
|
2992
3146
|
"""
|
|
2993
3147
|
# Method is deprecated - using update_control_implementation_status_after_close instead
|
|
2994
|
-
|
|
3148
|
+
logger.warning(
|
|
3149
|
+
"update_control_implementation_status is deprecated - using update_control_implementation_status_after_close instead"
|
|
3150
|
+
)
|
|
2995
3151
|
|
|
2996
3152
|
def update_regscale_checklists(self, findings: List[IntegrationFinding]) -> int:
|
|
2997
3153
|
"""
|
|
@@ -3074,3 +3230,31 @@ class ScannerIntegration(ABC):
|
|
|
3074
3230
|
impact=finding.impact,
|
|
3075
3231
|
recommendationForMitigation=finding.recommendation_for_mitigation,
|
|
3076
3232
|
).create()
|
|
3233
|
+
|
|
3234
|
+
@staticmethod
|
|
3235
|
+
def _calculate_kev_due_date(kev_data: dict, issue_date_created: str) -> Optional[str]:
|
|
3236
|
+
"""
|
|
3237
|
+
Calculate the due date for a KEV issue based on the difference between
|
|
3238
|
+
KEV due date and date added, then add that difference to the issue creation date.
|
|
3239
|
+
|
|
3240
|
+
:param dict kev_data: KEV data containing dueDate and dateAdded
|
|
3241
|
+
:param str issue_date_created: The issue creation date string
|
|
3242
|
+
:return: Calculated due date as a RegScale formatted string or None
|
|
3243
|
+
:rtype: Optional[str]
|
|
3244
|
+
"""
|
|
3245
|
+
from datetime import datetime
|
|
3246
|
+
|
|
3247
|
+
from regscale.core.app.utils.app_utils import convert_datetime_to_regscale_string
|
|
3248
|
+
|
|
3249
|
+
if datetime.strptime(kev_data["dueDate"], "%Y-%m-%d") < datetime.strptime(
|
|
3250
|
+
issue_date_created, "%Y-%m-%d %H:%M:%S"
|
|
3251
|
+
):
|
|
3252
|
+
# diff kev due date and kev dateAdded
|
|
3253
|
+
diff = datetime.strptime(kev_data["dueDate"], "%Y-%m-%d") - datetime.strptime(
|
|
3254
|
+
kev_data["dateAdded"], "%Y-%m-%d"
|
|
3255
|
+
)
|
|
3256
|
+
# add diff to issue.dateCreated
|
|
3257
|
+
return convert_datetime_to_regscale_string(
|
|
3258
|
+
datetime.strptime(issue_date_created, "%Y-%m-%d %H:%M:%S") + diff
|
|
3259
|
+
)
|
|
3260
|
+
return None
|
|
@@ -26,3 +26,4 @@ class ScannerVariables(metaclass=RsVariablesMeta):
|
|
|
26
26
|
maxRetries: RsVariableType(int, "3", default=3, required=False) # type: ignore
|
|
27
27
|
timeout: RsVariableType(int, "60", default=60, required=False) # type: ignore
|
|
28
28
|
complianceCreation: RsVariableType(str, "Assessment|Issue|POAM", default="Assessment", required=False) # type: ignore # noqa: F722,F821
|
|
29
|
+
useMilestones: RsVariableType(bool, "true|false", default=False, required=False) # type: ignore # noqa: F722,F722,F821
|
|
@@ -3,18 +3,17 @@ AWS Inspector Scan information
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
|
-
from typing import List, Optional, Tuple
|
|
7
|
-
|
|
8
6
|
from pathlib import Path
|
|
7
|
+
from typing import List, Optional, Tuple
|
|
9
8
|
|
|
10
9
|
from regscale.core.app.application import Application
|
|
11
10
|
from regscale.core.app.logz import create_logger
|
|
12
|
-
from regscale.core.app.utils.app_utils import
|
|
11
|
+
from regscale.core.app.utils.app_utils import is_valid_fqdn
|
|
12
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
13
13
|
from regscale.models import ImportValidater
|
|
14
14
|
from regscale.models.integration_models.amazon_models.inspector import InspectorRecord
|
|
15
15
|
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
16
|
-
from regscale.models.regscale_models
|
|
17
|
-
from regscale.models.regscale_models.vulnerability import Vulnerability
|
|
16
|
+
from regscale.models.regscale_models import Asset, AssetStatus, IssueStatus, Vulnerability
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class InspectorScan(FlatFileImporter):
|
|
@@ -101,26 +100,17 @@ class InspectorScan(FlatFileImporter):
|
|
|
101
100
|
# Container Image, Virtual Machine (VM), etc.
|
|
102
101
|
asset_type = self.amazon_type_map().get(dat.resource_type, "Other")
|
|
103
102
|
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"scanningTool": self.name,
|
|
116
|
-
"assetOwnerId": self.config["userId"],
|
|
117
|
-
"assetType": asset_type,
|
|
118
|
-
"fqdn": hostname if is_valid_fqdn(hostname) else None,
|
|
119
|
-
"operatingSystem": Asset.find_os(distro),
|
|
120
|
-
"systemAdministratorId": self.config["userId"],
|
|
121
|
-
"parentId": self.attributes.parent_id,
|
|
122
|
-
"parentModule": self.attributes.parent_module,
|
|
123
|
-
}
|
|
103
|
+
return IntegrationAsset(
|
|
104
|
+
identifier=hostname,
|
|
105
|
+
name=hostname,
|
|
106
|
+
ip_address="0.0.0.0",
|
|
107
|
+
cpu=0,
|
|
108
|
+
ram=0,
|
|
109
|
+
status=AssetStatus.Active.value,
|
|
110
|
+
asset_type=asset_type,
|
|
111
|
+
asset_category="Software",
|
|
112
|
+
operating_system=Asset.find_os(distro),
|
|
113
|
+
fqdn=hostname if is_valid_fqdn(hostname) else None,
|
|
124
114
|
)
|
|
125
115
|
|
|
126
116
|
def create_vuln(self, dat: Optional[InspectorRecord] = None, **kwargs) -> Optional[Vulnerability]:
|
|
@@ -132,44 +122,29 @@ class InspectorScan(FlatFileImporter):
|
|
|
132
122
|
:rtype: Optional[Vulnerability]
|
|
133
123
|
"""
|
|
134
124
|
hostname = dat.resource_id
|
|
135
|
-
distro = dat.platform
|
|
136
125
|
cve: str = dat.vulnerability_id
|
|
137
126
|
description: str = dat.description
|
|
138
127
|
title = dat.title if dat.title else dat.description
|
|
139
128
|
aws_severity = dat.severity
|
|
140
129
|
severity = self.severity_mapper(aws_severity)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if dat and asset_match:
|
|
145
|
-
return Vulnerability(
|
|
146
|
-
id=0,
|
|
147
|
-
scanId=0, # set later
|
|
148
|
-
parentId=asset.id,
|
|
149
|
-
parentModule="assets",
|
|
150
|
-
ipAddress="0.0.0.0", # No ip address available
|
|
151
|
-
lastSeen=dat.last_seen,
|
|
152
|
-
firstSeen=dat.first_seen,
|
|
153
|
-
daysOpen=None,
|
|
154
|
-
dns=hostname,
|
|
155
|
-
mitigated=None,
|
|
156
|
-
operatingSystem=(Asset.find_os(distro) if Asset.find_os(distro) else None),
|
|
157
|
-
severity=severity,
|
|
158
|
-
plugInName=dat.title,
|
|
159
|
-
plugInId=self.convert_cve_string_to_int(dat.vulnerability_id),
|
|
160
|
-
cve=cve,
|
|
161
|
-
vprScore=None,
|
|
162
|
-
tenantsId=0,
|
|
163
|
-
title=f"{description} on asset {asset.name}",
|
|
130
|
+
if dat:
|
|
131
|
+
return IntegrationFinding(
|
|
132
|
+
title=title,
|
|
164
133
|
description=description,
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
134
|
+
severity=self.determine_severity(severity),
|
|
135
|
+
status=IssueStatus.Open.value,
|
|
136
|
+
ip_address="0.0.0.0",
|
|
137
|
+
plugin_text=title,
|
|
138
|
+
plugin_name=dat.title,
|
|
139
|
+
plugin_id=self.convert_cve_string_to_int(dat.vulnerability_id),
|
|
140
|
+
asset_identifier=hostname,
|
|
141
|
+
remediation=dat.remediation,
|
|
142
|
+
cve=cve,
|
|
143
|
+
first_seen=dat.first_seen,
|
|
144
|
+
last_seen=dat.last_seen,
|
|
145
|
+
scan_date=self.scan_date,
|
|
146
|
+
category="Software",
|
|
147
|
+
control_labels=[],
|
|
173
148
|
)
|
|
174
149
|
return None
|
|
175
150
|
|