regscale-cli 6.16.2.0__py3-none-any.whl → 6.16.4.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/core/app/internal/control_editor.py +26 -2
- regscale/core/app/internal/model_editor.py +39 -26
- regscale/core/app/utils/api_handler.py +4 -11
- regscale/integrations/commercial/crowdstrike.py +0 -1
- regscale/integrations/commercial/grype/scanner.py +37 -29
- regscale/integrations/commercial/opentext/commands.py +2 -0
- regscale/integrations/commercial/opentext/scanner.py +45 -31
- regscale/integrations/commercial/qualys.py +52 -61
- regscale/integrations/commercial/servicenow.py +1 -0
- regscale/integrations/commercial/sicura/commands.py +9 -14
- regscale/integrations/commercial/snyk.py +2 -2
- regscale/integrations/commercial/synqly/ticketing.py +29 -0
- regscale/integrations/commercial/tenablev2/click.py +25 -13
- regscale/integrations/commercial/tenablev2/scanner.py +12 -3
- regscale/integrations/commercial/trivy/scanner.py +14 -6
- regscale/integrations/commercial/veracode.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +15 -37
- regscale/integrations/jsonl_scanner_integration.py +120 -16
- regscale/integrations/public/fedramp/click.py +8 -8
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +499 -106
- regscale/integrations/public/fedramp/ssp_logger.py +2 -9
- regscale/integrations/scanner_integration.py +67 -27
- regscale/models/integration_models/cisa_kev_data.json +86 -12
- regscale/models/integration_models/flat_file_importer/__init__.py +29 -8
- regscale/models/integration_models/snyk.py +141 -15
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/tenable_models/integration.py +23 -3
- regscale/models/integration_models/veracode.py +91 -48
- regscale/models/regscale_models/control_implementation.py +18 -0
- regscale/models/regscale_models/control_objective.py +2 -1
- regscale/models/regscale_models/facility.py +10 -26
- regscale/models/regscale_models/functional_roles.py +38 -0
- regscale/models/regscale_models/issue.py +3 -1
- regscale/models/regscale_models/parameter.py +21 -3
- regscale/models/regscale_models/profile.py +22 -0
- regscale/models/regscale_models/profile_mapping.py +48 -3
- regscale/models/regscale_models/regscale_model.py +2 -0
- regscale/models/regscale_models/risk.py +38 -30
- regscale/models/regscale_models/security_plan.py +1 -0
- regscale/models/regscale_models/supply_chain.py +1 -1
- regscale/models/regscale_models/user.py +19 -6
- regscale/utils/threading/__init__.py +1 -0
- regscale/utils/threading/threadsafe_list.py +10 -0
- regscale/utils/threading/threadsafe_set.py +116 -0
- regscale/utils/version.py +3 -5
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/RECORD +52 -50
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/top_level.txt +0 -0
|
@@ -48,17 +48,18 @@ class Risk(RegScaleModel):
|
|
|
48
48
|
dateClosed: Optional[str] = None
|
|
49
49
|
facilityId: Optional[int] = None
|
|
50
50
|
orgId: Optional[int] = None
|
|
51
|
+
scenarioId: Optional[int] = None
|
|
51
52
|
comments: Optional[str] = None
|
|
52
53
|
riskTier: Optional[str] = None
|
|
53
54
|
title: Optional[str] = None
|
|
54
55
|
recommendations: Optional[str] = None
|
|
55
56
|
impactDescription: Optional[str] = None
|
|
56
|
-
inherentRiskScore: Optional[
|
|
57
|
-
residualRiskScore: Optional[
|
|
58
|
-
targetRiskScore: Optional[
|
|
59
|
-
difference: Optional[
|
|
60
|
-
futureCosts: Optional[
|
|
61
|
-
costToMitigate: Optional[
|
|
57
|
+
inherentRiskScore: Optional[float] = None
|
|
58
|
+
residualRiskScore: Optional[float] = None
|
|
59
|
+
targetRiskScore: Optional[float] = None
|
|
60
|
+
difference: Optional[float] = None
|
|
61
|
+
futureCosts: Optional[float] = None
|
|
62
|
+
costToMitigate: Optional[float] = None
|
|
62
63
|
controlId: Optional[int] = None
|
|
63
64
|
assessmentId: Optional[int] = None
|
|
64
65
|
requirementId: Optional[int] = None
|
|
@@ -73,6 +74,9 @@ class Risk(RegScaleModel):
|
|
|
73
74
|
nextAssessmentDueDate: Optional[str] = None
|
|
74
75
|
riskOwnerId: Optional[str] = None
|
|
75
76
|
isPublic: bool = True
|
|
77
|
+
averageRiskScore: Optional[float] = None
|
|
78
|
+
weightedRiskScore: Optional[float] = None
|
|
79
|
+
parentRiskModelId: Optional[int] = None
|
|
76
80
|
|
|
77
81
|
@staticmethod
|
|
78
82
|
def fetch_all_risks(app: Application) -> list["Risk"]:
|
|
@@ -145,31 +149,35 @@ class Risk(RegScaleModel):
|
|
|
145
149
|
"dateClosed": 26,
|
|
146
150
|
"facilityId": 27,
|
|
147
151
|
"orgId": 28,
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
152
|
+
"scenarioId": 29,
|
|
153
|
+
"comments": 30,
|
|
154
|
+
"riskTier": 31,
|
|
155
|
+
"title": 32,
|
|
156
|
+
"recommendations": 33,
|
|
157
|
+
"impactDescription": 34,
|
|
158
|
+
"inherentRiskScore": 35,
|
|
159
|
+
"residualRiskScore": 36,
|
|
160
|
+
"targetRiskScore": 37,
|
|
161
|
+
"difference": 38,
|
|
162
|
+
"futureCosts": 39,
|
|
163
|
+
"costToMitigate": 40,
|
|
164
|
+
"controlId": 41,
|
|
165
|
+
"assessmentId": 42,
|
|
166
|
+
"requirementId": 43,
|
|
167
|
+
"securityPlanId": 44,
|
|
168
|
+
"projectId": 45,
|
|
169
|
+
"supplyChainId": 46,
|
|
170
|
+
"policyId": 47,
|
|
171
|
+
"componentId": 48,
|
|
172
|
+
"incidentId": 49,
|
|
173
|
+
"riskAssessmentFrequency": 50,
|
|
174
|
+
"dateLastAssessed": 51,
|
|
175
|
+
"nextAssessmentDueDate": 52,
|
|
176
|
+
"riskOwnerId": 53,
|
|
172
177
|
"isPublic": -1,
|
|
178
|
+
"averageRiskScore": 54,
|
|
179
|
+
"weightedRiskScore": 55,
|
|
180
|
+
"parentRiskModelId": 56,
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
# pylint: disable=W0613
|
|
@@ -106,7 +106,7 @@ class SupplyChain(RegScaleModel):
|
|
|
106
106
|
actualCosts: Optional[int] = 0
|
|
107
107
|
strategicTier: Optional[Union[SupplyChainTier, str]] = None
|
|
108
108
|
contractType: Optional[Union[SupplyChainContractType, str]] = None
|
|
109
|
-
scope: Optional[str] =
|
|
109
|
+
scope: Optional[str] = None
|
|
110
110
|
startDate: Optional[str] = None
|
|
111
111
|
endDate: Optional[str] = None
|
|
112
112
|
violationURL: Optional[str] = None
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
# standard python imports
|
|
6
6
|
import random
|
|
7
7
|
import string
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import List, Optional, cast
|
|
9
9
|
|
|
10
|
-
from pydantic import
|
|
10
|
+
from pydantic import ConfigDict, Field, field_validator
|
|
11
11
|
|
|
12
12
|
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
13
|
+
|
|
13
14
|
from .regscale_model import RegScaleModel, T
|
|
14
15
|
|
|
15
16
|
|
|
@@ -75,11 +76,10 @@ class User(RegScaleModel):
|
|
|
75
76
|
:param str v: homePageUrl value
|
|
76
77
|
:return: The homePageUrl if the RegScale version is compatible, None otherwise
|
|
77
78
|
"""
|
|
78
|
-
from
|
|
79
|
-
|
|
80
|
-
regscale_version = cls._get_api_handler().regscale_version
|
|
79
|
+
from regscale.utils.version import RegscaleVersion
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
rv = RegscaleVersion()
|
|
82
|
+
if rv.meets_minimum_version("6.14.0.0"):
|
|
83
83
|
return v
|
|
84
84
|
else:
|
|
85
85
|
return None
|
|
@@ -123,6 +123,19 @@ class User(RegScaleModel):
|
|
|
123
123
|
change_avatar="/api/{model_slug}/changeAvatar/{strUsername}",
|
|
124
124
|
)
|
|
125
125
|
|
|
126
|
+
@classmethod
|
|
127
|
+
def get_roles(cls) -> List[dict]:
|
|
128
|
+
"""
|
|
129
|
+
Get all roles from RegScale
|
|
130
|
+
|
|
131
|
+
:return: List of RegScale roles
|
|
132
|
+
:rtype: List[dict]
|
|
133
|
+
"""
|
|
134
|
+
response = cls._get_api_handler().get(endpoint=cls.get_endpoint("get_roles"))
|
|
135
|
+
if response and response.ok:
|
|
136
|
+
return response.json()
|
|
137
|
+
return []
|
|
138
|
+
|
|
126
139
|
@classmethod
|
|
127
140
|
def get_tenant_id_for_user_id(cls, user_id: str) -> Optional[int]:
|
|
128
141
|
"""
|
|
@@ -63,6 +63,16 @@ class ThreadSafeList(Generic[T]):
|
|
|
63
63
|
with self._lock:
|
|
64
64
|
return iter(self._list.copy())
|
|
65
65
|
|
|
66
|
+
def __list__(self) -> List[T]:
|
|
67
|
+
"""
|
|
68
|
+
Convert ThreadSafeList to a regular list when list() is called
|
|
69
|
+
|
|
70
|
+
:return: A copy of the internal list
|
|
71
|
+
:rtype: List[T]
|
|
72
|
+
"""
|
|
73
|
+
with self._lock:
|
|
74
|
+
return self._list.copy()
|
|
75
|
+
|
|
66
76
|
def remove(self, item: T) -> None:
|
|
67
77
|
"""
|
|
68
78
|
Remove an item from the list
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the ThreadSafeSet class, which is a thread-safe set.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from threading import RLock
|
|
6
|
+
from typing import Generic, Iterator, Optional, Set, TypeVar
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T") # Declare type variable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ThreadSafeSet(Generic[T]):
|
|
12
|
+
"""
|
|
13
|
+
ThreadSafeSet class to create a thread-safe set.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, initial_set: Optional[Set[T]] = None):
|
|
17
|
+
"""
|
|
18
|
+
Initialize a new ThreadSafeSet
|
|
19
|
+
|
|
20
|
+
:param Set[T]|None initial_set: Optional initial set to populate the ThreadSafeSet
|
|
21
|
+
"""
|
|
22
|
+
self._set: Set[T] = set(initial_set) if initial_set is not None else set()
|
|
23
|
+
self._lock = RLock()
|
|
24
|
+
|
|
25
|
+
def add(self, item: T) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Add an item to the set
|
|
28
|
+
|
|
29
|
+
:param T item: Item to add to the set
|
|
30
|
+
:rtype: None
|
|
31
|
+
"""
|
|
32
|
+
with self._lock:
|
|
33
|
+
self._set.add(item)
|
|
34
|
+
|
|
35
|
+
def remove(self, item: T) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Remove an item from the set
|
|
38
|
+
|
|
39
|
+
:param T item: Item to remove from the set
|
|
40
|
+
:raises KeyError: If the item is not found
|
|
41
|
+
:rtype: None
|
|
42
|
+
"""
|
|
43
|
+
with self._lock:
|
|
44
|
+
self._set.remove(item)
|
|
45
|
+
|
|
46
|
+
def discard(self, item: T) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Remove an item from the set if it exists
|
|
49
|
+
|
|
50
|
+
:param T item: Item to remove from the set
|
|
51
|
+
:rtype: None
|
|
52
|
+
"""
|
|
53
|
+
with self._lock:
|
|
54
|
+
self._set.discard(item)
|
|
55
|
+
|
|
56
|
+
def __len__(self) -> int:
|
|
57
|
+
"""
|
|
58
|
+
Get the length of the set
|
|
59
|
+
|
|
60
|
+
:return: The length of the set
|
|
61
|
+
:rtype: int
|
|
62
|
+
"""
|
|
63
|
+
with self._lock:
|
|
64
|
+
return len(self._set)
|
|
65
|
+
|
|
66
|
+
def __iter__(self) -> Iterator[T]:
|
|
67
|
+
"""
|
|
68
|
+
Return an iterator over the set
|
|
69
|
+
|
|
70
|
+
:return: An iterator over the set
|
|
71
|
+
:rtype: Iterator[T]
|
|
72
|
+
"""
|
|
73
|
+
with self._lock:
|
|
74
|
+
return iter(self._set.copy())
|
|
75
|
+
|
|
76
|
+
def __contains__(self, item: T) -> bool:
|
|
77
|
+
"""
|
|
78
|
+
Check if an item is in the set
|
|
79
|
+
|
|
80
|
+
:param T item: Item to check
|
|
81
|
+
:return: True if the item is in the set, False otherwise
|
|
82
|
+
:rtype: bool
|
|
83
|
+
"""
|
|
84
|
+
with self._lock:
|
|
85
|
+
return item in self._set
|
|
86
|
+
|
|
87
|
+
def clear(self) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Clear the set
|
|
90
|
+
|
|
91
|
+
:rtype: None
|
|
92
|
+
"""
|
|
93
|
+
with self._lock:
|
|
94
|
+
self._set.clear()
|
|
95
|
+
|
|
96
|
+
def union(self, other: Set[T]) -> Set[T]:
|
|
97
|
+
"""
|
|
98
|
+
Return the union of this set and another
|
|
99
|
+
|
|
100
|
+
:param Set[T] other: Other set to union with
|
|
101
|
+
:return: A new set containing the union
|
|
102
|
+
:rtype: Set[T]
|
|
103
|
+
"""
|
|
104
|
+
with self._lock:
|
|
105
|
+
return self._set.union(other)
|
|
106
|
+
|
|
107
|
+
def intersection(self, other: Set[T]) -> Set[T]:
|
|
108
|
+
"""
|
|
109
|
+
Return the intersection of this set and another
|
|
110
|
+
|
|
111
|
+
:param Set[T] other: Other set to intersect with
|
|
112
|
+
:return: A new set containing the intersection
|
|
113
|
+
:rtype: Set[T]
|
|
114
|
+
"""
|
|
115
|
+
with self._lock:
|
|
116
|
+
return self._set.intersection(other)
|
regscale/utils/version.py
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
|
-
from typing import Optional
|
|
6
5
|
from functools import lru_cache
|
|
7
6
|
|
|
8
7
|
from packaging.version import Version
|
|
9
8
|
|
|
10
9
|
from regscale.core.app.utils.api_handler import APIHandler
|
|
11
|
-
from regscale.utils.decorators import classproperty
|
|
12
10
|
|
|
13
11
|
logger = logging.getLogger(__name__)
|
|
14
12
|
|
|
@@ -32,15 +30,15 @@ class RegscaleVersion:
|
|
|
32
30
|
try:
|
|
33
31
|
api_handler = APIHandler()
|
|
34
32
|
response = api_handler.get("/assets/json/version.json")
|
|
35
|
-
if response.status_code == 200:
|
|
33
|
+
if response.ok and response.status_code == 200:
|
|
36
34
|
version_data = response.json()
|
|
37
35
|
return version_data.get("version", "Unknown")
|
|
38
36
|
else:
|
|
39
37
|
logger.error(f"Failed to fetch version. Status code: {response.status_code}")
|
|
40
|
-
return "
|
|
38
|
+
return "Unknown"
|
|
41
39
|
except Exception as e:
|
|
42
40
|
logger.error(f"Error fetching version: {e}", exc_info=True)
|
|
43
|
-
return "
|
|
41
|
+
return "Unknown"
|
|
44
42
|
|
|
45
43
|
@staticmethod
|
|
46
44
|
def is_valid_version(version: str) -> bool:
|