regscale-cli 6.26.0.0__py3-none-any.whl → 6.27.0.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/_version.py +1 -1
- regscale/core/app/application.py +1 -1
- regscale/core/app/internal/evidence.py +419 -2
- regscale/dev/code_gen.py +24 -20
- regscale/integrations/commercial/__init__.py +0 -1
- regscale/integrations/commercial/jira.py +367 -126
- regscale/integrations/commercial/qualys/__init__.py +7 -8
- regscale/integrations/commercial/qualys/scanner.py +8 -3
- regscale/integrations/commercial/synqly/assets.py +17 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +45 -28
- regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
- regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
- regscale/integrations/commercial/tenablev2/commands.py +142 -1
- regscale/integrations/commercial/tenablev2/scanner.py +0 -1
- regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
- regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +44 -59
- regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
- regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
- regscale/integrations/commercial/wizv2/compliance_report.py +10 -9
- regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
- regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +3 -3
- regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +1 -17
- regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
- regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +5 -9
- regscale/integrations/commercial/wizv2/issue.py +1 -1
- regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
- regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
- regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
- regscale/integrations/commercial/wizv2/reports.py +1 -1
- regscale/integrations/commercial/wizv2/sbom.py +1 -1
- regscale/integrations/commercial/wizv2/scanner.py +40 -100
- regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
- regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
- regscale/integrations/commercial/wizv2/variables.py +89 -3
- regscale/integrations/compliance_integration.py +0 -46
- regscale/integrations/control_matcher.py +22 -3
- regscale/integrations/due_date_handler.py +14 -8
- regscale/integrations/public/fedramp/docx_parser.py +10 -1
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +393 -340
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/scanner_integration.py +127 -57
- regscale/models/integration_models/cisa_kev_data.json +132 -9
- regscale/models/integration_models/qualys.py +3 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +24 -7
- regscale/models/integration_models/synqly_models/synqly_model.py +8 -1
- regscale/models/regscale_models/control_implementation.py +1 -1
- regscale/models/regscale_models/issue.py +0 -1
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/METADATA +1 -17
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/RECORD +94 -61
- tests/regscale/integrations/commercial/test_jira.py +481 -91
- tests/regscale/integrations/commercial/test_wiz.py +96 -200
- tests/regscale/integrations/commercial/wizv2/__init__.py +1 -1
- tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
- tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
- tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
- tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
- tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
- tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
- tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
- tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
- tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
- tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +1 -1
- tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
- tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
- tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
- tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +1 -1
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +72 -29
- tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +946 -78
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +97 -202
- tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
- tests/regscale/integrations/public/test_fedramp.py +301 -0
- tests/regscale/integrations/test_control_matcher.py +83 -0
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3543
- tests/regscale/integrations/commercial/wizv2/test_wiz_policy_compliance.py +0 -750
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/LICENSE +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/WHEEL +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.26.0.0.dist-info → regscale_cli-6.27.0.1.dist-info}/top_level.txt +0 -0
|
@@ -49,6 +49,7 @@ class ControlMatcher:
|
|
|
49
49
|
Handles various formats:
|
|
50
50
|
- NIST format: AC-1, AC-1(1), AC-1.1
|
|
51
51
|
- With leading zeros: AC-01, AC-17(02)
|
|
52
|
+
- With spaces: AC-1 (1), AC-02 (04)
|
|
52
53
|
- With text: "Access Control AC-1"
|
|
53
54
|
- Multiple controls: "AC-1, AC-2"
|
|
54
55
|
|
|
@@ -63,14 +64,32 @@ class ControlMatcher:
|
|
|
63
64
|
control_string = control_string.strip().upper()
|
|
64
65
|
|
|
65
66
|
# Common NIST control ID pattern
|
|
66
|
-
# Matches: AC-1, AC-01, AC-1(1), AC-1(01), AC-1.1, AC-1.01, etc.
|
|
67
|
-
|
|
67
|
+
# Matches: AC-1, AC-01, AC-1(1), AC-1(01), AC-1 (1), AC-1.1, AC-1.01, etc.
|
|
68
|
+
# Allows optional whitespace before and inside parentheses
|
|
69
|
+
pattern = r"([A-Z]{2,3}-\d+(?:\s*\(\s*\d+\s*\)|\.\d+)?)"
|
|
68
70
|
|
|
69
71
|
matches = re.findall(pattern, control_string)
|
|
70
72
|
if matches:
|
|
71
|
-
# Normalize parentheses to dots for consistency
|
|
73
|
+
# Normalize parentheses to dots for consistency and remove spaces
|
|
72
74
|
control_id = matches[0]
|
|
75
|
+
control_id = control_id.replace(" ", "") # Remove all spaces
|
|
73
76
|
control_id = control_id.replace("(", ".").replace(")", "")
|
|
77
|
+
|
|
78
|
+
# Normalize leading zeros (e.g., AC-01.02 -> AC-1.2)
|
|
79
|
+
parts = control_id.split("-")
|
|
80
|
+
if len(parts) == 2:
|
|
81
|
+
family = parts[0]
|
|
82
|
+
number_part = parts[1]
|
|
83
|
+
|
|
84
|
+
if "." in number_part:
|
|
85
|
+
main_num, enhancement = number_part.split(".", 1)
|
|
86
|
+
main_num = str(int(main_num))
|
|
87
|
+
enhancement = str(int(enhancement))
|
|
88
|
+
control_id = f"{family}-{main_num}.{enhancement}"
|
|
89
|
+
else:
|
|
90
|
+
main_num = str(int(number_part))
|
|
91
|
+
control_id = f"{family}-{main_num}"
|
|
92
|
+
|
|
74
93
|
return control_id
|
|
75
94
|
|
|
76
95
|
return None
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from typing import Any, Dict, Optional
|
|
7
|
+
from typing import Any, Dict, Optional, Union
|
|
8
8
|
|
|
9
9
|
from regscale.core.app.application import Application
|
|
10
10
|
from regscale.core.utils.date import get_day_increment
|
|
@@ -53,9 +53,13 @@ class DueDateHandler:
|
|
|
53
53
|
# Default due date timelines (days)
|
|
54
54
|
self.default_timelines = {
|
|
55
55
|
regscale_models.IssueSeverity.Critical: 30,
|
|
56
|
+
"critical": 30,
|
|
56
57
|
regscale_models.IssueSeverity.High: 60,
|
|
58
|
+
"high": 60,
|
|
57
59
|
regscale_models.IssueSeverity.Moderate: 120,
|
|
60
|
+
"moderate": 120,
|
|
58
61
|
regscale_models.IssueSeverity.Low: 364,
|
|
62
|
+
"low": 364,
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
# Load integration-specific timelines from config
|
|
@@ -66,10 +70,10 @@ class DueDateHandler:
|
|
|
66
70
|
|
|
67
71
|
def _load_integration_timelines(self) -> Dict[regscale_models.IssueSeverity, int]:
|
|
68
72
|
"""
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
Load timeline configurations for this integration from init.yaml
|
|
74
|
+
mv
|
|
75
|
+
:return: Dictionary mapping severity to days
|
|
76
|
+
:rtype: Dict[regscale_models.IssueSeverity, int]
|
|
73
77
|
"""
|
|
74
78
|
timelines = self.default_timelines.copy()
|
|
75
79
|
|
|
@@ -184,7 +188,7 @@ class DueDateHandler:
|
|
|
184
188
|
|
|
185
189
|
def calculate_due_date(
|
|
186
190
|
self,
|
|
187
|
-
severity: regscale_models.IssueSeverity,
|
|
191
|
+
severity: Union[regscale_models.IssueSeverity, str],
|
|
188
192
|
created_date: str,
|
|
189
193
|
cve: Optional[str] = None,
|
|
190
194
|
title: Optional[str] = None,
|
|
@@ -192,7 +196,7 @@ class DueDateHandler:
|
|
|
192
196
|
"""
|
|
193
197
|
Calculate the due date for an issue based on severity, KEV status, and integration config
|
|
194
198
|
|
|
195
|
-
:param regscale_models.IssueSeverity severity: The severity of the issue
|
|
199
|
+
:param Union[regscale_models.IssueSeverity, str] severity: The severity of the issue
|
|
196
200
|
:param str created_date: The creation date of the issue
|
|
197
201
|
:param Optional[str] cve: The CVE identifier (if applicable)
|
|
198
202
|
:param Optional[str] title: The title of the issue (for additional context)
|
|
@@ -244,7 +248,9 @@ class DueDateHandler:
|
|
|
244
248
|
# Ensure due date is never in the past (allow yesterday for timezone differences)
|
|
245
249
|
due_date = self._ensure_future_due_date(calculated_due_date, days)
|
|
246
250
|
|
|
247
|
-
logger.debug(
|
|
251
|
+
logger.debug(
|
|
252
|
+
f"Using {self.integration_name} timeline: {severity.name if isinstance(severity, regscale_models.IssueSeverity) else severity} = {days} days, due date = {due_date}"
|
|
253
|
+
)
|
|
248
254
|
|
|
249
255
|
return due_date
|
|
250
256
|
|
|
@@ -246,7 +246,16 @@ class SSPDocParser:
|
|
|
246
246
|
headers = self.extract_table_headers(table, namespaces)
|
|
247
247
|
table_data = []
|
|
248
248
|
tables_dicts_list["preceding_text"] = preceding_text[i] if i < len(preceding_text) else ""
|
|
249
|
-
|
|
249
|
+
# Check if this is a vertical table:
|
|
250
|
+
is_vertical = False
|
|
251
|
+
# - Single header that matches vertical_tables list
|
|
252
|
+
first_option = len(headers) == 1 and headers[0].lower() in vertical_tables
|
|
253
|
+
# - OR two headers where first matches and second is empty/whitespace
|
|
254
|
+
second_option = len(headers) == 2 and headers[0].lower() in vertical_tables and not headers[1].strip()
|
|
255
|
+
if first_option or second_option:
|
|
256
|
+
is_vertical = True
|
|
257
|
+
|
|
258
|
+
if is_vertical:
|
|
250
259
|
table_data = self.extract_vertical_row_data(table, namespaces)
|
|
251
260
|
tables_dicts_list["table_data"] = table_data
|
|
252
261
|
# tables_dicts_list.append({headers[0].lower(): table_data})
|