regscale-cli 6.17.0.0__py3-none-any.whl → 6.19.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/__init__.py +1 -1
- regscale/core/app/api.py +5 -0
- regscale/core/login.py +3 -0
- regscale/integrations/api_paginator.py +932 -0
- regscale/integrations/api_paginator_example.py +348 -0
- regscale/integrations/commercial/__init__.py +11 -10
- regscale/integrations/commercial/burp.py +4 -0
- regscale/integrations/commercial/{qualys.py → qualys/__init__.py} +756 -105
- regscale/integrations/commercial/qualys/scanner.py +1051 -0
- regscale/integrations/commercial/qualys/variables.py +21 -0
- regscale/integrations/commercial/sicura/api.py +1 -0
- regscale/integrations/commercial/stigv2/click_commands.py +36 -8
- regscale/integrations/commercial/stigv2/stig_integration.py +63 -9
- regscale/integrations/commercial/tenablev2/__init__.py +9 -0
- regscale/integrations/commercial/tenablev2/authenticate.py +23 -2
- regscale/integrations/commercial/tenablev2/commands.py +779 -0
- regscale/integrations/commercial/tenablev2/jsonl_scanner.py +1999 -0
- regscale/integrations/commercial/tenablev2/sc_scanner.py +600 -0
- regscale/integrations/commercial/tenablev2/scanner.py +7 -5
- regscale/integrations/commercial/tenablev2/utils.py +21 -4
- regscale/integrations/commercial/tenablev2/variables.py +4 -0
- regscale/integrations/jsonl_scanner_integration.py +523 -142
- regscale/integrations/scanner_integration.py +102 -26
- regscale/integrations/transformer/__init__.py +17 -0
- regscale/integrations/transformer/data_transformer.py +445 -0
- regscale/integrations/transformer/mappings/__init__.py +8 -0
- regscale/integrations/variables.py +2 -0
- regscale/models/__init__.py +5 -2
- regscale/models/integration_models/cisa_kev_data.json +63 -7
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/regscale_models/asset.py +5 -2
- regscale/models/regscale_models/file.py +5 -2
- regscale/regscale.py +3 -1
- {regscale_cli-6.17.0.0.dist-info → regscale_cli-6.19.0.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.17.0.0.dist-info → regscale_cli-6.19.0.0.dist-info}/RECORD +47 -31
- tests/regscale/core/test_version.py +22 -0
- tests/regscale/integrations/__init__.py +0 -0
- tests/regscale/integrations/test_api_paginator.py +597 -0
- tests/regscale/integrations/test_integration_mapping.py +60 -0
- tests/regscale/integrations/test_issue_creation.py +317 -0
- tests/regscale/integrations/test_issue_due_date.py +46 -0
- tests/regscale/integrations/transformer/__init__.py +0 -0
- tests/regscale/integrations/transformer/test_data_transformer.py +850 -0
- regscale/integrations/commercial/tenablev2/click.py +0 -1637
- {regscale_cli-6.17.0.0.dist-info → regscale_cli-6.19.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.17.0.0.dist-info → regscale_cli-6.19.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.17.0.0.dist-info → regscale_cli-6.19.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.17.0.0.dist-info → regscale_cli-6.19.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Qualys Integration Variables"""
|
|
4
|
+
|
|
5
|
+
from regscale.integrations.variables import RsVariablesMeta, RsVariableType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QualysVariables(metaclass=RsVariablesMeta):
|
|
9
|
+
"""
|
|
10
|
+
Qualys Variables class to define class-level attributes with type annotations and examples
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# API Connection Settings
|
|
14
|
+
qualysUserName: RsVariableType(str, "qualys_username") # type: ignore
|
|
15
|
+
qualysPassword: RsVariableType(str, "qualys_password", sensitive=True) # type: ignore
|
|
16
|
+
qualysUrl: RsVariableType(str, "https://qualysapi.qualys.com", default="https://qualysapi.qualys.com") # type: ignore
|
|
17
|
+
|
|
18
|
+
# Total Cloud Specific Settings
|
|
19
|
+
totalCloudTagFilter: RsVariableType(str, "tag_name", required=False) # type: ignore
|
|
20
|
+
totalCloudIncludeTags: RsVariableType(str, "tag1,tag2,tag3", required=False) # type: ignore
|
|
21
|
+
totalCloudExcludeTags: RsVariableType(str, "tag1,tag2,tag3", required=False) # type: ignore
|
|
@@ -7,6 +7,7 @@ RegScale STIG Integration
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from regscale.integrations.commercial.stigv2.stig_integration import StigIntegration
|
|
10
|
+
from regscale.models.app_models.click import NotRequiredIf
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@click.group(name="stigv2")
|
|
@@ -21,7 +22,17 @@ def stigv2():
|
|
|
21
22
|
type=click.INT,
|
|
22
23
|
help="The ID number from RegScale of the System Security Plan",
|
|
23
24
|
prompt="Enter RegScale System Security Plan ID",
|
|
24
|
-
|
|
25
|
+
cls=NotRequiredIf,
|
|
26
|
+
not_required_if=["component_id"],
|
|
27
|
+
)
|
|
28
|
+
@click.option(
|
|
29
|
+
"-c",
|
|
30
|
+
"--component_id",
|
|
31
|
+
type=click.INT,
|
|
32
|
+
help="The ID number from RegScale of the Component",
|
|
33
|
+
prompt="Enter RegScale Component ID",
|
|
34
|
+
cls=NotRequiredIf,
|
|
35
|
+
not_required_if=["regscale_ssp_id"],
|
|
25
36
|
)
|
|
26
37
|
@click.option(
|
|
27
38
|
"-d",
|
|
@@ -31,9 +42,12 @@ def stigv2():
|
|
|
31
42
|
prompt="Enter STIG directory",
|
|
32
43
|
required=True,
|
|
33
44
|
)
|
|
34
|
-
def sync_findings(regscale_ssp_id, stig_directory):
|
|
45
|
+
def sync_findings(regscale_ssp_id, component_id, stig_directory):
|
|
35
46
|
"""Sync GCP Findings to RegScale."""
|
|
36
|
-
|
|
47
|
+
if component_id:
|
|
48
|
+
StigIntegration.sync_findings(plan_id=component_id, path=stig_directory, is_component=True)
|
|
49
|
+
else:
|
|
50
|
+
StigIntegration.sync_findings(plan_id=regscale_ssp_id, path=stig_directory, is_component=False)
|
|
37
51
|
|
|
38
52
|
|
|
39
53
|
@stigv2.command(name="sync_assets")
|
|
@@ -41,9 +55,18 @@ def sync_findings(regscale_ssp_id, stig_directory):
|
|
|
41
55
|
"-p",
|
|
42
56
|
"--regscale_ssp_id",
|
|
43
57
|
type=click.INT,
|
|
44
|
-
help="The ID number from RegScale of the System Security Plan",
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
help="The ID number from RegScale of the System Security Plan to sync assets to.",
|
|
59
|
+
cls=NotRequiredIf,
|
|
60
|
+
not_required_if=["component_id"],
|
|
61
|
+
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"-c",
|
|
64
|
+
"--component_id",
|
|
65
|
+
type=click.INT,
|
|
66
|
+
help="The ID number from RegScale of the Component to sync assets to.",
|
|
67
|
+
cls=NotRequiredIf,
|
|
68
|
+
not_required_if=["regscale_ssp_id"],
|
|
69
|
+
default=None,
|
|
47
70
|
)
|
|
48
71
|
@click.option(
|
|
49
72
|
"-d",
|
|
@@ -53,9 +76,14 @@ def sync_findings(regscale_ssp_id, stig_directory):
|
|
|
53
76
|
prompt="Enter STIG directory",
|
|
54
77
|
required=True,
|
|
55
78
|
)
|
|
56
|
-
def sync_assets(regscale_ssp_id, stig_directory):
|
|
79
|
+
def sync_assets(regscale_ssp_id, component_id, stig_directory):
|
|
57
80
|
"""Sync GCP Assets to RegScale."""
|
|
58
|
-
|
|
81
|
+
if component_id:
|
|
82
|
+
StigIntegration.sync_assets(plan_id=component_id, path=stig_directory, is_component=True)
|
|
83
|
+
elif regscale_ssp_id:
|
|
84
|
+
StigIntegration.sync_assets(plan_id=regscale_ssp_id, path=stig_directory, is_component=False)
|
|
85
|
+
else:
|
|
86
|
+
raise click.UsageError("Either --regscale_ssp_id or --component_id must be provided.")
|
|
59
87
|
|
|
60
88
|
|
|
61
89
|
@stigv2.command(name="process_checklist")
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
RegScale STIG Integration
|
|
5
5
|
"""
|
|
6
6
|
import datetime
|
|
7
|
-
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Iterator, Optional, Generator, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from regscale.core.app.utils.app_utils import error_and_exit
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
8
14
|
|
|
9
15
|
from pathlib import Path
|
|
10
16
|
|
|
@@ -24,6 +30,9 @@ from regscale.integrations.scanner_integration import (
|
|
|
24
30
|
from regscale.models import regscale_models
|
|
25
31
|
|
|
26
32
|
|
|
33
|
+
logger = logging.getLogger("regscale")
|
|
34
|
+
|
|
35
|
+
|
|
27
36
|
class StigIntegration(ScannerIntegration):
|
|
28
37
|
options_map_assets_to_components = True
|
|
29
38
|
|
|
@@ -59,10 +68,10 @@ class StigIntegration(ScannerIntegration):
|
|
|
59
68
|
logger.info(f"Processing '{stig_file}'")
|
|
60
69
|
checklist = parse_checklist(stig_file)
|
|
61
70
|
logger.info(f"Found {len(checklist.stigs[0].vulns)} Vulnerabilities in '{stig_file}'")
|
|
71
|
+
self.num_findings_to_process += len(checklist.stigs[0].vulns)
|
|
62
72
|
for stig in checklist.stigs:
|
|
63
73
|
for vuln in stig.vulns:
|
|
64
74
|
for finding in self.process_vulnerabilities(checklist, vuln, stig):
|
|
65
|
-
self.num_findings_to_process += 1
|
|
66
75
|
yield finding
|
|
67
76
|
|
|
68
77
|
def process_vulnerabilities(
|
|
@@ -149,7 +158,44 @@ class StigIntegration(ScannerIntegration):
|
|
|
149
158
|
impact=vuln.potential_impact or "",
|
|
150
159
|
)
|
|
151
160
|
|
|
152
|
-
|
|
161
|
+
@staticmethod
|
|
162
|
+
def get_component_names(checklist: Checklist, component_title: Optional[str] = None) -> list[str]:
|
|
163
|
+
"""
|
|
164
|
+
Extracts component names from the checklist and STIG.
|
|
165
|
+
|
|
166
|
+
:param Checklist checklist: The checklist containing assets to process.
|
|
167
|
+
:param Optional[str] component_title: The title of the component to filter by, defaults to None
|
|
168
|
+
:return: A list of component names associated with the STIG.
|
|
169
|
+
:rtype: list[str]
|
|
170
|
+
"""
|
|
171
|
+
component_names = []
|
|
172
|
+
if component_title:
|
|
173
|
+
component_names.append(component_title)
|
|
174
|
+
else:
|
|
175
|
+
for stig in checklist.stigs:
|
|
176
|
+
component_names.append(stig.component_title)
|
|
177
|
+
return component_names
|
|
178
|
+
|
|
179
|
+
def should_process_asset(
|
|
180
|
+
self, stig_asset: regscale_models.Asset, is_component: bool, component_names: Optional[list[str]] = None
|
|
181
|
+
) -> bool:
|
|
182
|
+
"""
|
|
183
|
+
Determines if an asset should be processed based on the provided parameters.
|
|
184
|
+
|
|
185
|
+
:param Asset stig_asset: The asset to be processed.
|
|
186
|
+
:param bool is_component: Whether the asset is a component.
|
|
187
|
+
:param Optional[list[str]] component_names: The list of component names to filter by, defaults to None
|
|
188
|
+
:return: True if the asset should be processed, False otherwise.
|
|
189
|
+
:rtype: bool
|
|
190
|
+
"""
|
|
191
|
+
if not stig_asset.host_name and not stig_asset.host_fqdn:
|
|
192
|
+
self.log_error(f"Failed to extract asset from {stig_asset}")
|
|
193
|
+
return False
|
|
194
|
+
elif is_component and not component_names:
|
|
195
|
+
return False
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
def fetch_assets(self, path: Optional[Path] = None, **kwargs) -> Iterator["IntegrationAsset"]:
|
|
153
199
|
"""
|
|
154
200
|
Fetches GCP assets using the AssetServiceClient
|
|
155
201
|
|
|
@@ -166,7 +212,14 @@ class StigIntegration(ScannerIntegration):
|
|
|
166
212
|
raise ValueError("Path to STIG files is required.")
|
|
167
213
|
logger.info("Fetching assets...")
|
|
168
214
|
stig_files = find_stig_files(path)
|
|
215
|
+
component_title = ""
|
|
216
|
+
if is_component := kwargs.get("is_component", False):
|
|
217
|
+
from regscale.validation.record import validate_regscale_object
|
|
169
218
|
|
|
219
|
+
if not validate_regscale_object(parent_id=self.plan_id, parent_module="components"):
|
|
220
|
+
raise error_and_exit("The provided Component ID is not valid.")
|
|
221
|
+
component = regscale_models.Component.get_object(self.plan_id)
|
|
222
|
+
component_title = component.title
|
|
170
223
|
self.num_assets_to_process = len(stig_files)
|
|
171
224
|
|
|
172
225
|
loading_stig_files = self.asset_progress.add_task(
|
|
@@ -177,12 +230,9 @@ class StigIntegration(ScannerIntegration):
|
|
|
177
230
|
logger.info(f"Processing '{stig_file}'")
|
|
178
231
|
checklist = parse_checklist(stig_file)
|
|
179
232
|
for stig_asset in checklist.assets:
|
|
180
|
-
component_names =
|
|
181
|
-
for stig in checklist.stigs:
|
|
182
|
-
component_names.append(stig.component_title)
|
|
233
|
+
component_names = self.get_component_names(checklist, component_title)
|
|
183
234
|
|
|
184
|
-
if not stig_asset
|
|
185
|
-
self.log_error(f"Failed to extract asset from {stig_asset}")
|
|
235
|
+
if not self.should_process_asset(stig_asset, is_component, component_names):
|
|
186
236
|
continue
|
|
187
237
|
|
|
188
238
|
yield IntegrationAsset(
|
|
@@ -193,7 +243,11 @@ class StigIntegration(ScannerIntegration):
|
|
|
193
243
|
asset_type=stig_asset.asset_type,
|
|
194
244
|
asset_owner_id=self.assessor_id,
|
|
195
245
|
parent_id=self.plan_id,
|
|
196
|
-
parent_module=
|
|
246
|
+
parent_module=(
|
|
247
|
+
regscale_models.Component.get_module_slug()
|
|
248
|
+
if kwargs.get("is_component", False)
|
|
249
|
+
else regscale_models.SecurityPlan.get_module_slug()
|
|
250
|
+
),
|
|
197
251
|
asset_category=regscale_models.AssetCategory.Hardware,
|
|
198
252
|
component_names=component_names,
|
|
199
253
|
# TODO: Determine correct component type
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tenable integration for RegScale CLI.
|
|
3
|
+
|
|
4
|
+
This module provides functionality for scanning assets and findings from Tenable.io and Tenable SC.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from regscale.integrations.commercial.tenablev2.commands import tenable, sync_vulns, sync_jsonl
|
|
8
|
+
|
|
9
|
+
__all__ = ["tenable", "sync_vulns", "sync_jsonl"]
|
|
@@ -6,6 +6,7 @@ from regscale.integrations.commercial.tenablev2.variables import TenableVariable
|
|
|
6
6
|
# Delay import of Tenable libraries
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from tenable.io import TenableIO # type: ignore
|
|
9
|
+
from tenable.sc import TenableSC # type: ignore
|
|
9
10
|
|
|
10
11
|
REGSCALE_INC = "RegScale, Inc."
|
|
11
12
|
REGSCALE_CLI = "RegScale CLI"
|
|
@@ -13,9 +14,9 @@ REGSCALE_CLI = "RegScale CLI"
|
|
|
13
14
|
|
|
14
15
|
def gen_tio() -> "TenableIO":
|
|
15
16
|
"""
|
|
16
|
-
Generate Tenable Object
|
|
17
|
+
Generate Tenable IO Object
|
|
17
18
|
|
|
18
|
-
:return: Tenable client
|
|
19
|
+
:return: Tenable IO client
|
|
19
20
|
:rtype: "TenableIO"
|
|
20
21
|
"""
|
|
21
22
|
|
|
@@ -29,3 +30,23 @@ def gen_tio() -> "TenableIO":
|
|
|
29
30
|
product=REGSCALE_CLI,
|
|
30
31
|
build=__version__,
|
|
31
32
|
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def gen_tsc() -> "TenableSC":
|
|
36
|
+
"""
|
|
37
|
+
Generate Tenable SC Object
|
|
38
|
+
|
|
39
|
+
:return: Tenable SC client
|
|
40
|
+
:rtype: "TenableSC"
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from tenable.sc import TenableSC
|
|
44
|
+
|
|
45
|
+
return TenableSC(
|
|
46
|
+
url=TenableVariables.tenableUrl,
|
|
47
|
+
access_key=TenableVariables.tenableAccessKey,
|
|
48
|
+
secret_key=TenableVariables.tenableSecretKey,
|
|
49
|
+
vendor=REGSCALE_INC,
|
|
50
|
+
product=REGSCALE_CLI,
|
|
51
|
+
build=__version__,
|
|
52
|
+
)
|