regscale-cli 6.22.0.1__py3-none-any.whl → 6.23.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/api.py +4 -1
- regscale/core/app/utils/app_utils.py +3 -3
- regscale/dev/code_gen.py +1 -1
- regscale/integrations/commercial/__init__.py +12 -0
- regscale/integrations/commercial/sarif/__init__.py +0 -0
- regscale/integrations/commercial/sarif/sairf_importer.py +432 -0
- regscale/integrations/commercial/sarif/sarif_converter.py +67 -0
- regscale/models/integration_models/cisa_kev_data.json +33 -3
- regscale/models/integration_models/flat_file_importer/__init__.py +1 -2
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +1 -1
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +2 -2
- regscale/models/regscale_models/issue.py +4 -1
- regscale/models/regscale_models/vulnerability.py +3 -3
- regscale/regscale.py +5 -3
- {regscale_cli-6.22.0.1.dist-info → regscale_cli-6.23.0.0.dist-info}/METADATA +9 -9
- {regscale_cli-6.22.0.1.dist-info → regscale_cli-6.23.0.0.dist-info}/RECORD +21 -18
- {regscale_cli-6.22.0.1.dist-info → regscale_cli-6.23.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.22.0.1.dist-info → regscale_cli-6.23.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.22.0.1.dist-info → regscale_cli-6.23.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.22.0.1.dist-info → regscale_cli-6.23.0.0.dist-info}/top_level.txt +0 -0
regscale/_version.py
CHANGED
regscale/core/app/api.py
CHANGED
|
@@ -44,7 +44,10 @@ class Api:
|
|
|
44
44
|
from regscale.integrations.variables import ScannerVariables
|
|
45
45
|
|
|
46
46
|
if isinstance(timeout, str):
|
|
47
|
-
|
|
47
|
+
try:
|
|
48
|
+
timeout = int(timeout)
|
|
49
|
+
except ValueError:
|
|
50
|
+
timeout = ScannerVariables.timeout
|
|
48
51
|
|
|
49
52
|
self.verify = True
|
|
50
53
|
self.timeout = timeout
|
|
@@ -602,7 +602,7 @@ def save_to_csv(file: Path, data: Any, output_log: bool, transpose: bool = True)
|
|
|
602
602
|
data = pd.DataFrame(data)
|
|
603
603
|
data.to_csv(file)
|
|
604
604
|
if output_log:
|
|
605
|
-
logger.info("Data successfully saved to: %s", file.
|
|
605
|
+
logger.info("Data successfully saved to: %s", file.absolute())
|
|
606
606
|
|
|
607
607
|
|
|
608
608
|
def save_to_excel(file: Path, data: Any, output_log: bool, transpose: bool = True) -> None:
|
|
@@ -623,7 +623,7 @@ def save_to_excel(file: Path, data: Any, output_log: bool, transpose: bool = Tru
|
|
|
623
623
|
|
|
624
624
|
d_frame.to_excel(file)
|
|
625
625
|
if output_log:
|
|
626
|
-
logger.info("Data successfully saved to: %s", file.
|
|
626
|
+
logger.info("Data successfully saved to: %s", file.absolute())
|
|
627
627
|
|
|
628
628
|
|
|
629
629
|
def save_to_json(file: Path, data: Any, output_log: bool) -> None:
|
|
@@ -642,7 +642,7 @@ def save_to_json(file: Path, data: Any, output_log: bool) -> None:
|
|
|
642
642
|
with open(file, "w", encoding="utf-8") as outfile:
|
|
643
643
|
outfile.write(str(data))
|
|
644
644
|
if output_log:
|
|
645
|
-
logger.info("Data successfully saved to %s", file.
|
|
645
|
+
logger.info("Data successfully saved to %s", file.absolute())
|
|
646
646
|
|
|
647
647
|
|
|
648
648
|
def save_data_to(file: Path, data: Any, output_log: bool = True, transpose_data: bool = True) -> None:
|
regscale/dev/code_gen.py
CHANGED
|
@@ -319,6 +319,18 @@ def qualys():
|
|
|
319
319
|
show_mapping(group=qualys, import_name="qualys", file_type="csv")
|
|
320
320
|
|
|
321
321
|
|
|
322
|
+
@click.group(
|
|
323
|
+
cls=LazyGroup,
|
|
324
|
+
lazy_subcommands={
|
|
325
|
+
"import": "regscale.integrations.commercial.sarif.sarif_converter.import_sarif",
|
|
326
|
+
},
|
|
327
|
+
name="sarif",
|
|
328
|
+
)
|
|
329
|
+
def sarif():
|
|
330
|
+
"""Convert SARIF files to OCSF format via API."""
|
|
331
|
+
pass
|
|
332
|
+
|
|
333
|
+
|
|
322
334
|
@click.group(
|
|
323
335
|
cls=LazyGroup,
|
|
324
336
|
lazy_subcommands={
|
|
File without changes
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module to import and convert SARIF files to OCSF format using an API converter, and creating Vulnerability,
|
|
3
|
+
VulnerabilityMapping, and ScanHistory objects in RegScale.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import datetime
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
from logging import getLogger
|
|
10
|
+
from typing import Any, Dict, Optional, Union
|
|
11
|
+
|
|
12
|
+
import requests
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from requests.exceptions import RequestException
|
|
15
|
+
from rich.progress import Progress
|
|
16
|
+
from synqly.engine.resources.ocsf.resources.v_1_3_0.resources.vulnerabilityfinding import Vulnerability as OcsfVuln
|
|
17
|
+
from synqly.engine.resources.ocsf.resources.v_1_5_0.resources.applicationsecurityposturefinding import (
|
|
18
|
+
ApplicationSecurityPostureFinding,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from regscale.core.app.application import Application
|
|
22
|
+
from regscale.core.app.utils.app_utils import (
|
|
23
|
+
create_progress_object,
|
|
24
|
+
check_file_path,
|
|
25
|
+
check_license,
|
|
26
|
+
error_and_exit,
|
|
27
|
+
save_data_to,
|
|
28
|
+
get_current_datetime,
|
|
29
|
+
)
|
|
30
|
+
from regscale.models import Asset, IssueStatus, Issue, ScanHistory, SecurityPlan, Vulnerability, VulnerabilityMapping
|
|
31
|
+
from regscale.validation.record import validate_regscale_object
|
|
32
|
+
|
|
33
|
+
logger = getLogger("regscale")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SarifImporter:
|
|
37
|
+
"""
|
|
38
|
+
Class to handle importing and converting SARIF files to OCSF format using an API converter. It then creates
|
|
39
|
+
Vulnerability, VulnerabilityMapping, ScanHistory objects in RegScale.
|
|
40
|
+
|
|
41
|
+
:param Path file_path: Path to the SARIF file or directory of files
|
|
42
|
+
:param int asset_id: The RegScale Asset ID to import the findings to
|
|
43
|
+
:param Union[datetime.datetime, str, None] scan_date: The scan date of the file (defaults to current date if None)
|
|
44
|
+
:rtype: None
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, file_path: Path, asset_id: int, scan_date: Union[datetime.datetime, str, None] = None) -> None:
|
|
48
|
+
self.file_path: Path = file_path
|
|
49
|
+
self.app: Application = check_license()
|
|
50
|
+
if not scan_date:
|
|
51
|
+
scan_date = get_current_datetime()
|
|
52
|
+
if isinstance(scan_date, datetime.datetime):
|
|
53
|
+
scan_date = scan_date.strftime("%Y-%m-%d")
|
|
54
|
+
self.scan_date: str = scan_date
|
|
55
|
+
self.token: Optional[str] = os.getenv("synqlyAccessToken") or self.app.config.get("synqlyAccessToken")
|
|
56
|
+
if not self.token:
|
|
57
|
+
error_and_exit("synqlyAccessToken environment variable or init.yaml value is required")
|
|
58
|
+
if not validate_regscale_object(asset_id, Asset.get_module_string()):
|
|
59
|
+
error_and_exit(f"Asset ID {asset_id} does not exist in RegScale.")
|
|
60
|
+
self.asset: Asset = Asset.get_object(asset_id)
|
|
61
|
+
self.parent_id = asset_id
|
|
62
|
+
self.parent_module = Asset.get_module_slug()
|
|
63
|
+
self.scan_history: Optional[ScanHistory] = None
|
|
64
|
+
self.progress: Progress = create_progress_object()
|
|
65
|
+
self.process_sarif_files()
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def load_sarif_file(file_path: Path) -> Dict[str, Any]:
|
|
69
|
+
"""
|
|
70
|
+
Load and parse a SARIF file from disk
|
|
71
|
+
|
|
72
|
+
:param Path file_path: Path to the SARIF file
|
|
73
|
+
:return: Parsed SARIF data as dictionary
|
|
74
|
+
:rtype: Dict[str, Any]
|
|
75
|
+
:raises: SystemExit if file cannot be loaded or parsed
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
with open(file_path, "r", encoding="utf-8") as file: # type: ignore
|
|
79
|
+
sarif_data = json.load(file)
|
|
80
|
+
|
|
81
|
+
# Basic validation that it's a SARIF file
|
|
82
|
+
if not isinstance(sarif_data, dict) or "$schema" not in sarif_data:
|
|
83
|
+
logger.warning("File may not be a valid SARIF file (missing $schema)")
|
|
84
|
+
elif "sarif" not in sarif_data.get("$schema", "").lower():
|
|
85
|
+
logger.warning("File may not be a valid SARIF file (schema doesn't contain 'sarif')")
|
|
86
|
+
|
|
87
|
+
logger.debug("Successfully loaded SARIF file with %d runs", len(sarif_data.get("runs", [])))
|
|
88
|
+
return sarif_data
|
|
89
|
+
|
|
90
|
+
except FileNotFoundError:
|
|
91
|
+
error_and_exit(f"SARIF file not found: {file_path}")
|
|
92
|
+
except json.JSONDecodeError as e:
|
|
93
|
+
error_and_exit(f"Failed to parse SARIF file as JSON: {e}")
|
|
94
|
+
except Exception as e:
|
|
95
|
+
error_and_exit(f"Failed to load SARIF file: {e}")
|
|
96
|
+
|
|
97
|
+
def convert_sarif_to_ocsf(self, sarif_data: Dict[str, Any]) -> Optional[Any]:
|
|
98
|
+
"""
|
|
99
|
+
Convert SARIF data to OCSF format using Synqly API
|
|
100
|
+
|
|
101
|
+
:param Dict[str, Any] sarif_data: The SARIF data to convert
|
|
102
|
+
:raises: SystemExit if API call fails
|
|
103
|
+
:return: Converted data from Synqly API
|
|
104
|
+
:rtype: Optional[Any]
|
|
105
|
+
"""
|
|
106
|
+
api_url = "https://api.synqly.com/v1/mappings/apply"
|
|
107
|
+
|
|
108
|
+
headers = {"content-type": "application/json", "authorization": f"Bearer {self.token}"}
|
|
109
|
+
|
|
110
|
+
payload = {"mappings": ["synqly-default.sarif:1.5.0.0"], "data": sarif_data}
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
logger.debug("Making API request to convert the data: %s", api_url)
|
|
114
|
+
response = requests.post(api_url, headers=headers, json=payload, timeout=60) # 60 second timeout
|
|
115
|
+
|
|
116
|
+
if response.status_code != 200:
|
|
117
|
+
logger.error("API request failed with status %d: %s", response.status_code, response.text)
|
|
118
|
+
|
|
119
|
+
converted_data = response.json()
|
|
120
|
+
logger.debug("Successfully converted SARIF data using API.")
|
|
121
|
+
logger.debug("Response status: %d, Content length: %d bytes", response.status_code, len(response.content))
|
|
122
|
+
|
|
123
|
+
# get the results from the nested dictionary
|
|
124
|
+
if mapping := converted_data.get("result", {}).get("mapping", {}):
|
|
125
|
+
return mapping
|
|
126
|
+
logger.error("Failed to convert SARIF data using API.")
|
|
127
|
+
|
|
128
|
+
except RequestException as e:
|
|
129
|
+
if hasattr(e, "response") and e.response is not None:
|
|
130
|
+
try:
|
|
131
|
+
error_detail = e.response.json()
|
|
132
|
+
error_and_exit(f"API error ({e.response.status_code}): {error_detail}")
|
|
133
|
+
except json.JSONDecodeError:
|
|
134
|
+
error_and_exit(f"API error ({e.response.status_code}): {e.response.text}")
|
|
135
|
+
else:
|
|
136
|
+
error_and_exit(f"Failed to connect to API: {e}")
|
|
137
|
+
except json.JSONDecodeError:
|
|
138
|
+
error_and_exit("Failed to parse API response as JSON")
|
|
139
|
+
except Exception as e:
|
|
140
|
+
error_and_exit(f"Unexpected error during SARIF conversion: {e}")
|
|
141
|
+
|
|
142
|
+
def _process_single_sarif_file(
|
|
143
|
+
self,
|
|
144
|
+
sarif_file: Path,
|
|
145
|
+
output_directory: Path,
|
|
146
|
+
) -> Dict[str, Any]:
|
|
147
|
+
"""
|
|
148
|
+
Process a single SARIF file and return result information
|
|
149
|
+
|
|
150
|
+
:param Path sarif_file: Path to the SARIF file to process
|
|
151
|
+
:param Path output_directory: Output directory for converted files
|
|
152
|
+
:return: Processing result information
|
|
153
|
+
:rtype: Dict[str, Any]
|
|
154
|
+
"""
|
|
155
|
+
try:
|
|
156
|
+
sarif_data = self.load_sarif_file(sarif_file)
|
|
157
|
+
logger.debug(f"Converting {sarif_file} data to OCSF data via API...")
|
|
158
|
+
|
|
159
|
+
if "runs" in sarif_data and isinstance(sarif_data["runs"], list) and len(sarif_data["runs"]) > 0:
|
|
160
|
+
# Process each run separately and collect results
|
|
161
|
+
converted_data = [self.convert_sarif_to_ocsf(run) for run in sarif_data["runs"]]
|
|
162
|
+
else:
|
|
163
|
+
# Process the entire SARIF data as a single unit
|
|
164
|
+
converted_data = self.convert_sarif_to_ocsf(sarif_data)
|
|
165
|
+
|
|
166
|
+
# Save converted data
|
|
167
|
+
output_file = output_directory / f"{sarif_file.stem}-converted.json"
|
|
168
|
+
logger.debug("Saving converted data to: %s", output_file)
|
|
169
|
+
|
|
170
|
+
save_data_to(
|
|
171
|
+
file=output_file,
|
|
172
|
+
data=converted_data, # Only log save details in single file mode
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
created_count, updated_count = self._map_sarif_to_integration_findings(converted_data)
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
"file": sarif_file.absolute(),
|
|
179
|
+
"output": output_file.absolute(),
|
|
180
|
+
"status": "success",
|
|
181
|
+
"error": None,
|
|
182
|
+
"created": created_count,
|
|
183
|
+
"updated": updated_count,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
except Exception as e:
|
|
187
|
+
return {"file": sarif_file.absolute(), "output": None, "status": "failed", "error": str(e)}
|
|
188
|
+
|
|
189
|
+
def process_sarif_files(
|
|
190
|
+
self,
|
|
191
|
+
) -> None:
|
|
192
|
+
"""
|
|
193
|
+
Unified function to process SARIF files (single or multiple) and convert them using an API converter
|
|
194
|
+
|
|
195
|
+
:rtype: None
|
|
196
|
+
"""
|
|
197
|
+
if self.file_path.is_file():
|
|
198
|
+
sarif_files = [self.file_path]
|
|
199
|
+
else:
|
|
200
|
+
sarif_files = list(self.file_path.glob("*.sarif"))
|
|
201
|
+
|
|
202
|
+
# Ensure output directory exists
|
|
203
|
+
output_directory = self.file_path.parent / "converted"
|
|
204
|
+
check_file_path(output_directory)
|
|
205
|
+
|
|
206
|
+
# Initialize processing statistics
|
|
207
|
+
successful_conversions = 0
|
|
208
|
+
failed_conversions = 0
|
|
209
|
+
processed_files = []
|
|
210
|
+
|
|
211
|
+
if total_files := len(sarif_files):
|
|
212
|
+
self.create_scan_history()
|
|
213
|
+
else:
|
|
214
|
+
error_and_exit(f"No SARIF files found in directory: {self.file_path}")
|
|
215
|
+
if batch_mode := total_files > 1:
|
|
216
|
+
logger.info("Found %d SARIF files to convert", total_files)
|
|
217
|
+
|
|
218
|
+
# Process each SARIF file
|
|
219
|
+
for idx, sarif_file in enumerate(sarif_files, 1):
|
|
220
|
+
# Log progress for batch mode
|
|
221
|
+
if batch_mode:
|
|
222
|
+
logger.info("Processing file %d/%d: %s", idx, total_files, sarif_file.name)
|
|
223
|
+
else:
|
|
224
|
+
logger.info("Loading SARIF file: %s", sarif_file)
|
|
225
|
+
|
|
226
|
+
# Process single file
|
|
227
|
+
result = self._process_single_sarif_file(sarif_file, output_directory)
|
|
228
|
+
processed_files.append(result)
|
|
229
|
+
|
|
230
|
+
successful_conversions, failed_conversions = self._log_result_summary(
|
|
231
|
+
result=result,
|
|
232
|
+
successful_conversions=successful_conversions,
|
|
233
|
+
failed_conversions=failed_conversions,
|
|
234
|
+
batch_mode=batch_mode,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
self.scan_history.save()
|
|
238
|
+
if batch_mode:
|
|
239
|
+
logger.info(
|
|
240
|
+
"Batch conversion completed: %d successful, %d failed", successful_conversions, failed_conversions
|
|
241
|
+
)
|
|
242
|
+
logger.info("Converted files saved to: %s", output_directory.absolute())
|
|
243
|
+
else:
|
|
244
|
+
if successful_conversions == 1:
|
|
245
|
+
logger.info(
|
|
246
|
+
"Conversion completed successfully. Converted file saved to: %s", output_directory.absolute()
|
|
247
|
+
)
|
|
248
|
+
else:
|
|
249
|
+
error_and_exit("SARIF file conversion failed.")
|
|
250
|
+
|
|
251
|
+
def create_scan_history(self) -> None:
|
|
252
|
+
"""
|
|
253
|
+
Create a ScanHistory record for the SARIF import
|
|
254
|
+
|
|
255
|
+
:rtype: None
|
|
256
|
+
"""
|
|
257
|
+
if getattr(self.asset, "parentModule") == SecurityPlan.get_module_string():
|
|
258
|
+
parent_id = self.asset.parentId
|
|
259
|
+
parent_module: str = SecurityPlan.get_module_string()
|
|
260
|
+
else:
|
|
261
|
+
parent_id = self.asset.id
|
|
262
|
+
parent_module = self.asset.parentModule
|
|
263
|
+
self.scan_history = ScanHistory(
|
|
264
|
+
parentId=parent_id,
|
|
265
|
+
parentModule=parent_module,
|
|
266
|
+
scanningTool="Sarif Scanner",
|
|
267
|
+
scanDate=self.scan_date,
|
|
268
|
+
tenantsId=Asset.get_tenant_id(),
|
|
269
|
+
vLow=0,
|
|
270
|
+
vMedium=0,
|
|
271
|
+
vHigh=0,
|
|
272
|
+
vCritical=0,
|
|
273
|
+
).create()
|
|
274
|
+
|
|
275
|
+
@staticmethod
|
|
276
|
+
def _log_result_summary(
|
|
277
|
+
result: Dict[str, Any],
|
|
278
|
+
successful_conversions: int,
|
|
279
|
+
failed_conversions: int,
|
|
280
|
+
batch_mode: bool,
|
|
281
|
+
) -> tuple[int, int]:
|
|
282
|
+
"""
|
|
283
|
+
Log the result of a single SARIF file conversion and update statistics
|
|
284
|
+
|
|
285
|
+
:param Dict[str, Any] result: The result of the conversion
|
|
286
|
+
:param int successful_conversions: The number of successful conversions
|
|
287
|
+
:param int failed_conversions: The number of failed conversions
|
|
288
|
+
:param bool batch_mode: Whether running in batch mode (multiple files)
|
|
289
|
+
:return: Updated counts of successful and failed conversions
|
|
290
|
+
:rtype: tuple[int, int]
|
|
291
|
+
"""
|
|
292
|
+
if result["status"] == "success":
|
|
293
|
+
successful_conversions += 1
|
|
294
|
+
logger.debug("Successfully converted: %s -> %s", result["file"], result["output"])
|
|
295
|
+
logger.info(
|
|
296
|
+
"Successfully converted: %s -> %s, %s created vulnerabilities and %s updated vulnerabilities",
|
|
297
|
+
result["file"],
|
|
298
|
+
result["output"],
|
|
299
|
+
result["created"],
|
|
300
|
+
result["updated"],
|
|
301
|
+
)
|
|
302
|
+
else:
|
|
303
|
+
failed_conversions += 1
|
|
304
|
+
if batch_mode:
|
|
305
|
+
logger.error("Failed to convert %s: %s", result["file"], result["error"])
|
|
306
|
+
else:
|
|
307
|
+
error_and_exit(f"Failed to convert SARIF file: {result['error']}")
|
|
308
|
+
return successful_conversions, failed_conversions
|
|
309
|
+
|
|
310
|
+
def _map_sarif_to_integration_findings(
|
|
311
|
+
self,
|
|
312
|
+
converted_data: list[dict[str, Any]],
|
|
313
|
+
) -> tuple[int, int]:
|
|
314
|
+
"""
|
|
315
|
+
Map converted SARIF data to a list of IntegrationFinding objects
|
|
316
|
+
|
|
317
|
+
:param Any converted_data: The converted SARIF data from the API
|
|
318
|
+
:return: Number of created and updated vulnerabilities
|
|
319
|
+
:rtype: tuple[int, int]
|
|
320
|
+
"""
|
|
321
|
+
create_vuln_count = 0
|
|
322
|
+
updated_vuln_count = 0
|
|
323
|
+
# Convert the nested dictionary to a list of ApplicationSecurityPostureFinding objects for easier parsing
|
|
324
|
+
with self.progress as progress:
|
|
325
|
+
task = progress.add_task("Mapping Sarif data to RegScale vulnerabilities...", total=len(converted_data))
|
|
326
|
+
vulneribility_task = progress.add_task("Creating vulnerabilities and mappings...", total=0)
|
|
327
|
+
for result in converted_data:
|
|
328
|
+
name = self._parse_name(result)
|
|
329
|
+
findings = ApplicationSecurityPostureFinding(**result).vulnerabilities
|
|
330
|
+
progress.update(vulneribility_task, total=len(findings))
|
|
331
|
+
for finding in findings:
|
|
332
|
+
created, vuln = Vulnerability(
|
|
333
|
+
title=finding.title,
|
|
334
|
+
severity=Issue.assign_severity(finding.severity), # type: ignore
|
|
335
|
+
description=self._build_description(finding),
|
|
336
|
+
status=IssueStatus.Open,
|
|
337
|
+
firstSeen=self.scan_date,
|
|
338
|
+
lastSeen=self.scan_date,
|
|
339
|
+
plugInName=name,
|
|
340
|
+
plugInId=self._parse_plugin_id(finding),
|
|
341
|
+
parentId=self.parent_id,
|
|
342
|
+
parentModule=self.parent_module,
|
|
343
|
+
).create_or_update_with_status()
|
|
344
|
+
self.update_scan_history_count(vuln.severity)
|
|
345
|
+
if created:
|
|
346
|
+
create_vuln_count += 1
|
|
347
|
+
else:
|
|
348
|
+
updated_vuln_count += 1
|
|
349
|
+
# Map vulnerability to asset
|
|
350
|
+
VulnerabilityMapping(
|
|
351
|
+
assetId=self.asset.id,
|
|
352
|
+
vulnerabilityId=vuln.id,
|
|
353
|
+
scanId=self.scan_history.id,
|
|
354
|
+
securityPlanId=self.asset.parentId if self.asset.parentModule == "securityplans" else None,
|
|
355
|
+
status=vuln.status,
|
|
356
|
+
firstSeen=vuln.firstSeen,
|
|
357
|
+
lastSeen=vuln.lastSeen,
|
|
358
|
+
dateCreated=self.scan_date,
|
|
359
|
+
).create_or_update()
|
|
360
|
+
progress.update(vulneribility_task, advance=1)
|
|
361
|
+
progress.update(task, advance=1)
|
|
362
|
+
return create_vuln_count, updated_vuln_count
|
|
363
|
+
|
|
364
|
+
@staticmethod
|
|
365
|
+
def _parse_name(result: Dict[str, Any]) -> str:
|
|
366
|
+
"""
|
|
367
|
+
Parse the name and version from the result metadata
|
|
368
|
+
|
|
369
|
+
:param Dict[str, Any] result: The result to parse the name and version from
|
|
370
|
+
:return: The name and version string
|
|
371
|
+
:rtype: str
|
|
372
|
+
"""
|
|
373
|
+
if metadata := result["metadata"]:
|
|
374
|
+
name = metadata.get("product", {}).get("name", "Static Scanner")
|
|
375
|
+
version = metadata.get("version")
|
|
376
|
+
else:
|
|
377
|
+
name = "Static Scanner"
|
|
378
|
+
version = None
|
|
379
|
+
name = f"{name} {version}" if version else name
|
|
380
|
+
return name
|
|
381
|
+
|
|
382
|
+
@staticmethod
|
|
383
|
+
def _parse_plugin_id(finding: OcsfVuln) -> str:
|
|
384
|
+
"""
|
|
385
|
+
Parse the plugin ID from the finding
|
|
386
|
+
|
|
387
|
+
:param ocsf_vuln finding: The finding to parse the plugin ID from
|
|
388
|
+
:return: The plugin ID string
|
|
389
|
+
:rtype: str
|
|
390
|
+
"""
|
|
391
|
+
if cwe := getattr(finding, "cwe"):
|
|
392
|
+
return cwe.uid
|
|
393
|
+
elif cve := getattr(finding, "cve"):
|
|
394
|
+
return cve.uid
|
|
395
|
+
return finding.title
|
|
396
|
+
|
|
397
|
+
def update_scan_history_count(self, severity: str) -> None:
|
|
398
|
+
"""
|
|
399
|
+
Update the scan history count for a given severity
|
|
400
|
+
|
|
401
|
+
:param str severity: The severity of the vulnerability
|
|
402
|
+
:rtype: None
|
|
403
|
+
"""
|
|
404
|
+
if "Low" in severity:
|
|
405
|
+
self.scan_history.vLow += 1
|
|
406
|
+
elif "Moderate" in severity:
|
|
407
|
+
self.scan_history.vMedium += 1
|
|
408
|
+
elif "High" in severity:
|
|
409
|
+
self.scan_history.vHigh += 1
|
|
410
|
+
elif "Critical" in severity:
|
|
411
|
+
self.scan_history.vCritical += 1
|
|
412
|
+
else:
|
|
413
|
+
self.scan_history.vInfo += 1
|
|
414
|
+
|
|
415
|
+
@staticmethod
|
|
416
|
+
def _build_description(finding: OcsfVuln) -> str:
|
|
417
|
+
"""
|
|
418
|
+
Build a detailed description for a vulnerability finding
|
|
419
|
+
|
|
420
|
+
:param ocsf_vuln finding: The finding to build the description for
|
|
421
|
+
:return: Detailed description string
|
|
422
|
+
:rtype: str
|
|
423
|
+
"""
|
|
424
|
+
description = f"{finding.desc}\n"
|
|
425
|
+
for affected_code in getattr(finding, "affected_code", []):
|
|
426
|
+
|
|
427
|
+
for key, value in affected_code.dict().items():
|
|
428
|
+
if isinstance(value, dict):
|
|
429
|
+
for sub_key, sub_value in value.items():
|
|
430
|
+
description += f"file {sub_key}: {sub_value}\n"
|
|
431
|
+
description += f"{key}: {value}\n"
|
|
432
|
+
return description
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""SARIF Converter integration for RegScale CLI"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from regscale.core.app.utils.app_utils import (
|
|
13
|
+
get_current_datetime,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("regscale")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.group()
|
|
20
|
+
def sarif():
|
|
21
|
+
"""Convert SARIF files to OCSF data using an API converter."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@sarif.command(name="import")
|
|
25
|
+
@click.option(
|
|
26
|
+
"--file_path",
|
|
27
|
+
"-f",
|
|
28
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=True, path_type=Path),
|
|
29
|
+
help="Path to the SARIF file or a directory of files to convert",
|
|
30
|
+
prompt="Enter the path",
|
|
31
|
+
required=True,
|
|
32
|
+
)
|
|
33
|
+
@click.option(
|
|
34
|
+
"--asset_id",
|
|
35
|
+
"-id",
|
|
36
|
+
type=click.INT,
|
|
37
|
+
help="The RegScale Asset ID # to import the findings to.",
|
|
38
|
+
prompt="RegScale Asset ID",
|
|
39
|
+
required=True,
|
|
40
|
+
)
|
|
41
|
+
@click.option(
|
|
42
|
+
"--scan_date",
|
|
43
|
+
"-sd",
|
|
44
|
+
type=click.DateTime(formats=["%Y-%m-%d"]),
|
|
45
|
+
help="The scan date of the file.",
|
|
46
|
+
required=False,
|
|
47
|
+
default=get_current_datetime(),
|
|
48
|
+
)
|
|
49
|
+
def import_sarif(file_path: Path, asset_id: int, scan_date: Optional[datetime.datetime] = None) -> None:
|
|
50
|
+
"""Convert a SARIF file(s) to OCSF format using an API converter."""
|
|
51
|
+
process_sarif_files(file_path, asset_id, scan_date)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def process_sarif_files(file_path: Path, asset_id: int, scan_date: Optional[datetime.datetime]) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Process SARIF files for import.
|
|
57
|
+
|
|
58
|
+
:param Path file_path: Path to the SARIF file or directory of files
|
|
59
|
+
:param int asset_id: The RegScale Asset ID to import the findings to
|
|
60
|
+
:param Optional[datetime.datetime] scan_date: The scan date of the file
|
|
61
|
+
:return: None
|
|
62
|
+
"""
|
|
63
|
+
from regscale.integrations.commercial.sarif.sairf_importer import SarifImporter
|
|
64
|
+
|
|
65
|
+
if not scan_date:
|
|
66
|
+
scan_date = get_current_datetime()
|
|
67
|
+
SarifImporter(file_path, asset_id, scan_date=scan_date)
|
|
@@ -1,9 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "CISA Catalog of Known Exploited Vulnerabilities",
|
|
3
|
-
"catalogVersion": "2025.09.
|
|
4
|
-
"dateReleased": "2025-09-
|
|
5
|
-
"count":
|
|
3
|
+
"catalogVersion": "2025.09.03",
|
|
4
|
+
"dateReleased": "2025-09-03T17:00:44.122Z",
|
|
5
|
+
"count": 1410,
|
|
6
6
|
"vulnerabilities": [
|
|
7
|
+
{
|
|
8
|
+
"cveID": "CVE-2023-50224",
|
|
9
|
+
"vendorProject": "TP-Link",
|
|
10
|
+
"product": "TL-WR841N",
|
|
11
|
+
"vulnerabilityName": "TP-Link TL-WR841N Authentication Bypass by Spoofing Vulnerability",
|
|
12
|
+
"dateAdded": "2025-09-03",
|
|
13
|
+
"shortDescription": "TP-Link TL-WR841N contains an authentication bypass by spoofing vulnerability within the httpd service, which listens on TCP port 80 by default, leading to the disclose of stored credentials. The impacted products could be end-of-life (EoL) and\/or end-of-service (EoS). Users should discontinue product utilization.",
|
|
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-09-24",
|
|
16
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
+
"notes": "https:\/\/www.tp-link.com\/us\/support\/faq\/4308\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2023-50224",
|
|
18
|
+
"cwes": [
|
|
19
|
+
"CWE-290"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"cveID": "CVE-2025-9377",
|
|
24
|
+
"vendorProject": "TP-Link",
|
|
25
|
+
"product": "Multiple Routers",
|
|
26
|
+
"vulnerabilityName": "TP-Link Archer C7(EU) and TL-WR841N\/ND(MS) OS Command Injection Vulnerability",
|
|
27
|
+
"dateAdded": "2025-09-03",
|
|
28
|
+
"shortDescription": "TP-Link Archer C7(EU) and TL-WR841N\/ND(MS) contain an OS command injection vulnerability that exists in the Parental Control page. The impacted products could be end-of-life (EoL) and\/or end-of-service (EoS). Users should discontinue product utilization.",
|
|
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-09-24",
|
|
31
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
32
|
+
"notes": "https:\/\/www.tp-link.com\/us\/support\/faq\/4308\/ ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-9377",
|
|
33
|
+
"cwes": [
|
|
34
|
+
"CWE-78"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
7
37
|
{
|
|
8
38
|
"cveID": "CVE-2020-24363",
|
|
9
39
|
"vendorProject": "TP-Link",
|
|
@@ -32,10 +32,9 @@ from regscale.core.app.utils.app_utils import (
|
|
|
32
32
|
from regscale.core.app.utils.parser_utils import safe_datetime_str
|
|
33
33
|
from regscale.integrations.scanner_integration import ScannerIntegration
|
|
34
34
|
from regscale.models import IssueStatus, Metadata, regscale_models
|
|
35
|
-
from regscale.models.app_models.mapping import Mapping
|
|
36
35
|
from regscale.models.regscale_models import Asset, File, IssueSeverity, Vulnerability
|
|
37
36
|
|
|
38
|
-
logger = logging.getLogger(
|
|
37
|
+
logger = logging.getLogger("regscale")
|
|
39
38
|
|
|
40
39
|
DT_FORMAT = "%Y-%m-%d"
|
|
41
40
|
|
|
@@ -85,7 +85,7 @@ class Vulnerabilities(SynqlyModel):
|
|
|
85
85
|
if scan_date := date_obj(scan_date):
|
|
86
86
|
vuln_filter.append(f"finding.last_seen_time[gte]{scan_date.isoformat()}")
|
|
87
87
|
else:
|
|
88
|
-
|
|
88
|
+
vuln_filter.append(f"finding.last_seen_time[gte]{get_last_pull_epoch(regscale_ssp_id)}")
|
|
89
89
|
else:
|
|
90
90
|
vuln_filter.append(f"finding.last_seen_time[gte]{get_last_pull_epoch(regscale_ssp_id)}")
|
|
91
91
|
return vuln_filter
|
|
@@ -5,7 +5,7 @@ from typing import Any, Union, TYPE_CHECKING, Optional
|
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
7
|
from regscale.models.integration_models.synqly_models.connectors import Edr, Ticketing, Vulnerabilities
|
|
8
|
-
from synqly.engine.resources.ocsf.resources.
|
|
8
|
+
from synqly.engine.resources.ocsf.resources.v_1_3_0.resources.securityfinding import ResourceDetails, Vulnerability
|
|
9
9
|
|
|
10
10
|
from synqly import engine
|
|
11
11
|
from synqly.engine import CreateTicketRequest
|
|
@@ -160,7 +160,7 @@ class Mapper:
|
|
|
160
160
|
:return: A dictionary of the parsed data
|
|
161
161
|
:rtype: dict
|
|
162
162
|
"""
|
|
163
|
-
from synqly.engine.resources.ocsf.resources.
|
|
163
|
+
from synqly.engine.resources.ocsf.resources.v_1_3_0.resources.securityfinding import Remediation
|
|
164
164
|
|
|
165
165
|
finding_data = {
|
|
166
166
|
"cve": None,
|
|
@@ -526,6 +526,7 @@ class Issue(RegScaleModel):
|
|
|
526
526
|
"low": IssueSeverity.Low.value,
|
|
527
527
|
"moderate": IssueSeverity.Moderate.value,
|
|
528
528
|
"high": IssueSeverity.High.value,
|
|
529
|
+
"critical": IssueSeverity.Critical.value,
|
|
529
530
|
}
|
|
530
531
|
severity = IssueSeverity.NotAssigned.value
|
|
531
532
|
# see if the value is an int or float
|
|
@@ -542,8 +543,10 @@ class Issue(RegScaleModel):
|
|
|
542
543
|
severity = severity_levels["low"]
|
|
543
544
|
elif value.lower() in ["medium", "moderate", "major"]:
|
|
544
545
|
severity = severity_levels["moderate"]
|
|
545
|
-
elif value.lower() in ["high", "
|
|
546
|
+
elif value.lower() in ["high", "highest", "blocker"]:
|
|
546
547
|
severity = severity_levels["high"]
|
|
548
|
+
elif value.lower() in ["critical"]:
|
|
549
|
+
severity = severity_levels["critical"]
|
|
547
550
|
elif value in list(severity_levels.values()):
|
|
548
551
|
severity = value
|
|
549
552
|
return severity
|
|
@@ -67,8 +67,8 @@ class Vulnerability(RegScaleModel):
|
|
|
67
67
|
lastSeen: Optional[str] = None
|
|
68
68
|
firstSeen: Optional[str] = None
|
|
69
69
|
daysOpen: Optional[int] = None
|
|
70
|
-
dns: Optional[str] =
|
|
71
|
-
ipAddress: Optional[str] =
|
|
70
|
+
dns: Optional[str] = ""
|
|
71
|
+
ipAddress: Optional[str] = ""
|
|
72
72
|
mitigated: Optional[bool] = None
|
|
73
73
|
operatingSystem: Optional[str] = None
|
|
74
74
|
port: Optional[Union[str, int]] = None
|
|
@@ -83,7 +83,7 @@ class Vulnerability(RegScaleModel):
|
|
|
83
83
|
cvsSv3BaseScore: Optional[Union[float, int]] = None
|
|
84
84
|
description: Optional[str] = None
|
|
85
85
|
plugInText: Optional[str] = None
|
|
86
|
-
tenantsId: int = Field(
|
|
86
|
+
tenantsId: int = Field(default_factory=RegScaleModel.get_tenant_id)
|
|
87
87
|
isPublic: bool = Field(default=False)
|
|
88
88
|
dateClosed: Optional[str] = None
|
|
89
89
|
status: Optional[Union[str, IssueStatus]] = Field(default_factory=lambda: IssueStatus.Open)
|
regscale/regscale.py
CHANGED
|
@@ -172,6 +172,7 @@ okta = import_command_with_timing(COMMERCIAL, "okta")
|
|
|
172
172
|
prisma = import_command_with_timing(COMMERCIAL, "prisma")
|
|
173
173
|
qualys = import_command_with_timing(COMMERCIAL, "qualys")
|
|
174
174
|
salesforce = import_command_with_timing(COMMERCIAL, "salesforce")
|
|
175
|
+
sarif = import_command_with_timing(COMMERCIAL, "sarif")
|
|
175
176
|
sap = import_command_with_timing("regscale.integrations.commercial.sap.click", "sap")
|
|
176
177
|
sysdig = import_command_with_timing("regscale.integrations.commercial.sap.sysdig.click", "sysdig")
|
|
177
178
|
servicenow = import_command_with_timing(COMMERCIAL, "servicenow")
|
|
@@ -756,8 +757,8 @@ cli.add_command(catalog) # add Catalog Management Feature
|
|
|
756
757
|
cli.add_command(compare) # add Comparison support
|
|
757
758
|
cli.add_command(control_editor) # add Control Editor Feature
|
|
758
759
|
cli.add_command(evidence) # add Evidence Feature
|
|
759
|
-
cli.add_command(migrations) # add data migration support
|
|
760
760
|
cli.add_command(issues) # add POAM(Issues) Editor Feature
|
|
761
|
+
cli.add_command(migrations) # add data migration support
|
|
761
762
|
cli.add_command(model) # add POAM(Issues) Editor Feature
|
|
762
763
|
cli.add_command(set_permissions) # add builk editor for record permissions
|
|
763
764
|
|
|
@@ -791,15 +792,16 @@ cli.add_command(prisma) # add Prisma support
|
|
|
791
792
|
cli.add_command(qualys) # add Qualys Functionality
|
|
792
793
|
cli.add_command(salesforce) # add Salesforce support
|
|
793
794
|
cli.add_command(sap) # add SAP Concur support
|
|
795
|
+
cli.add_command(sarif) # add SARIF Converter support
|
|
794
796
|
cli.add_command(servicenow) # add ServiceNow support
|
|
795
797
|
cli.add_command(sicura) # add Sicura Integration
|
|
796
798
|
cli.add_command(snyk) # add Snyk support
|
|
797
|
-
cli.add_command(veracode) # add Veracode Integration
|
|
798
799
|
cli.add_command(sonarcloud) # add SonarCloud Integration
|
|
799
800
|
cli.add_command(stig) # add STIGv2 support
|
|
800
801
|
cli.add_command(stig_mapper) # add STIG Mapper support
|
|
801
802
|
cli.add_command(tenable) # add Tenable & TenableV2 support
|
|
802
803
|
cli.add_command(trivy) # add Trivy support
|
|
804
|
+
cli.add_command(veracode) # add Veracode Integration
|
|
803
805
|
cli.add_command(wiz) # add Wiz support
|
|
804
806
|
cli.add_command(xray) # add JFrog Xray support
|
|
805
807
|
|
|
@@ -808,12 +810,12 @@ cli.add_command(xray) # add JFrog Xray support
|
|
|
808
810
|
############################################################
|
|
809
811
|
cli.add_command(alienvault) # add Alienvault OTX integration
|
|
810
812
|
cli.add_command(cisa) # add CISA support
|
|
813
|
+
cli.add_command(criticality_updater) # add Criticality Updater support
|
|
811
814
|
cli.add_command(csam) # add CSAM support
|
|
812
815
|
cli.add_command(emass) # add eMASS support
|
|
813
816
|
cli.add_command(fedramp) # add FedRAMP support
|
|
814
817
|
cli.add_command(nist) # add Nist_Catalog support
|
|
815
818
|
cli.add_command(oscal) # add OSCAL support
|
|
816
|
-
cli.add_command(criticality_updater) # add Criticality Updater support
|
|
817
819
|
|
|
818
820
|
# start function for the CLI
|
|
819
821
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: regscale-cli
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.23.0.0
|
|
4
4
|
Summary: Command Line Interface (CLI) for bulk processing/loading data into RegScale
|
|
5
5
|
Home-page: https://github.com/RegScale/regscale-cli
|
|
6
6
|
Author: Travis Howerton
|
|
@@ -68,7 +68,7 @@ Requires-Dist: setuptools
|
|
|
68
68
|
Requires-Dist: simple-salesforce
|
|
69
69
|
Requires-Dist: smart-open ~=7.0
|
|
70
70
|
Requires-Dist: static
|
|
71
|
-
Requires-Dist: synqly
|
|
71
|
+
Requires-Dist: synqly >=0.4.56
|
|
72
72
|
Requires-Dist: tools
|
|
73
73
|
Requires-Dist: typing-extensions ~=4.12.2
|
|
74
74
|
Requires-Dist: wheel
|
|
@@ -150,7 +150,7 @@ Requires-Dist: setuptools >=69.0.0 ; extra == 'airflow'
|
|
|
150
150
|
Requires-Dist: simple-salesforce ; extra == 'airflow'
|
|
151
151
|
Requires-Dist: smart-open ~=7.0 ; extra == 'airflow'
|
|
152
152
|
Requires-Dist: static ; extra == 'airflow'
|
|
153
|
-
Requires-Dist: synqly ; extra == 'airflow'
|
|
153
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'airflow'
|
|
154
154
|
Requires-Dist: tools ; extra == 'airflow'
|
|
155
155
|
Requires-Dist: typing-extensions ~=4.12.2 ; extra == 'airflow'
|
|
156
156
|
Requires-Dist: wheel ; extra == 'airflow'
|
|
@@ -235,7 +235,7 @@ Requires-Dist: setuptools >=69.0.0 ; extra == 'airflow-azure'
|
|
|
235
235
|
Requires-Dist: simple-salesforce ; extra == 'airflow-azure'
|
|
236
236
|
Requires-Dist: smart-open ~=7.0 ; extra == 'airflow-azure'
|
|
237
237
|
Requires-Dist: static ; extra == 'airflow-azure'
|
|
238
|
-
Requires-Dist: synqly ; extra == 'airflow-azure'
|
|
238
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'airflow-azure'
|
|
239
239
|
Requires-Dist: tools ; extra == 'airflow-azure'
|
|
240
240
|
Requires-Dist: typing-extensions ~=4.12.2 ; extra == 'airflow-azure'
|
|
241
241
|
Requires-Dist: wheel ; extra == 'airflow-azure'
|
|
@@ -320,7 +320,7 @@ Requires-Dist: setuptools >=69.0.0 ; extra == 'airflow-sqlserver'
|
|
|
320
320
|
Requires-Dist: simple-salesforce ; extra == 'airflow-sqlserver'
|
|
321
321
|
Requires-Dist: smart-open ~=7.0 ; extra == 'airflow-sqlserver'
|
|
322
322
|
Requires-Dist: static ; extra == 'airflow-sqlserver'
|
|
323
|
-
Requires-Dist: synqly ; extra == 'airflow-sqlserver'
|
|
323
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'airflow-sqlserver'
|
|
324
324
|
Requires-Dist: tools ; extra == 'airflow-sqlserver'
|
|
325
325
|
Requires-Dist: typing-extensions ~=4.12.2 ; extra == 'airflow-sqlserver'
|
|
326
326
|
Requires-Dist: wheel ; extra == 'airflow-sqlserver'
|
|
@@ -410,7 +410,7 @@ Requires-Dist: setuptools >=69.0.0 ; extra == 'all'
|
|
|
410
410
|
Requires-Dist: simple-salesforce ; extra == 'all'
|
|
411
411
|
Requires-Dist: smart-open ~=7.0 ; extra == 'all'
|
|
412
412
|
Requires-Dist: static ; extra == 'all'
|
|
413
|
-
Requires-Dist: synqly ; extra == 'all'
|
|
413
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'all'
|
|
414
414
|
Requires-Dist: tools ; extra == 'all'
|
|
415
415
|
Requires-Dist: typing-extensions ~=4.12.2 ; extra == 'all'
|
|
416
416
|
Requires-Dist: werkzeug >=2.3.8 ; extra == 'all'
|
|
@@ -472,7 +472,7 @@ Requires-Dist: setuptools ; extra == 'ansible'
|
|
|
472
472
|
Requires-Dist: simple-salesforce ; extra == 'ansible'
|
|
473
473
|
Requires-Dist: smart-open ~=7.0 ; extra == 'ansible'
|
|
474
474
|
Requires-Dist: static ; extra == 'ansible'
|
|
475
|
-
Requires-Dist: synqly ; extra == 'ansible'
|
|
475
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'ansible'
|
|
476
476
|
Requires-Dist: tools ; extra == 'ansible'
|
|
477
477
|
Requires-Dist: typing-extensions ~=4.12.2 ; extra == 'ansible'
|
|
478
478
|
Requires-Dist: wheel ; extra == 'ansible'
|
|
@@ -555,7 +555,7 @@ Requires-Dist: sphinx ; extra == 'dev'
|
|
|
555
555
|
Requires-Dist: sphinx-autodoc-typehints ; extra == 'dev'
|
|
556
556
|
Requires-Dist: sphinx-click ; extra == 'dev'
|
|
557
557
|
Requires-Dist: static ; extra == 'dev'
|
|
558
|
-
Requires-Dist: synqly ; extra == 'dev'
|
|
558
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'dev'
|
|
559
559
|
Requires-Dist: tools ; extra == 'dev'
|
|
560
560
|
Requires-Dist: types-python-dateutil ; extra == 'dev'
|
|
561
561
|
Requires-Dist: types-pyyaml ; extra == 'dev'
|
|
@@ -624,7 +624,7 @@ Requires-Dist: setuptools ; extra == 'server'
|
|
|
624
624
|
Requires-Dist: simple-salesforce ; extra == 'server'
|
|
625
625
|
Requires-Dist: smart-open ~=7.0 ; extra == 'server'
|
|
626
626
|
Requires-Dist: static ; extra == 'server'
|
|
627
|
-
Requires-Dist: synqly ; extra == 'server'
|
|
627
|
+
Requires-Dist: synqly >=0.4.56 ; extra == 'server'
|
|
628
628
|
Requires-Dist: tools ; extra == 'server'
|
|
629
629
|
Requires-Dist: typing-extensions ~=4.12.2 ; extra == 'server'
|
|
630
630
|
Requires-Dist: werkzeug >=2.3.8 ; extra == 'server'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
regscale/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
|
|
2
|
-
regscale/_version.py,sha256=
|
|
3
|
-
regscale/regscale.py,sha256=
|
|
2
|
+
regscale/_version.py,sha256=WCBjfKcCkvP_rge5Txea03DdGp8t8G4D7ysVpze60LM,1198
|
|
3
|
+
regscale/regscale.py,sha256=Lfjztf_bYITfITh830v1ENkrj5ZBDbNinygsUxGdh7o,31116
|
|
4
4
|
regscale/airflow/__init__.py,sha256=yMwN0Bz4JbM0nl5qY_hPegxo_O2ilhTOL9PY5Njhn-s,270
|
|
5
5
|
regscale/airflow/click_dags.py,sha256=H3SUR5jkvInNMv1gu-VG-Ja_H-kH145CpQYNalWNAbE,4520
|
|
6
6
|
regscale/airflow/click_mixins.py,sha256=BTwKWsEu6KVtlrzFbXpD_RuEpMzc-CSnCCySUzqzCgQ,3571
|
|
@@ -35,7 +35,7 @@ regscale/core/decorators.py,sha256=YuX9VCbCJh76qlc_6ungu0nD4VT1VsV2spXH_bsDTfY,8
|
|
|
35
35
|
regscale/core/lazy_group.py,sha256=S2-nA5tzm47A929NOTqGkzrzKuZQDlq2OAPbNnG1W1Q,2046
|
|
36
36
|
regscale/core/login.py,sha256=-8vy1HVAtv1iARnZh6uzYtwmx8VFYPwLYR0QAf1ttCk,2714
|
|
37
37
|
regscale/core/app/__init__.py,sha256=nGcCN1vWBAnZzoccIlt0jwWQdegCOrBWOB7LPhQkQSs,96
|
|
38
|
-
regscale/core/app/api.py,sha256=
|
|
38
|
+
regscale/core/app/api.py,sha256=vDcdvXLz9hEu6R-U-f9z7zZ-aXmmhCjiUKlhzm5M6zA,23602
|
|
39
39
|
regscale/core/app/application.py,sha256=qGi5aLixOGhUq_ioGqx9vSbZBKXWxtqNaaQ_pQX9kXM,32020
|
|
40
40
|
regscale/core/app/logz.py,sha256=8AdBKmquv45JGi5fCMc38JqQg6-FpUONGmqfd5EGwrI,2583
|
|
41
41
|
regscale/core/app/internal/__init__.py,sha256=rod4nmE7rrYDdbuYF4mCWz49TK_2r-v4tWy1UHW63r0,4808
|
|
@@ -57,7 +57,7 @@ regscale/core/app/internal/workflow.py,sha256=SpgYk1QyzdilVLOK1fFzaKhdLspumaugf5
|
|
|
57
57
|
regscale/core/app/utils/XMLIR.py,sha256=M_RrCsbjznihatkucCKw6dPgHTPQczXyqIdUXWhuCLI,8328
|
|
58
58
|
regscale/core/app/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
regscale/core/app/utils/api_handler.py,sha256=T1meKw6Yi3ZAgRbQ1xuKDVh9Q9B8mbMqqN_LrSwIlAM,11765
|
|
60
|
-
regscale/core/app/utils/app_utils.py,sha256=
|
|
60
|
+
regscale/core/app/utils/app_utils.py,sha256=c7V61VYaHaz_4o4YNmpQl0gZ3bHlbRwfpj-fUBVcb_s,37134
|
|
61
61
|
regscale/core/app/utils/file_utils.py,sha256=x7cqYPxJ-PgSb2lX_K6zhdqyGQjOCmr04lnqdBQV3hI,9269
|
|
62
62
|
regscale/core/app/utils/parser_utils.py,sha256=aBEgcFwbJMD-ARf3wzf-tyWwR6NHvzEcdYcPMm8hGqo,2533
|
|
63
63
|
regscale/core/app/utils/pickle_file_handler.py,sha256=iMdv4N8z00TB5LyPdxIcLKNRpDQVWQ8ZQWAqCKpqmF0,1695
|
|
@@ -100,7 +100,7 @@ regscale/core/utils/urls.py,sha256=ZcU9OJqDmVQXgu6BrLESIp2KMkkUuzTZZ_wHsZMzfA4,6
|
|
|
100
100
|
regscale/dev/__init__.py,sha256=wVP59B1iurp36ul8pD_CjmunJLHOdKWWodz1r5loNvw,190
|
|
101
101
|
regscale/dev/analysis.py,sha256=9s6pfTGK6FBqV-karQQnCc_GYHloETmFyvsvVJ5jBm8,15603
|
|
102
102
|
regscale/dev/cli.py,sha256=VT9QHhfJX10KdJlSL9zBx-D__0H7qqS8G1GPwOb59Xs,8783
|
|
103
|
-
regscale/dev/code_gen.py,sha256=
|
|
103
|
+
regscale/dev/code_gen.py,sha256=wh9398z_CoEN7ndBf31N5xrXZx1FKoZK34w77WWfY9Y,22538
|
|
104
104
|
regscale/dev/dirs.py,sha256=wmEKM4UZjMXDiNi6a17JchhyfQNvJg6ACQmqT_Xt6V0,2044
|
|
105
105
|
regscale/dev/docs.py,sha256=Ngtd2Z0vYXYQXUIAqhL02f-_fUuIpmTPa5YIO3wAOHY,14678
|
|
106
106
|
regscale/dev/monitoring.py,sha256=h0pewRSXF8bLEtQ9dB3D0XqGTM4HtjaCiUUH3ijEllM,835
|
|
@@ -116,7 +116,7 @@ regscale/integrations/integration_override.py,sha256=HjYBCuvNpU3t3FptaqYAkdexLFO
|
|
|
116
116
|
regscale/integrations/jsonl_scanner_integration.py,sha256=l8nq_T3rE1XX-6HxrNHm3xzxCNWbIjxQvGMdtZWs7KQ,57003
|
|
117
117
|
regscale/integrations/scanner_integration.py,sha256=fMdA4SrpzJJiTTTPtKCjq5HjeoM1QrIhHNp7wVj1BuI,161584
|
|
118
118
|
regscale/integrations/variables.py,sha256=MfQ34WuYVN5437A9sZ2ssHRkA3gFhMHfk1DVasceGmY,2336
|
|
119
|
-
regscale/integrations/commercial/__init__.py,sha256=
|
|
119
|
+
regscale/integrations/commercial/__init__.py,sha256=lbwZX0BKAe5euU5d_MV4MaAhCvd5actLiCklk9LHUAA,14276
|
|
120
120
|
regscale/integrations/commercial/ad.py,sha256=YXSmK8vRf6yi2GnREGa5GrE6GelhFrLj44SY8AO1pK0,15509
|
|
121
121
|
regscale/integrations/commercial/burp.py,sha256=3BLNKLfwL1x7jfhd8MJD6hdHEpj58pOEtrtCkn2hcWA,3344
|
|
122
122
|
regscale/integrations/commercial/cpe.py,sha256=vUHKGdq0UlR38pZWqqHLLTdDfooLtE9zIiFHdoFcUr0,5735
|
|
@@ -201,6 +201,9 @@ regscale/integrations/commercial/sap/sysdig/sysdig_scanner.py,sha256=3Xy6vSznlb5
|
|
|
201
201
|
regscale/integrations/commercial/sap/tenable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
202
202
|
regscale/integrations/commercial/sap/tenable/click.py,sha256=vCdRe6d5ey6mywtL8GY21n5ecqWTdYLLDceEOy8QrLg,1425
|
|
203
203
|
regscale/integrations/commercial/sap/tenable/scanner.py,sha256=eeXXe2b-zoth80pVcasO7Cy-3NhW_4PcDhin1G8hj0o,9363
|
|
204
|
+
regscale/integrations/commercial/sarif/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
205
|
+
regscale/integrations/commercial/sarif/sairf_importer.py,sha256=gCuDsybT0jbhCtQLJW0L88hLxUpWIgatVERU4D6_9Xc,17886
|
|
206
|
+
regscale/integrations/commercial/sarif/sarif_converter.py,sha256=VwUBfw6FYXIVGqLsqoipPEYbF7GJSOZ6kkCyXQDlNhM,1900
|
|
204
207
|
regscale/integrations/commercial/sicura/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
205
208
|
regscale/integrations/commercial/sicura/api.py,sha256=4FDM3ATk8bysdGaBtcfsexlZoTHUf-ckA60eGrK-KDk,32151
|
|
206
209
|
regscale/integrations/commercial/sicura/commands.py,sha256=-54gqCpmGECC1ph5Wpr8cwYhBscsQy1V_24-xQ0sFyw,1874
|
|
@@ -319,7 +322,7 @@ regscale/models/integration_models/azure_alerts.py,sha256=2etrpvcxa7jVQrc98bJlVG
|
|
|
319
322
|
regscale/models/integration_models/base64.py,sha256=sxV6O5qY1_TstJENX5jBPsSdQwmA83-NNhgJFunXiZE,570
|
|
320
323
|
regscale/models/integration_models/burp.py,sha256=FBEBkH3U0Q8vq71FFoWnvgLRF5Hkr9GYmQFmNNHFrVk,16932
|
|
321
324
|
regscale/models/integration_models/burp_models.py,sha256=UytDTAcCaxyu-knFkm_mEUH6UmWK3OTXKSC9Sc6OjVs,3669
|
|
322
|
-
regscale/models/integration_models/cisa_kev_data.json,sha256=
|
|
325
|
+
regscale/models/integration_models/cisa_kev_data.json,sha256=UVI0CQadIoComCdjuIs5wUsNCZ6ARdpQv1_7W439Qn8,1264242
|
|
323
326
|
regscale/models/integration_models/defender_data.py,sha256=jsAcjKxiGmumGerj7xSWkFd6r__YpuKDnYX5o7xHDiE,2844
|
|
324
327
|
regscale/models/integration_models/defenderimport.py,sha256=Ze4kgwns-IYPyO7sBjEzW8PXWlxwU-DAo2fIyRcTC3k,6242
|
|
325
328
|
regscale/models/integration_models/drf.py,sha256=Aq7AdLa_CH97NrnR-CxaFI22JjVN9uCxVN7Z-BBUaNU,18896
|
|
@@ -346,13 +349,13 @@ regscale/models/integration_models/axonius_models/connectors/assets.py,sha256=6m
|
|
|
346
349
|
regscale/models/integration_models/ecr_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
347
350
|
regscale/models/integration_models/ecr_models/data.py,sha256=l28DCidXar1JygYBQZL9MYenQA9N-Cx3Skf51IOjZcw,1017
|
|
348
351
|
regscale/models/integration_models/ecr_models/ecr.py,sha256=oAkQ-SDS3Mjrn291dh9qF5LaRYGFJnmuNY28UyrzIfg,7293
|
|
349
|
-
regscale/models/integration_models/flat_file_importer/__init__.py,sha256=
|
|
352
|
+
regscale/models/integration_models/flat_file_importer/__init__.py,sha256=HYO7mrqnBaXKyo7dBNGnVqYY7m_1OjTadJKfg4f_ae4,40595
|
|
350
353
|
regscale/models/integration_models/sbom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
351
354
|
regscale/models/integration_models/sbom/cyclone_dx.py,sha256=0pFR0BWBrF5c8_cC_8mj2MXvNOMHOdHbBYXvTVfFAh8,4058
|
|
352
355
|
regscale/models/integration_models/synqly_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
353
356
|
regscale/models/integration_models/synqly_models/capabilities.json,sha256=mjnI5C29qmT7rr1wkdebvo0-5w10msVtLYvl3bODvUY,394787
|
|
354
357
|
regscale/models/integration_models/synqly_models/connector_types.py,sha256=8nxptkTexpskySnmL0obNAff_iu_fx6tJ7i1-4hJvao,461
|
|
355
|
-
regscale/models/integration_models/synqly_models/ocsf_mapper.py,sha256=
|
|
358
|
+
regscale/models/integration_models/synqly_models/ocsf_mapper.py,sha256=ftObPhGg9CamnwRZ5z6qi8pW2Gu4JYy8apEo33o7q00,16960
|
|
356
359
|
regscale/models/integration_models/synqly_models/param.py,sha256=Xt5Zm6lC_VkLj7LF2qXo72TJZHysqttsp5ai0NCf1po,2643
|
|
357
360
|
regscale/models/integration_models/synqly_models/synqly_model.py,sha256=9wgR0mNTuteMarnMj3iAIj8Ki9-8rc-pIWZpku4hH_k,34701
|
|
358
361
|
regscale/models/integration_models/synqly_models/tenants.py,sha256=kewIZw-iv18bNXJGG3ghwuFJ4CK5iXQhn_x2-xvV0iM,1078
|
|
@@ -360,7 +363,7 @@ regscale/models/integration_models/synqly_models/connectors/__init__.py,sha256=J
|
|
|
360
363
|
regscale/models/integration_models/synqly_models/connectors/assets.py,sha256=HHNIAVh5pRuJe8sStqhFEc6VnX2wT0FcY5178nbQgkQ,3705
|
|
361
364
|
regscale/models/integration_models/synqly_models/connectors/edr.py,sha256=kio3uoEYubCHretpDOJqxdwmzid1IzbVYz0BF64zeL0,5547
|
|
362
365
|
regscale/models/integration_models/synqly_models/connectors/ticketing.py,sha256=yRBuCkRAVfa_C91r3WqJ9gxrQsoD0qV9cY48YXpJl70,25358
|
|
363
|
-
regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py,sha256=
|
|
366
|
+
regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py,sha256=NzsaaBuuL8mCxOgUGhA7eqvrc398l_3cJSJgv0WVF4s,7180
|
|
364
367
|
regscale/models/integration_models/tenable_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
365
368
|
regscale/models/integration_models/tenable_models/integration.py,sha256=lplL8zmjTFuhLreW-4y7G1fiCOBgzNAaATq800jgTQc,10271
|
|
366
369
|
regscale/models/integration_models/tenable_models/models.py,sha256=dmG7btkN4YkDWwnfW5Ldc3tWEAGjPiaRgJjrqMOkPEU,15846
|
|
@@ -409,7 +412,7 @@ regscale/models/regscale_models/incident.py,sha256=jsS4MfigzjwFphvdIrBk62GfvbceQ
|
|
|
409
412
|
regscale/models/regscale_models/inheritance.py,sha256=n8CtDQZ8WPQ-AwC0kq5D0nMwK1_njfB-rUN5PdjiMOs,1314
|
|
410
413
|
regscale/models/regscale_models/inherited_control.py,sha256=RuQJgVyZgfoIrUG_vvwQYHECb3wsFjDH-zPj-bIFBNU,2007
|
|
411
414
|
regscale/models/regscale_models/interconnection.py,sha256=8Q9CGeHEX9TXQrim_NIAj9KuM4MwaUTpBLs_LKaXAlw,1256
|
|
412
|
-
regscale/models/regscale_models/issue.py,sha256=
|
|
415
|
+
regscale/models/regscale_models/issue.py,sha256=pPrCTDy9y9ZTYMtOCl9J2U12NrWn09XhFjF1A5cUgdw,59381
|
|
413
416
|
regscale/models/regscale_models/leveraged_authorization.py,sha256=OUrL8JQV3r7T3ldHlL6Y_ZLv6KuQIC-3eZW5wZ7XFUk,4192
|
|
414
417
|
regscale/models/regscale_models/line_of_inquiry.py,sha256=Uu0lQEhif0W6yTSkJo27GyQGmExSngJvyqGBTr4Q8Fg,1713
|
|
415
418
|
regscale/models/regscale_models/link.py,sha256=lAY4Ig3Menm1EqfcAbVJ7jsCsRO5tWtJIf-9-G9FXT8,6593
|
|
@@ -457,7 +460,7 @@ regscale/models/regscale_models/team.py,sha256=MfJvSg6E77FF5dkIlGJs-2XnHMZLMYS3e
|
|
|
457
460
|
regscale/models/regscale_models/threat.py,sha256=4TNZcRnTgmlDwBsYu5Pbh9GRd8ZWAtqqr0Xph3uPNAA,7255
|
|
458
461
|
regscale/models/regscale_models/user.py,sha256=wiU2qKwp3aYtmaHEmTtv8BbMEgFb913dHgc2VnmsAkg,7186
|
|
459
462
|
regscale/models/regscale_models/user_group.py,sha256=vzlXHvPNsgJd38H0R3osi46Oj19QO5oPx0qXntQBKWI,1891
|
|
460
|
-
regscale/models/regscale_models/vulnerability.py,sha256=
|
|
463
|
+
regscale/models/regscale_models/vulnerability.py,sha256=OxHGwq2REY5CCilis-TRgvVGYUyJs_BWNgP0bKOtyN0,11080
|
|
461
464
|
regscale/models/regscale_models/vulnerability_mapping.py,sha256=k14azHU7VwryHfXaJdvAMWXs3AqHDr7rnj602bscWQM,6260
|
|
462
465
|
regscale/models/regscale_models/workflow.py,sha256=uMNVVAn5qR8wxjMP5PHbcvMmvPRe1gn1oclVUpbv52s,1873
|
|
463
466
|
regscale/models/regscale_models/workflow_action.py,sha256=zMHrvUkTQJlkCj6Xx6wadozBwsVPpObj5GD81LI2VZc,925
|
|
@@ -533,9 +536,9 @@ tests/regscale/models/test_regscale_model.py,sha256=ZsrEZkC4EtdIsoQuayn1xv2gEGcV
|
|
|
533
536
|
tests/regscale/models/test_report.py,sha256=IqUq7C__a1_q_mLaz0PE9Lq6fHggBsB14-AzEYNBxLw,4666
|
|
534
537
|
tests/regscale/models/test_tenable_integrations.py,sha256=y1qaW77H094VSGHjZdlvF66UCt-nPEib9Mv3cdwbM94,32435
|
|
535
538
|
tests/regscale/models/test_user_model.py,sha256=e9olv28qBApgnvK6hFHOgXjUC-pkaV8aGDirEIWASL4,4427
|
|
536
|
-
regscale_cli-6.
|
|
537
|
-
regscale_cli-6.
|
|
538
|
-
regscale_cli-6.
|
|
539
|
-
regscale_cli-6.
|
|
540
|
-
regscale_cli-6.
|
|
541
|
-
regscale_cli-6.
|
|
539
|
+
regscale_cli-6.23.0.0.dist-info/LICENSE,sha256=ytNhYQ9Rmhj_m-EX2pPq9Ld6tH5wrqqDYg-fCf46WDU,1076
|
|
540
|
+
regscale_cli-6.23.0.0.dist-info/METADATA,sha256=cjr3qeaYzjy47S7c4z4l7daXTpF92UldmmYpIJb83F8,35027
|
|
541
|
+
regscale_cli-6.23.0.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
542
|
+
regscale_cli-6.23.0.0.dist-info/entry_points.txt,sha256=cLOaIP1eRv1yZ2u7BvpE3aB4x3kDrDwkpeisKOu33z8,269
|
|
543
|
+
regscale_cli-6.23.0.0.dist-info/top_level.txt,sha256=Uv8VUCAdxRm70bgrD4YNEJUmDhBThad_1aaEFGwRByc,15
|
|
544
|
+
regscale_cli-6.23.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|