regscale-cli 6.19.1.0__py3-none-any.whl → 6.20.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/airflow/config.py +2 -0
- regscale/airflow/tasks/groups.py +11 -47
- regscale/core/app/internal/login.py +49 -43
- regscale/core/app/internal/model_editor.py +2 -1
- regscale/dev/code_gen.py +2 -5
- regscale/integrations/commercial/amazon/common.py +5 -4
- regscale/integrations/commercial/aws/scanner.py +3 -2
- regscale/integrations/commercial/synqly/assets.py +20 -0
- regscale/integrations/commercial/synqly/ticketing.py +25 -0
- regscale/integrations/commercial/wizv2/click.py +3 -3
- regscale/integrations/public/fedramp/appendix_parser.py +499 -104
- regscale/integrations/public/fedramp/fedramp_five.py +89 -43
- regscale/integrations/scanner_integration.py +1 -1
- regscale/models/app_models/import_validater.py +2 -0
- regscale/models/integration_models/cisa_kev_data.json +355 -27
- regscale/models/integration_models/flat_file_importer/__init__.py +26 -9
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/regscale_models/__init__.py +5 -0
- regscale/models/regscale_models/business_impact_assessment.py +71 -0
- regscale/models/regscale_models/control_implementation.py +15 -0
- regscale/models/regscale_models/master_assessment.py +19 -0
- regscale/models/regscale_models/policy.py +90 -0
- regscale/models/regscale_models/question.py +30 -2
- regscale/models/regscale_models/questionnaire.py +4 -3
- regscale/models/regscale_models/questionnaire_instance.py +37 -14
- regscale/models/regscale_models/rbac.py +0 -1
- regscale/models/regscale_models/regscale_model.py +16 -15
- regscale/models/regscale_models/risk_trend.py +67 -0
- regscale/utils/graphql_client.py +2 -1
- {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/METADATA +130 -71
- {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/RECORD +36 -33
- {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/top_level.txt +0 -0
|
@@ -11,7 +11,6 @@ from tempfile import gettempdir
|
|
|
11
11
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
12
12
|
|
|
13
13
|
from dateutil.relativedelta import relativedelta
|
|
14
|
-
from packaging.version import Version
|
|
15
14
|
|
|
16
15
|
from regscale.core.app.api import Api
|
|
17
16
|
from regscale.core.app.application import Application
|
|
@@ -28,7 +27,6 @@ from regscale.models import (
|
|
|
28
27
|
ControlParameter,
|
|
29
28
|
File,
|
|
30
29
|
ImplementationObjective,
|
|
31
|
-
ImplementationObjectiveResponsibility,
|
|
32
30
|
ImplementationOption,
|
|
33
31
|
LeveragedAuthorization,
|
|
34
32
|
Parameter,
|
|
@@ -40,6 +38,7 @@ from regscale.models import (
|
|
|
40
38
|
StakeHolder,
|
|
41
39
|
SystemRole,
|
|
42
40
|
User,
|
|
41
|
+
ImplementationControlOrigin,
|
|
43
42
|
)
|
|
44
43
|
from regscale.utils.version import RegscaleVersion
|
|
45
44
|
|
|
@@ -1400,8 +1399,7 @@ def handle_parts(
|
|
|
1400
1399
|
else control_objectives
|
|
1401
1400
|
)
|
|
1402
1401
|
logger.debug(f"Matching Objectives: {matching_objectives}")
|
|
1403
|
-
|
|
1404
|
-
if len(regscale_version) >= 10 or Version(regscale_version) >= Version("6.13.0.0"):
|
|
1402
|
+
if RegscaleVersion.meets_minimum_version("6.13.0.0"):
|
|
1405
1403
|
status = status_map.get(status, status)
|
|
1406
1404
|
|
|
1407
1405
|
# Status should never be None
|
|
@@ -1510,44 +1508,33 @@ def map_responsibility(responsibility: str) -> str:
|
|
|
1510
1508
|
:return: The mapped responsibility.
|
|
1511
1509
|
:rtype: str
|
|
1512
1510
|
"""
|
|
1513
|
-
|
|
1511
|
+
if not responsibility:
|
|
1512
|
+
return "" # Return empty string instead of None
|
|
1513
|
+
|
|
1514
|
+
# Handle comma-separated values
|
|
1515
|
+
if "," in responsibility:
|
|
1516
|
+
responsibility_values = [r.strip() for r in responsibility.split(",")]
|
|
1517
|
+
return ",".join([map_responsibility(r) for r in responsibility_values])
|
|
1518
|
+
|
|
1519
|
+
# This should be server code with proper enums, but this is the best we can do for now
|
|
1514
1520
|
responsibility_map = {
|
|
1515
|
-
"
|
|
1516
|
-
"Provider
|
|
1517
|
-
"
|
|
1518
|
-
"
|
|
1519
|
-
"
|
|
1520
|
-
"Shared
|
|
1521
|
-
"Inherited
|
|
1521
|
+
"Service Provider Corporate": ImplementationControlOrigin.SERVICE_PROVIDER_CORPORATE.value,
|
|
1522
|
+
"Service Provider System Specific": ImplementationControlOrigin.SERVICE_PROVIDER_SYSTEM.value,
|
|
1523
|
+
"Service Provider Hybrid (Corporate and System Specific)": ImplementationControlOrigin.SERVICE_PROVIDER_HYBRID.value, # Map to closest value
|
|
1524
|
+
"Configured by Customer (Customer System Specific)": ImplementationControlOrigin.CONFIGURED_BY_CUSTOMER.value,
|
|
1525
|
+
"Provided by Customer (Customer System Specific)": ImplementationControlOrigin.PROVIDED_BY_CUSTOMER.value,
|
|
1526
|
+
"Shared (Service Provider and Customer Responsibility)": ImplementationControlOrigin.SHARED.value,
|
|
1527
|
+
"Inherited from pre-existing FedRAMP Authorization": ImplementationControlOrigin.INHERITED_FROM_PRE_EXISTING_FEDRAMP_AUTHORIZATION.value,
|
|
1522
1528
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
res = ImplementationObjectiveResponsibility.PROVIDER_SYSTEM_SPECIFIC.value
|
|
1526
|
-
if responsibility == SERVICE_PROVIDER_CORPORATE:
|
|
1527
|
-
res = ImplementationObjectiveResponsibility.PROVIDER.value
|
|
1528
|
-
if responsibility == "Provided by Customer (Customer System Specific)":
|
|
1529
|
-
res = ImplementationObjectiveResponsibility.CUSTOMER.value
|
|
1530
|
-
if responsibility == "Configured by Customer (Customer System Specific)":
|
|
1531
|
-
res = ImplementationObjectiveResponsibility.CUSTOMER_CONFIGURED.value
|
|
1532
|
-
if responsibility == "Service Provider Hybrid (Corporate and System Specific)":
|
|
1533
|
-
res = ImplementationObjectiveResponsibility.HYBRID.value
|
|
1534
|
-
if responsibility == "Inherited from pre-existing FedRAMP Authorization":
|
|
1535
|
-
res = ImplementationObjectiveResponsibility.INHERITED.value
|
|
1536
|
-
if responsibility == ImplementationObjectiveResponsibility.NOT_APPLICABLE.value:
|
|
1537
|
-
res = ImplementationObjectiveResponsibility.NOT_APPLICABLE.value
|
|
1538
|
-
if responsibility == "Shared (Service Provider and Customer Responsibility)":
|
|
1539
|
-
res = ImplementationObjectiveResponsibility.SHARED.value
|
|
1540
|
-
regscale_version = RegscaleVersion.get_platform_version()
|
|
1541
|
-
if len(regscale_version) >= 10 or Version(regscale_version) >= Version("6.13.0.0"):
|
|
1542
|
-
return responsibility_map.get(res, res)
|
|
1543
|
-
return res
|
|
1529
|
+
|
|
1530
|
+
return responsibility_map.get(responsibility, responsibility or "")
|
|
1544
1531
|
|
|
1545
1532
|
|
|
1546
1533
|
def handle_implementation_objectives(
|
|
1547
1534
|
objective: ControlObjective,
|
|
1548
1535
|
part_statement: str,
|
|
1549
1536
|
status: Optional[str],
|
|
1550
|
-
control_implementation: ControlImplementation,
|
|
1537
|
+
control_implementation: Union[ControlImplementation, int, None],
|
|
1551
1538
|
imp_objectives: List[ImplementationObjective],
|
|
1552
1539
|
control: SecurityControl,
|
|
1553
1540
|
duplicate: bool,
|
|
@@ -1555,26 +1542,30 @@ def handle_implementation_objectives(
|
|
|
1555
1542
|
):
|
|
1556
1543
|
"""
|
|
1557
1544
|
Handle the implementation objectives for the given objective, option, and control implementation.
|
|
1558
|
-
:param ControlObjective objective:
|
|
1559
|
-
:param str part_statement:
|
|
1560
|
-
:param Optional[str] status:
|
|
1561
|
-
:param ControlImplementation control_implementation:
|
|
1562
|
-
:param List[ImplementationObjective] imp_objectives:
|
|
1563
|
-
:param SecurityControl control:
|
|
1545
|
+
:param ControlObjective objective: The control objective.
|
|
1546
|
+
:param str part_statement: The statement text for this part.
|
|
1547
|
+
:param Optional[str] status: The implementation status.
|
|
1548
|
+
:param Union[ControlImplementation, int, None] control_implementation: The control implementation object or ID.
|
|
1549
|
+
:param List[ImplementationObjective] imp_objectives: List to collect implementation objectives.
|
|
1550
|
+
:param SecurityControl control: The security control.
|
|
1564
1551
|
:param bool duplicate: Whether the option is a duplicate will add note if True.
|
|
1565
1552
|
:param Optional[str] origination: The origination of the implementation.
|
|
1566
1553
|
"""
|
|
1567
1554
|
if isinstance(status, ControlImplementationStatus):
|
|
1568
1555
|
status = status.value
|
|
1556
|
+
|
|
1557
|
+
# Ensure part_statement is valid
|
|
1558
|
+
statement = part_statement if part_statement else ""
|
|
1559
|
+
|
|
1569
1560
|
imp_obj = ImplementationObjective(
|
|
1570
1561
|
securityControlId=control.id,
|
|
1571
|
-
implementationId=control_implementation.id,
|
|
1562
|
+
implementationId=control_implementation.id if hasattr(control_implementation, "id") else control_implementation,
|
|
1572
1563
|
objectiveId=objective.id,
|
|
1573
1564
|
optionId=None,
|
|
1574
1565
|
status=status,
|
|
1575
|
-
statement=
|
|
1566
|
+
statement=statement,
|
|
1576
1567
|
notes="#replicated-data-part" if duplicate else "",
|
|
1577
|
-
responsibility=origination
|
|
1568
|
+
responsibility=origination,
|
|
1578
1569
|
)
|
|
1579
1570
|
if imp_obj not in imp_objectives:
|
|
1580
1571
|
imp_objectives.append(imp_obj)
|
|
@@ -2341,3 +2332,58 @@ def get_max_version(entries: List[Dict]) -> Optional[str]:
|
|
|
2341
2332
|
max_version = max(max_version, version_str, key=parse_version)
|
|
2342
2333
|
logger.debug(f"Version: {max_version}")
|
|
2343
2334
|
return max_version
|
|
2335
|
+
|
|
2336
|
+
|
|
2337
|
+
def process_objective(
|
|
2338
|
+
objective: ControlObjective,
|
|
2339
|
+
processed_objective_ids: set,
|
|
2340
|
+
existing_objectives_by_objective_id: Dict,
|
|
2341
|
+
control: SecurityControl,
|
|
2342
|
+
part_statement: Optional[str],
|
|
2343
|
+
status: Optional[str],
|
|
2344
|
+
origination: Optional[str] = None,
|
|
2345
|
+
imp_objectives: List[ImplementationObjective] = None,
|
|
2346
|
+
):
|
|
2347
|
+
"""
|
|
2348
|
+
Process a single control objective.
|
|
2349
|
+
|
|
2350
|
+
:param ControlObjective objective: The objective to process.
|
|
2351
|
+
:param set processed_objective_ids: Set of already processed objective IDs.
|
|
2352
|
+
:param Dict existing_objectives_by_objective_id: Dictionary of existing objectives by ID.
|
|
2353
|
+
:param SecurityControl control: The security control.
|
|
2354
|
+
:param Optional[str] part_statement: The statement for this part, may be None.
|
|
2355
|
+
:param Optional[str] status: The implementation status for this objective.
|
|
2356
|
+
:param Optional[str] origination: The implementation origination for this objective.
|
|
2357
|
+
:param List[ImplementationObjective] imp_objectives: List to collect implementation objectives.
|
|
2358
|
+
:return: None
|
|
2359
|
+
"""
|
|
2360
|
+
logger.debug(f"Processing objective: {objective.id} - {objective.name}")
|
|
2361
|
+
|
|
2362
|
+
# Skip if already processed
|
|
2363
|
+
if objective.id in processed_objective_ids:
|
|
2364
|
+
logger.debug(f"Objective {objective.id} already processed")
|
|
2365
|
+
return
|
|
2366
|
+
|
|
2367
|
+
processed_objective_ids.add(objective.id)
|
|
2368
|
+
existing_objective = existing_objectives_by_objective_id.get(objective.id)
|
|
2369
|
+
|
|
2370
|
+
statement = part_statement if part_statement is not None else ""
|
|
2371
|
+
|
|
2372
|
+
# Update existing objective if found
|
|
2373
|
+
if existing_objective is not None:
|
|
2374
|
+
logger.debug(f"Updating existing objective: {existing_objective.id}")
|
|
2375
|
+
existing_objective.status = status
|
|
2376
|
+
existing_objective.statement = statement
|
|
2377
|
+
if origination is not None:
|
|
2378
|
+
existing_objective.responsibility = origination
|
|
2379
|
+
existing_objective.save()
|
|
2380
|
+
# Create new objective if implementation objectives list provided
|
|
2381
|
+
elif imp_objectives is not None:
|
|
2382
|
+
logger.debug(f"Creating new objective for {objective.id}")
|
|
2383
|
+
imp_obj = ImplementationObjective(
|
|
2384
|
+
objectiveId=objective.id,
|
|
2385
|
+
status=status,
|
|
2386
|
+
statement=statement,
|
|
2387
|
+
responsibility=origination,
|
|
2388
|
+
)
|
|
2389
|
+
imp_objectives.append(imp_obj)
|
|
@@ -2259,7 +2259,7 @@ class ScannerIntegration(ABC):
|
|
|
2259
2259
|
self.handle_passing_checklist(finding=finding, plan_id=self.plan_id)
|
|
2260
2260
|
|
|
2261
2261
|
# Process vulnerability if applicable
|
|
2262
|
-
if finding.status != regscale_models.IssueStatus.Closed:
|
|
2262
|
+
if finding.status != regscale_models.IssueStatus.Closed or ScannerVariables.ingestClosedIssues:
|
|
2263
2263
|
if asset := self.get_asset_by_identifier(finding.asset_identifier):
|
|
2264
2264
|
if vulnerability_id := self.handle_vulnerability(finding, asset, scan_history):
|
|
2265
2265
|
current_vulnerabilities[asset.id].add(vulnerability_id)
|
|
@@ -183,6 +183,8 @@ class ImportValidater:
|
|
|
183
183
|
df = pandas.read_csv(file_path, skiprows=self.skip_rows - 1, on_bad_lines="warn")
|
|
184
184
|
else:
|
|
185
185
|
df = pandas.read_csv(file_path, on_bad_lines="warn")
|
|
186
|
+
if self.ignore_unnamed:
|
|
187
|
+
df = df.loc[:, ~df.columns.str.contains("^Unnamed")]
|
|
186
188
|
except pandas.errors.ParserError:
|
|
187
189
|
raise ValidationException(f"Unable to parse the {CSV} file: {file_path}")
|
|
188
190
|
self.validate_headers(df.columns)
|