regscale-cli 6.16.3.0__py3-none-any.whl → 6.16.4.1__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/control_editor.py +26 -2
- regscale/core/app/internal/model_editor.py +39 -26
- regscale/integrations/commercial/grype/scanner.py +37 -29
- regscale/integrations/commercial/opentext/commands.py +2 -0
- regscale/integrations/commercial/opentext/scanner.py +45 -31
- regscale/integrations/commercial/qualys.py +3 -1
- regscale/integrations/commercial/sicura/commands.py +9 -14
- regscale/integrations/commercial/tenablev2/click.py +25 -13
- regscale/integrations/commercial/tenablev2/scanner.py +12 -3
- regscale/integrations/commercial/trivy/scanner.py +14 -6
- regscale/integrations/commercial/wizv2/click.py +15 -37
- regscale/integrations/jsonl_scanner_integration.py +120 -16
- regscale/integrations/public/fedramp/click.py +8 -8
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +499 -106
- regscale/integrations/public/fedramp/ssp_logger.py +2 -9
- regscale/integrations/scanner_integration.py +17 -11
- regscale/models/integration_models/cisa_kev_data.json +39 -8
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/tenable_models/integration.py +23 -3
- regscale/models/regscale_models/control_implementation.py +18 -0
- regscale/models/regscale_models/control_objective.py +2 -1
- regscale/models/regscale_models/facility.py +10 -26
- regscale/models/regscale_models/functional_roles.py +38 -0
- regscale/models/regscale_models/issue.py +3 -1
- regscale/models/regscale_models/parameter.py +21 -3
- regscale/models/regscale_models/profile.py +22 -0
- regscale/models/regscale_models/profile_mapping.py +48 -3
- regscale/models/regscale_models/regscale_model.py +2 -0
- regscale/models/regscale_models/risk.py +38 -30
- regscale/models/regscale_models/security_plan.py +1 -0
- regscale/models/regscale_models/supply_chain.py +1 -1
- regscale/models/regscale_models/user.py +16 -2
- regscale/utils/threading/__init__.py +1 -0
- regscale/utils/threading/threadsafe_list.py +10 -0
- regscale/utils/threading/threadsafe_set.py +116 -0
- {regscale_cli-6.16.3.0.dist-info → regscale_cli-6.16.4.1.dist-info}/METADATA +1 -1
- {regscale_cli-6.16.3.0.dist-info → regscale_cli-6.16.4.1.dist-info}/RECORD +42 -40
- {regscale_cli-6.16.3.0.dist-info → regscale_cli-6.16.4.1.dist-info}/LICENSE +0 -0
- {regscale_cli-6.16.3.0.dist-info → regscale_cli-6.16.4.1.dist-info}/WHEEL +0 -0
- {regscale_cli-6.16.3.0.dist-info → regscale_cli-6.16.4.1.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.16.3.0.dist-info → regscale_cli-6.16.4.1.dist-info}/top_level.txt +0 -0
|
@@ -13,7 +13,7 @@ from pathlib import Path
|
|
|
13
13
|
|
|
14
14
|
from regscale.core.app.utils.parser_utils import safe_datetime_str
|
|
15
15
|
from regscale.integrations.jsonl_scanner_integration import JSONLScannerIntegration
|
|
16
|
-
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
16
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding, issue_due_date
|
|
17
17
|
from regscale.models import IssueSeverity, AssetStatus, IssueStatus
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger("regscale")
|
|
@@ -50,6 +50,9 @@ class TrivyIntegration(JSONLScannerIntegration):
|
|
|
50
50
|
kwargs["read_files_only"] = True
|
|
51
51
|
kwargs["file_pattern"] = "*.json"
|
|
52
52
|
self.disable_mapping = kwargs["disable_mapping"] = True
|
|
53
|
+
self.scan_date = kwargs.get("scan_date") if "scan_date" in kwargs else None
|
|
54
|
+
if self.scan_date:
|
|
55
|
+
self.scan_date = self.clean_scan_date(self.scan_date)
|
|
53
56
|
super().__init__(*args, **kwargs)
|
|
54
57
|
|
|
55
58
|
def is_valid_file(self, data: Any, file_path: Union[Path, str]) -> Tuple[bool, Optional[Dict[str, Any]]]:
|
|
@@ -167,8 +170,10 @@ class TrivyIntegration(JSONLScannerIntegration):
|
|
|
167
170
|
:return: IntegrationFinding object
|
|
168
171
|
:rtype: IntegrationFinding
|
|
169
172
|
"""
|
|
173
|
+
created_date = safe_datetime_str(data.get("CreatedAt"))
|
|
170
174
|
# Get scan date from the finding or use current time
|
|
171
|
-
scan_date
|
|
175
|
+
if self.scan_date is None:
|
|
176
|
+
self.scan_date = created_date
|
|
172
177
|
|
|
173
178
|
# Process severity
|
|
174
179
|
severity_str = item.get("Severity", "UNKNOWN")
|
|
@@ -220,10 +225,10 @@ class TrivyIntegration(JSONLScannerIntegration):
|
|
|
220
225
|
plugin_id=plugin_id,
|
|
221
226
|
asset_identifier=asset_identifier,
|
|
222
227
|
cve=cve,
|
|
223
|
-
first_seen=
|
|
224
|
-
last_seen=scan_date,
|
|
225
|
-
scan_date=scan_date,
|
|
226
|
-
date_created=
|
|
228
|
+
first_seen=safe_datetime_str(data.get("CreatedAt")),
|
|
229
|
+
last_seen=self.scan_date,
|
|
230
|
+
scan_date=self.scan_date,
|
|
231
|
+
date_created=item.get("CreatedAt"),
|
|
227
232
|
category="Software",
|
|
228
233
|
control_labels=[],
|
|
229
234
|
installed_versions=item.get("InstalledVersion", ""),
|
|
@@ -234,6 +239,9 @@ class TrivyIntegration(JSONLScannerIntegration):
|
|
|
234
239
|
build_version=build_version,
|
|
235
240
|
fixed_versions=item.get("FixedVersion", ""),
|
|
236
241
|
fix_status=item.get("Status", ""),
|
|
242
|
+
due_date=issue_due_date(
|
|
243
|
+
severity=severity, created_date=created_date, title="trivy", config=self.app.config
|
|
244
|
+
),
|
|
237
245
|
)
|
|
238
246
|
|
|
239
247
|
@staticmethod
|
|
@@ -32,20 +32,17 @@ def authenticate(client_id, client_secret):
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
@wiz.command()
|
|
35
|
-
@click.option(
|
|
35
|
+
@click.option(
|
|
36
36
|
"--wiz_project_id",
|
|
37
37
|
"-p",
|
|
38
38
|
required=False,
|
|
39
39
|
type=str,
|
|
40
40
|
help="Comma Seperated list of one or more Wiz project ids to pull inventory for.",
|
|
41
41
|
)
|
|
42
|
-
@
|
|
43
|
-
|
|
44
|
-
"--regscale_module",
|
|
45
|
-
"-m",
|
|
46
|
-
help="Regscale module to push inventory to in RegScale.",
|
|
42
|
+
@regscale_ssp_id(
|
|
43
|
+
help="RegScale SSP ID to push inventory to in RegScale.",
|
|
47
44
|
)
|
|
48
|
-
@click.option(
|
|
45
|
+
@click.option(
|
|
49
46
|
"--client_id",
|
|
50
47
|
"-ci",
|
|
51
48
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
@@ -53,7 +50,7 @@ def authenticate(client_id, client_secret):
|
|
|
53
50
|
hide_input=False,
|
|
54
51
|
required=False,
|
|
55
52
|
)
|
|
56
|
-
@click.option(
|
|
53
|
+
@click.option(
|
|
57
54
|
"--client_secret",
|
|
58
55
|
"-cs",
|
|
59
56
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
@@ -61,7 +58,7 @@ def authenticate(client_id, client_secret):
|
|
|
61
58
|
hide_input=False,
|
|
62
59
|
required=False,
|
|
63
60
|
)
|
|
64
|
-
@click.option(
|
|
61
|
+
@click.option(
|
|
65
62
|
"--filter_by_override",
|
|
66
63
|
"-f",
|
|
67
64
|
default=None,
|
|
@@ -71,22 +68,12 @@ def authenticate(client_id, client_secret):
|
|
|
71
68
|
IE: --filter_by='{projectId: ["1234"], type: ["VIRTUAL_MACHINE"], subscriptionExternalId: ["1234"],
|
|
72
69
|
providerUniqueId: ["1234"], updatedAt: {after: "2023-06-14T14:07:06Z"}, search: "test-7"}' """,
|
|
73
70
|
)
|
|
74
|
-
@click.option( # type: ignore
|
|
75
|
-
"--full_inventory",
|
|
76
|
-
"-fi",
|
|
77
|
-
is_flag=True,
|
|
78
|
-
help="Pull full inventory list. this disregards the last pull date.",
|
|
79
|
-
required=False,
|
|
80
|
-
default=False,
|
|
81
|
-
)
|
|
82
71
|
def inventory(
|
|
83
72
|
wiz_project_id: str,
|
|
84
|
-
|
|
85
|
-
regscale_module: str,
|
|
73
|
+
regscale_ssp_id: int,
|
|
86
74
|
client_id: str,
|
|
87
75
|
client_secret: str,
|
|
88
76
|
filter_by_override: Optional[str] = None,
|
|
89
|
-
full_inventory: bool = False,
|
|
90
77
|
) -> None:
|
|
91
78
|
"""Process inventory from Wiz and create assets in RegScale."""
|
|
92
79
|
from regscale.integrations.commercial.wizv2.scanner import WizVulnerabilityIntegration
|
|
@@ -96,9 +83,9 @@ def inventory(
|
|
|
96
83
|
if not client_id:
|
|
97
84
|
client_id = WizVariables.wizClientId
|
|
98
85
|
|
|
99
|
-
scanner = WizVulnerabilityIntegration(plan_id=
|
|
86
|
+
scanner = WizVulnerabilityIntegration(plan_id=regscale_ssp_id)
|
|
100
87
|
scanner.sync_assets(
|
|
101
|
-
plan_id=
|
|
88
|
+
plan_id=regscale_ssp_id,
|
|
102
89
|
filter_by_override=filter_by_override or WizVariables.wizInventoryFilterBy, # type: ignore
|
|
103
90
|
client_id=client_id, # type: ignore
|
|
104
91
|
client_secret=client_secret, # type: ignore
|
|
@@ -106,38 +93,30 @@ def inventory(
|
|
|
106
93
|
)
|
|
107
94
|
|
|
108
95
|
|
|
109
|
-
@wiz.command()
|
|
110
|
-
@click.option(
|
|
96
|
+
@wiz.command()
|
|
97
|
+
@click.option(
|
|
111
98
|
"--wiz_project_id",
|
|
112
99
|
"-p",
|
|
113
100
|
prompt="Enter the project ID for Wiz",
|
|
114
101
|
default=None,
|
|
115
102
|
required=False,
|
|
116
103
|
)
|
|
117
|
-
@
|
|
118
|
-
@click.option(
|
|
119
|
-
"--regscale_module",
|
|
120
|
-
"-m",
|
|
121
|
-
type=click.STRING, # type: ignore
|
|
122
|
-
help="Enter the RegScale module name. Default is 'securityplans'",
|
|
123
|
-
default="securityplans",
|
|
124
|
-
required=False,
|
|
125
|
-
)
|
|
126
|
-
@click.option( # type: ignore
|
|
104
|
+
@regscale_ssp_id(help="RegScale will create and update issues as children of this record.")
|
|
105
|
+
@click.option(
|
|
127
106
|
"--client_id",
|
|
128
107
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
129
108
|
default="",
|
|
130
109
|
hide_input=False,
|
|
131
110
|
required=False,
|
|
132
111
|
)
|
|
133
|
-
@click.option(
|
|
112
|
+
@click.option(
|
|
134
113
|
"--client_secret",
|
|
135
114
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
136
115
|
default="",
|
|
137
116
|
hide_input=True,
|
|
138
117
|
required=False,
|
|
139
118
|
)
|
|
140
|
-
@click.option(
|
|
119
|
+
@click.option(
|
|
141
120
|
"--filter_by_override",
|
|
142
121
|
"-f",
|
|
143
122
|
default=None,
|
|
@@ -152,7 +131,6 @@ def issues(
|
|
|
152
131
|
regscale_id: int,
|
|
153
132
|
client_id: str,
|
|
154
133
|
client_secret: str,
|
|
155
|
-
regscale_module: str = "securityplans",
|
|
156
134
|
filter_by_override: Optional[str] = None,
|
|
157
135
|
) -> None:
|
|
158
136
|
"""
|
|
@@ -8,14 +8,18 @@ import logging
|
|
|
8
8
|
import os
|
|
9
9
|
import shutil
|
|
10
10
|
import tempfile
|
|
11
|
+
import traceback
|
|
12
|
+
from datetime import datetime, time
|
|
11
13
|
from typing import Any, Dict, Iterator, Optional, Union, Tuple, TypeVar, Type, List
|
|
12
14
|
|
|
13
15
|
import boto3
|
|
14
16
|
from pathlib import Path
|
|
15
17
|
|
|
18
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
16
19
|
from regscale.core.app.utils.file_utils import is_s3_path, read_file, find_files, download_from_s3
|
|
17
20
|
from regscale.exceptions import ValidationException
|
|
18
21
|
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding, ScannerIntegration
|
|
22
|
+
from regscale.models import regscale_models
|
|
19
23
|
from regscale.models.app_models.mapping import Mapping
|
|
20
24
|
|
|
21
25
|
logger = logging.getLogger("regscale")
|
|
@@ -43,33 +47,36 @@ class JSONLScannerIntegration(ScannerIntegration):
|
|
|
43
47
|
# Constants for file paths - subclasses should override these
|
|
44
48
|
ASSETS_FILE = "./artifacts/assets.jsonl"
|
|
45
49
|
FINDINGS_FILE = "./artifacts/findings.jsonl"
|
|
50
|
+
DT_FORMAT = "%Y-%m-%d"
|
|
46
51
|
|
|
47
52
|
def __init__(self, *args, **kwargs):
|
|
48
53
|
"""
|
|
49
54
|
Initialize the JSONLScannerIntegration.
|
|
50
55
|
"""
|
|
56
|
+
logger.info("Initializing JSONLScannerIntegration")
|
|
57
|
+
self.plan_id = kwargs.get("plan_id", None)
|
|
58
|
+
# plan_id is required for all integrations
|
|
59
|
+
super().__init__(**kwargs)
|
|
51
60
|
# Extract S3-related kwargs
|
|
52
|
-
self.s3_bucket = kwargs.
|
|
53
|
-
self.s3_prefix = kwargs.
|
|
54
|
-
self.aws_profile = kwargs.
|
|
61
|
+
self.s3_bucket = kwargs.get("s3_bucket", None)
|
|
62
|
+
self.s3_prefix = kwargs.get("s3_prefix", "")
|
|
63
|
+
self.aws_profile = kwargs.get("aws_profile", "default")
|
|
55
64
|
|
|
56
|
-
self.
|
|
57
|
-
self.file_path = kwargs.pop("file_path", None)
|
|
65
|
+
self.file_path = kwargs.get("file_path", None)
|
|
58
66
|
self.empty_files: bool = True
|
|
59
|
-
self.
|
|
60
|
-
self.
|
|
61
|
-
self.
|
|
62
|
-
self.read_files_only = kwargs.pop("read_files_only", False)
|
|
67
|
+
self.download_destination = kwargs.get("destination", None)
|
|
68
|
+
self.file_pattern = kwargs.get("file_pattern", "*.json")
|
|
69
|
+
self.read_files_only = kwargs.get("read_files_only", False)
|
|
63
70
|
|
|
64
71
|
# Extract mapping-related kwargs
|
|
65
|
-
self.disable_mapping = kwargs.
|
|
66
|
-
self.mapping_path = kwargs.
|
|
67
|
-
self.required_asset_fields = kwargs.
|
|
68
|
-
self.required_finding_fields = kwargs.
|
|
72
|
+
self.disable_mapping = kwargs.get("disable_mapping", False)
|
|
73
|
+
self.mapping_path = kwargs.get("mapping_path", f"./mappings/{self.__class__.__name__.lower()}/mapping.json")
|
|
74
|
+
self.required_asset_fields = kwargs.get("required_asset_fields", ["identifier", "name"])
|
|
75
|
+
self.required_finding_fields = kwargs.get("required_finding_fields", ["asset_identifier", "title", "severity"])
|
|
69
76
|
self.mapping = self._load_mapping() if not self.disable_mapping else None
|
|
70
77
|
|
|
78
|
+
self.set_scan_date(kwargs.get("scan_date", get_current_datetime()))
|
|
71
79
|
# Initialize parent class
|
|
72
|
-
super().__init__(plan_id=self.plan_id, **kwargs)
|
|
73
80
|
|
|
74
81
|
self.s3_client = None
|
|
75
82
|
if self.s3_bucket and not self.read_files_only:
|
|
@@ -80,6 +87,100 @@ class JSONLScannerIntegration(ScannerIntegration):
|
|
|
80
87
|
logger.error(f"Failed to initialize S3 client with profile {self.aws_profile}: {str(e)}")
|
|
81
88
|
raise ValidationException(f"S3 client initialization failed: {str(e)}")
|
|
82
89
|
|
|
90
|
+
def set_scan_date(self, scan_date_input: str):
|
|
91
|
+
"""
|
|
92
|
+
Set the scan date input.
|
|
93
|
+
|
|
94
|
+
:param str scan_date_input: The scan date input (string or datetime)
|
|
95
|
+
:return: The cleaned scan date in 'YYYY-MM-DD' format
|
|
96
|
+
:rtype: str
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
self.scan_date: str = self.clean_scan_date(scan_date_input)
|
|
100
|
+
logger.info(f"Setting scan date input to {self.scan_date}")
|
|
101
|
+
|
|
102
|
+
def get_scan_date(self) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Get the scan date in 'YYYY-MM-DD' format.
|
|
105
|
+
|
|
106
|
+
:return: The scan date as a string
|
|
107
|
+
:rtype: str
|
|
108
|
+
"""
|
|
109
|
+
if self.scan_date:
|
|
110
|
+
return self.clean_scan_date(self.scan_date)
|
|
111
|
+
return get_current_datetime()
|
|
112
|
+
|
|
113
|
+
def create_scan_history(self) -> "regscale_models.ScanHistory":
|
|
114
|
+
"""
|
|
115
|
+
Creates a new ScanHistory object for the current scan, using self.scan_date if available.
|
|
116
|
+
|
|
117
|
+
:param str scan_date: The date of the scan in 'YYYY-MM-DD' format
|
|
118
|
+
:return: A newly created ScanHistory object
|
|
119
|
+
:rtype: regscale_models.ScanHistory
|
|
120
|
+
"""
|
|
121
|
+
scan_date = self.get_scan_date()
|
|
122
|
+
logger.info(f"Creating ScanHistory with scan_date: {scan_date}")
|
|
123
|
+
scan_history = regscale_models.ScanHistory(
|
|
124
|
+
parentId=self.plan_id,
|
|
125
|
+
parentModule=regscale_models.SecurityPlan.get_module_string(),
|
|
126
|
+
scanningTool=self.title,
|
|
127
|
+
scanDate=scan_date,
|
|
128
|
+
createdById=self.assessor_id,
|
|
129
|
+
tenantsId=self.tenant_id,
|
|
130
|
+
vLow=0,
|
|
131
|
+
vMedium=0,
|
|
132
|
+
vHigh=0,
|
|
133
|
+
vCritical=0,
|
|
134
|
+
).create()
|
|
135
|
+
|
|
136
|
+
count = 0
|
|
137
|
+
regscale_models.ScanHistory.delete_object_cache(scan_history)
|
|
138
|
+
while not regscale_models.ScanHistory.get_object(object_id=scan_history.id) and count < 10:
|
|
139
|
+
logger.info("Waiting for ScanHistory to be created...")
|
|
140
|
+
time.sleep(1)
|
|
141
|
+
count += 1
|
|
142
|
+
regscale_models.ScanHistory.delete_object_cache(scan_history)
|
|
143
|
+
return scan_history
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def clean_scan_date(date_input: Optional[Union[str, datetime]]) -> Optional[str]:
|
|
147
|
+
"""
|
|
148
|
+
Convert a date (string or datetime object) to a JSON-serializable string.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
date_input: A date as a string (e.g., '2025-02-01') or datetime object, or None.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
A string in 'YYYY-MM-DD' format if date_input is valid, otherwise None.
|
|
155
|
+
|
|
156
|
+
Examples:
|
|
157
|
+
>>> to_json_date('2025-02-01')
|
|
158
|
+
'2025-02-01'
|
|
159
|
+
>>> to_json_date(datetime(2025, 2, 1))
|
|
160
|
+
'2025-02-01'
|
|
161
|
+
>>> to_json_date(None)
|
|
162
|
+
None
|
|
163
|
+
"""
|
|
164
|
+
if date_input is None:
|
|
165
|
+
return None
|
|
166
|
+
if isinstance(date_input, datetime):
|
|
167
|
+
return date_input.strftime("%Y-%m-%d")
|
|
168
|
+
if isinstance(date_input, str):
|
|
169
|
+
try:
|
|
170
|
+
datetime.strptime(date_input, "%Y-%m-%d")
|
|
171
|
+
return date_input
|
|
172
|
+
except ValueError:
|
|
173
|
+
# Try parsing other common formats if needed
|
|
174
|
+
try:
|
|
175
|
+
try:
|
|
176
|
+
dt = datetime.strptime(date_input, "%Y-%m-%dT%H:%M:%S") # e.g., '2025-01-29T00:43:04'
|
|
177
|
+
except ValueError:
|
|
178
|
+
dt = datetime.strptime(date_input, "%Y-%m-%dT%H:%M:%S%z") # e.g., '2025-01-29T00:43:51+0000'
|
|
179
|
+
return dt.strftime("%Y-%m-%d")
|
|
180
|
+
except ValueError:
|
|
181
|
+
return None
|
|
182
|
+
return None
|
|
183
|
+
|
|
83
184
|
def _load_mapping(self) -> Optional[Mapping]:
|
|
84
185
|
"""Load the mapping configuration from a JSON file."""
|
|
85
186
|
try:
|
|
@@ -435,8 +536,9 @@ class JSONLScannerIntegration(ScannerIntegration):
|
|
|
435
536
|
logger.info(f"Processing file: {file}")
|
|
436
537
|
self._process_asset(file, data, assets_file, asset_tracker)
|
|
437
538
|
self._process_findings(file, data, findings_file, asset_tracker.existing, finding_tracker)
|
|
438
|
-
except Exception
|
|
439
|
-
|
|
539
|
+
except Exception:
|
|
540
|
+
error_message = traceback.format_exc()
|
|
541
|
+
logger.error(f"Error processing file {file}: {str(error_message)}")
|
|
440
542
|
|
|
441
543
|
def _process_asset(
|
|
442
544
|
self,
|
|
@@ -723,6 +825,7 @@ class JSONLScannerIntegration(ScannerIntegration):
|
|
|
723
825
|
file_path=file_path,
|
|
724
826
|
use_jsonl_file=True,
|
|
725
827
|
asset_count=total_assets,
|
|
828
|
+
scan_date=self.scan_date,
|
|
726
829
|
)
|
|
727
830
|
|
|
728
831
|
logger.info("Syncing %d findings to RegScale", total_findings)
|
|
@@ -731,6 +834,7 @@ class JSONLScannerIntegration(ScannerIntegration):
|
|
|
731
834
|
file_path=file_path,
|
|
732
835
|
use_jsonl_file=True,
|
|
733
836
|
finding_count=total_findings,
|
|
837
|
+
scan_date=self.scan_date,
|
|
734
838
|
)
|
|
735
839
|
|
|
736
840
|
logger.info("Assets and findings sync complete")
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""standard python imports"""
|
|
4
4
|
import glob
|
|
5
5
|
import logging
|
|
6
|
-
from datetime import
|
|
6
|
+
from datetime import date, datetime
|
|
7
7
|
from typing import Literal, Optional
|
|
8
8
|
|
|
9
9
|
import click
|
|
@@ -432,11 +432,11 @@ def import_drf(file_path: click.Path, regscale_id: int, regscale_module: str) ->
|
|
|
432
432
|
required=True,
|
|
433
433
|
)
|
|
434
434
|
@click.option(
|
|
435
|
-
"--
|
|
436
|
-
"-
|
|
435
|
+
"--profile_id",
|
|
436
|
+
"-p",
|
|
437
437
|
type=click.INT,
|
|
438
|
-
help="The ID number from RegScale of the
|
|
439
|
-
prompt="Enter RegScale
|
|
438
|
+
help="The ID number from RegScale of the Profile. (This will generate the control implementations for a new Security Plan)",
|
|
439
|
+
prompt="Enter RegScale Profile ID",
|
|
440
440
|
required=True,
|
|
441
441
|
)
|
|
442
442
|
@click.option(
|
|
@@ -459,11 +459,11 @@ def import_ciscrm(
|
|
|
459
459
|
version: str,
|
|
460
460
|
cis_sheet_name: str,
|
|
461
461
|
crm_sheet_name: Optional[click.STRING],
|
|
462
|
-
|
|
462
|
+
profile_id: int,
|
|
463
463
|
leveraged_auth_id: int = 0,
|
|
464
464
|
):
|
|
465
465
|
"""
|
|
466
|
-
[BETA] Import FedRAMP Rev5 CIS/CRM Workbook into a RegScale System Security Plan.
|
|
466
|
+
[BETA] Import FedRAMP Rev5 CIS/CRM Workbook into a new RegScale System Security Plan.
|
|
467
467
|
"""
|
|
468
468
|
|
|
469
469
|
from regscale.integrations.public.fedramp.fedramp_cis_crm import parse_and_import_ciscrm
|
|
@@ -474,6 +474,6 @@ def import_ciscrm(
|
|
|
474
474
|
version=version_literal, # type: ignore
|
|
475
475
|
cis_sheet_name=cis_sheet_name,
|
|
476
476
|
crm_sheet_name=crm_sheet_name,
|
|
477
|
-
|
|
477
|
+
profile_id=profile_id,
|
|
478
478
|
leveraged_auth_id=leveraged_auth_id,
|
|
479
479
|
)
|