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.

Files changed (52) hide show
  1. regscale/__init__.py +1 -1
  2. regscale/core/app/internal/control_editor.py +26 -2
  3. regscale/core/app/internal/model_editor.py +39 -26
  4. regscale/core/app/utils/api_handler.py +4 -11
  5. regscale/integrations/commercial/crowdstrike.py +0 -1
  6. regscale/integrations/commercial/grype/scanner.py +37 -29
  7. regscale/integrations/commercial/opentext/commands.py +2 -0
  8. regscale/integrations/commercial/opentext/scanner.py +45 -31
  9. regscale/integrations/commercial/qualys.py +52 -61
  10. regscale/integrations/commercial/servicenow.py +1 -0
  11. regscale/integrations/commercial/sicura/commands.py +9 -14
  12. regscale/integrations/commercial/snyk.py +2 -2
  13. regscale/integrations/commercial/synqly/ticketing.py +29 -0
  14. regscale/integrations/commercial/tenablev2/click.py +25 -13
  15. regscale/integrations/commercial/tenablev2/scanner.py +12 -3
  16. regscale/integrations/commercial/trivy/scanner.py +14 -6
  17. regscale/integrations/commercial/veracode.py +1 -1
  18. regscale/integrations/commercial/wizv2/click.py +15 -37
  19. regscale/integrations/jsonl_scanner_integration.py +120 -16
  20. regscale/integrations/public/fedramp/click.py +8 -8
  21. regscale/integrations/public/fedramp/fedramp_cis_crm.py +499 -106
  22. regscale/integrations/public/fedramp/ssp_logger.py +2 -9
  23. regscale/integrations/scanner_integration.py +67 -27
  24. regscale/models/integration_models/cisa_kev_data.json +86 -12
  25. regscale/models/integration_models/flat_file_importer/__init__.py +29 -8
  26. regscale/models/integration_models/snyk.py +141 -15
  27. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  28. regscale/models/integration_models/tenable_models/integration.py +23 -3
  29. regscale/models/integration_models/veracode.py +91 -48
  30. regscale/models/regscale_models/control_implementation.py +18 -0
  31. regscale/models/regscale_models/control_objective.py +2 -1
  32. regscale/models/regscale_models/facility.py +10 -26
  33. regscale/models/regscale_models/functional_roles.py +38 -0
  34. regscale/models/regscale_models/issue.py +3 -1
  35. regscale/models/regscale_models/parameter.py +21 -3
  36. regscale/models/regscale_models/profile.py +22 -0
  37. regscale/models/regscale_models/profile_mapping.py +48 -3
  38. regscale/models/regscale_models/regscale_model.py +2 -0
  39. regscale/models/regscale_models/risk.py +38 -30
  40. regscale/models/regscale_models/security_plan.py +1 -0
  41. regscale/models/regscale_models/supply_chain.py +1 -1
  42. regscale/models/regscale_models/user.py +19 -6
  43. regscale/utils/threading/__init__.py +1 -0
  44. regscale/utils/threading/threadsafe_list.py +10 -0
  45. regscale/utils/threading/threadsafe_set.py +116 -0
  46. regscale/utils/version.py +3 -5
  47. {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/METADATA +1 -1
  48. {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/RECORD +52 -50
  49. {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/LICENSE +0 -0
  50. {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/WHEEL +0 -0
  51. {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.4.0.dist-info}/entry_points.txt +0 -0
  52. {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[int] = None
57
- residualRiskScore: Optional[int] = None
58
- targetRiskScore: Optional[int] = None
59
- difference: Optional[int] = None
60
- futureCosts: Optional[int] = None
61
- costToMitigate: Optional[int] = None
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
- "comments": 29,
149
- "riskTier": 30,
150
- "title": 31,
151
- "recommendations": 32,
152
- "impactDescription": 33,
153
- "inherentRiskScore": 34,
154
- "residualRiskScore": 35,
155
- "targetRiskScore": 36,
156
- "difference": 37,
157
- "futureCosts": 38,
158
- "costToMitigate": 39,
159
- "controlId": 40,
160
- "assessmentId": 41,
161
- "requirementId": 42,
162
- "securityPlanId": 43,
163
- "projectId": 44,
164
- "supplyChainId": 45,
165
- "policyId": 46,
166
- "componentId": 47,
167
- "incidentId": 48,
168
- "riskAssessmentFrequency": 49,
169
- "dateLastAssessed": 50,
170
- "nextAssessmentDueDate": 51,
171
- "riskOwnerId": 52,
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
@@ -18,6 +18,7 @@ class SecurityPlan(RegScaleModel):
18
18
  """
19
19
 
20
20
  _module_slug = "securityplans"
21
+ _unique_fields = ["systemName", "tenantsId"]
21
22
 
22
23
  id: int = 0
23
24
  uuid: str = ""
@@ -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] = (None,)
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 cast, Optional, List
8
+ from typing import List, Optional, cast
9
9
 
10
- from pydantic import Field, ConfigDict, field_validator
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 packaging.version import Version
79
-
80
- regscale_version = cls._get_api_handler().regscale_version
79
+ from regscale.utils.version import RegscaleVersion
81
80
 
82
- if len(regscale_version) >= 10 or Version(regscale_version) >= Version("6.14.0.0"):
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
  """
@@ -6,3 +6,4 @@ from .threadhandler import ThreadManager
6
6
  from .threadsafe_counter import ThreadSafeCounter
7
7
  from .threadsafe_dict import ThreadSafeDict
8
8
  from .threadsafe_list import ThreadSafeList
9
+ from .threadsafe_set import ThreadSafeSet
@@ -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 "dev"
38
+ return "Unknown"
41
39
  except Exception as e:
42
40
  logger.error(f"Error fetching version: {e}", exc_info=True)
43
- return "dev"
41
+ return "Unknown"
44
42
 
45
43
  @staticmethod
46
44
  def is_valid_version(version: str) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: regscale-cli
3
- Version: 6.16.2.0
3
+ Version: 6.16.4.0
4
4
  Summary: Command Line Interface (CLI) for bulk processing/loading data into RegScale
5
5
  Home-page: https://github.com/RegScale/regscale-cli
6
6
  Author: Travis Howerton