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.

Files changed (37) hide show
  1. regscale/_version.py +1 -1
  2. regscale/integrations/commercial/__init__.py +1 -2
  3. regscale/integrations/commercial/amazon/common.py +79 -2
  4. regscale/integrations/commercial/aws/cli.py +183 -9
  5. regscale/integrations/commercial/aws/scanner.py +544 -9
  6. regscale/integrations/commercial/cpe.py +18 -1
  7. regscale/integrations/commercial/tenablev2/jsonl_scanner.py +2 -1
  8. regscale/integrations/commercial/wizv2/async_client.py +10 -3
  9. regscale/integrations/commercial/wizv2/click.py +102 -26
  10. regscale/integrations/commercial/wizv2/constants.py +249 -1
  11. regscale/integrations/commercial/wizv2/issue.py +2 -2
  12. regscale/integrations/commercial/wizv2/parsers.py +3 -2
  13. regscale/integrations/commercial/wizv2/policy_compliance.py +1858 -0
  14. regscale/integrations/commercial/wizv2/scanner.py +15 -21
  15. regscale/integrations/commercial/wizv2/utils.py +258 -85
  16. regscale/integrations/commercial/wizv2/variables.py +4 -3
  17. regscale/integrations/compliance_integration.py +1455 -0
  18. regscale/integrations/public/fedramp/fedramp_five.py +1 -1
  19. regscale/integrations/public/fedramp/markdown_parser.py +7 -1
  20. regscale/integrations/scanner_integration.py +30 -2
  21. regscale/models/app_models/__init__.py +1 -0
  22. regscale/models/integration_models/cisa_kev_data.json +73 -4
  23. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  24. regscale/{integrations/commercial/wizv2/models.py → models/integration_models/wizv2.py} +4 -12
  25. regscale/models/regscale_models/file.py +4 -0
  26. regscale/models/regscale_models/issue.py +123 -0
  27. regscale/models/regscale_models/regscale_model.py +4 -2
  28. regscale/models/regscale_models/security_plan.py +1 -1
  29. regscale/utils/graphql_client.py +3 -1
  30. {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/METADATA +9 -9
  31. {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/RECORD +37 -34
  32. tests/regscale/core/test_version_regscale.py +5 -3
  33. tests/regscale/integrations/test_wiz_policy_compliance_affected_controls.py +154 -0
  34. {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/LICENSE +0 -0
  35. {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/WHEEL +0 -0
  36. {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/entry_points.txt +0 -0
  37. {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}"