regscale-cli 6.21.0.0__py3-none-any.whl → 6.21.1.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/integrations/commercial/__init__.py +1 -2
- regscale/integrations/commercial/amazon/common.py +79 -2
- regscale/integrations/commercial/aws/cli.py +183 -9
- regscale/integrations/commercial/aws/scanner.py +544 -9
- regscale/integrations/commercial/cpe.py +18 -1
- regscale/integrations/commercial/tenablev2/jsonl_scanner.py +2 -1
- regscale/integrations/commercial/wizv2/async_client.py +10 -3
- regscale/integrations/commercial/wizv2/click.py +102 -26
- regscale/integrations/commercial/wizv2/constants.py +249 -1
- regscale/integrations/commercial/wizv2/issue.py +2 -2
- regscale/integrations/commercial/wizv2/parsers.py +3 -2
- regscale/integrations/commercial/wizv2/policy_compliance.py +1858 -0
- regscale/integrations/commercial/wizv2/scanner.py +15 -21
- regscale/integrations/commercial/wizv2/utils.py +258 -85
- regscale/integrations/commercial/wizv2/variables.py +4 -3
- regscale/integrations/compliance_integration.py +1455 -0
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/public/fedramp/markdown_parser.py +7 -1
- regscale/integrations/scanner_integration.py +30 -2
- regscale/models/app_models/__init__.py +1 -0
- regscale/models/integration_models/cisa_kev_data.json +73 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/{integrations/commercial/wizv2/models.py → models/integration_models/wizv2.py} +4 -12
- regscale/models/regscale_models/file.py +4 -0
- regscale/models/regscale_models/issue.py +123 -0
- regscale/models/regscale_models/regscale_model.py +4 -2
- regscale/models/regscale_models/security_plan.py +1 -1
- regscale/utils/graphql_client.py +3 -1
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/METADATA +9 -9
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/RECORD +37 -34
- tests/regscale/core/test_version_regscale.py +5 -3
- tests/regscale/integrations/test_wiz_policy_compliance_affected_controls.py +154 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Test affected controls functionality in Wiz Policy Compliance Integration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
from unittest.mock import patch, MagicMock
|
|
9
|
+
|
|
10
|
+
from regscale.integrations.commercial.wizv2.policy_compliance import WizPolicyComplianceIntegration
|
|
11
|
+
from regscale.integrations.compliance_integration import ComplianceItem
|
|
12
|
+
from regscale.models import regscale_models
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DummyItem(ComplianceItem):
|
|
16
|
+
"""Dummy compliance item for testing."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, rid: str, rname: str, cid: str, framework: str, result: str):
|
|
19
|
+
self._rid = rid
|
|
20
|
+
self._rname = rname
|
|
21
|
+
self._cid = cid
|
|
22
|
+
self._framework = framework
|
|
23
|
+
self._result = result
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def resource_id(self) -> str:
|
|
27
|
+
"""Get resource ID."""
|
|
28
|
+
return self._rid
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def resource_name(self) -> str:
|
|
32
|
+
"""Get resource name."""
|
|
33
|
+
return self._rname
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def control_id(self) -> str:
|
|
37
|
+
"""Get control ID."""
|
|
38
|
+
return self._cid
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def compliance_result(self) -> str:
|
|
42
|
+
"""Get compliance result."""
|
|
43
|
+
return self._result
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def severity(self):
|
|
47
|
+
"""Get severity."""
|
|
48
|
+
return "HIGH"
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def description(self) -> str:
|
|
52
|
+
"""Get description."""
|
|
53
|
+
return "desc"
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def framework(self) -> str:
|
|
57
|
+
"""Get framework."""
|
|
58
|
+
return self._framework
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@pytest.mark.parametrize("control_id", ["AC-2(1)", "ac-2 (1)", "AC-2-1"])
|
|
62
|
+
@patch("regscale.integrations.commercial.wizv2.policy_compliance.wiz_authenticate")
|
|
63
|
+
@patch("regscale.integrations.commercial.wizv2.policy_compliance.check_license")
|
|
64
|
+
def test_issue_affected_controls_from_external_id(mock_check_license, mock_wiz_auth, monkeypatch, control_id):
|
|
65
|
+
"""Test that affected controls are properly set from normalized control IDs."""
|
|
66
|
+
# Mock authentication to prevent 401 errors - using same pattern as main test file
|
|
67
|
+
mock_app = MagicMock()
|
|
68
|
+
mock_app.config = {"wizUrl": "https://api.wiz.io/graphql"}
|
|
69
|
+
mock_check_license.return_value = mock_app
|
|
70
|
+
mock_wiz_auth.return_value = "test-token"
|
|
71
|
+
|
|
72
|
+
# Mock the base class methods that make API calls
|
|
73
|
+
with patch.object(WizPolicyComplianceIntegration, "_load_existing_records_cache"), patch.object(
|
|
74
|
+
WizPolicyComplianceIntegration, "get_asset_by_identifier", return_value=None
|
|
75
|
+
), patch.object(WizPolicyComplianceIntegration, "_ensure_asset_for_finding", return_value=None):
|
|
76
|
+
|
|
77
|
+
integ = WizPolicyComplianceIntegration(
|
|
78
|
+
plan_id=999,
|
|
79
|
+
wiz_project_id="proj",
|
|
80
|
+
client_id="cid",
|
|
81
|
+
client_secret="secret",
|
|
82
|
+
framework_id="wf-id-4",
|
|
83
|
+
)
|
|
84
|
+
integ.parent_module = regscale_models.SecurityPlan.get_module_string()
|
|
85
|
+
|
|
86
|
+
# Create a minimal raw compliance node matching the selected framework
|
|
87
|
+
raw_node = {
|
|
88
|
+
"id": "node-1",
|
|
89
|
+
"result": "FAIL",
|
|
90
|
+
"policy": {
|
|
91
|
+
"name": "Policy X",
|
|
92
|
+
"securitySubCategories": [{"category": {"framework": {"id": "wf-id-4"}}}],
|
|
93
|
+
},
|
|
94
|
+
"resource": {"id": "asset-1", "name": "name", "type": "VM"},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
comp_item = integ.create_compliance_item(raw_node)
|
|
98
|
+
# Monkeypatch control id onto the item to simulate parsed control
|
|
99
|
+
comp_item.policy = {
|
|
100
|
+
"name": "Policy X",
|
|
101
|
+
"securitySubCategories": [
|
|
102
|
+
{
|
|
103
|
+
"externalId": control_id,
|
|
104
|
+
"category": {"framework": {"id": "wf-id-4"}},
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
finding = integ.create_finding_from_compliance_item(comp_item)
|
|
110
|
+
assert finding is not None
|
|
111
|
+
|
|
112
|
+
# Ensure affected_controls on finding is set to normalized control ID
|
|
113
|
+
expected_normalized = integ._normalize_control_id_string(control_id)
|
|
114
|
+
assert (
|
|
115
|
+
finding.affected_controls == expected_normalized
|
|
116
|
+
), f"Expected {expected_normalized}, got {finding.affected_controls}"
|
|
117
|
+
|
|
118
|
+
# Mock the base class issue creation method more thoroughly
|
|
119
|
+
with patch.object(
|
|
120
|
+
WizPolicyComplianceIntegration, "_find_existing_issue_cached", return_value=None
|
|
121
|
+
), patch.object(
|
|
122
|
+
WizPolicyComplianceIntegration, "_create_or_update_issue", return_value=None
|
|
123
|
+
) as mock_base_create:
|
|
124
|
+
|
|
125
|
+
# Create a proper mock issue that behaves like the real Issue model
|
|
126
|
+
mock_issue = MagicMock(spec=regscale_models.Issue)
|
|
127
|
+
mock_issue.id = 123
|
|
128
|
+
mock_issue.affectedControls = None
|
|
129
|
+
mock_issue.assetIdentifier = finding.asset_identifier
|
|
130
|
+
mock_issue.controlId = None
|
|
131
|
+
mock_issue.assessmentId = None
|
|
132
|
+
mock_issue.isPoam = False
|
|
133
|
+
mock_issue.parentId = None
|
|
134
|
+
mock_issue.parentModule = None
|
|
135
|
+
|
|
136
|
+
# Make the base method return our mock issue
|
|
137
|
+
mock_base_create.return_value = mock_issue
|
|
138
|
+
|
|
139
|
+
# This should call the parent method and then apply post-processing
|
|
140
|
+
with patch.object(
|
|
141
|
+
WizPolicyComplianceIntegration.__bases__[0],
|
|
142
|
+
"create_or_update_issue_from_finding",
|
|
143
|
+
return_value=mock_issue,
|
|
144
|
+
):
|
|
145
|
+
issue = integ.create_or_update_issue_from_finding(title=finding.title, finding=finding)
|
|
146
|
+
|
|
147
|
+
# Verify we got our mock issue back
|
|
148
|
+
assert issue is mock_issue
|
|
149
|
+
|
|
150
|
+
# Verify the issue's affectedControls was set to the normalized control ID
|
|
151
|
+
# (This gets set in the post-processing step of create_or_update_issue_from_finding)
|
|
152
|
+
assert (
|
|
153
|
+
issue.affectedControls == expected_normalized
|
|
154
|
+
), f"Issue affectedControls should be {expected_normalized}, got {issue.affectedControls}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|