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.

Files changed (36) hide show
  1. regscale/__init__.py +1 -1
  2. regscale/airflow/config.py +2 -0
  3. regscale/airflow/tasks/groups.py +11 -47
  4. regscale/core/app/internal/login.py +49 -43
  5. regscale/core/app/internal/model_editor.py +2 -1
  6. regscale/dev/code_gen.py +2 -5
  7. regscale/integrations/commercial/amazon/common.py +5 -4
  8. regscale/integrations/commercial/aws/scanner.py +3 -2
  9. regscale/integrations/commercial/synqly/assets.py +20 -0
  10. regscale/integrations/commercial/synqly/ticketing.py +25 -0
  11. regscale/integrations/commercial/wizv2/click.py +3 -3
  12. regscale/integrations/public/fedramp/appendix_parser.py +499 -104
  13. regscale/integrations/public/fedramp/fedramp_five.py +89 -43
  14. regscale/integrations/scanner_integration.py +1 -1
  15. regscale/models/app_models/import_validater.py +2 -0
  16. regscale/models/integration_models/cisa_kev_data.json +355 -27
  17. regscale/models/integration_models/flat_file_importer/__init__.py +26 -9
  18. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  19. regscale/models/regscale_models/__init__.py +5 -0
  20. regscale/models/regscale_models/business_impact_assessment.py +71 -0
  21. regscale/models/regscale_models/control_implementation.py +15 -0
  22. regscale/models/regscale_models/master_assessment.py +19 -0
  23. regscale/models/regscale_models/policy.py +90 -0
  24. regscale/models/regscale_models/question.py +30 -2
  25. regscale/models/regscale_models/questionnaire.py +4 -3
  26. regscale/models/regscale_models/questionnaire_instance.py +37 -14
  27. regscale/models/regscale_models/rbac.py +0 -1
  28. regscale/models/regscale_models/regscale_model.py +16 -15
  29. regscale/models/regscale_models/risk_trend.py +67 -0
  30. regscale/utils/graphql_client.py +2 -1
  31. {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/METADATA +130 -71
  32. {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/RECORD +36 -33
  33. {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/LICENSE +0 -0
  34. {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/WHEEL +0 -0
  35. {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/entry_points.txt +0 -0
  36. {regscale_cli-6.19.1.0.dist-info → regscale_cli-6.20.0.0.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@
3
3
  from .assessment import *
4
4
  from .asset import *
5
5
  from .asset_mapping import *
6
+ from .business_impact_assessment import *
6
7
  from .catalog import *
7
8
  from .cci import *
8
9
  from .change import *
@@ -32,9 +33,11 @@ from .interconnection import *
32
33
  from .issue import *
33
34
  from .leveraged_authorization import *
34
35
  from .link import *
36
+ from .master_assessment import *
35
37
  from .meta_data import *
36
38
  from .objective import *
37
39
  from .parameter import *
40
+ from .policy import *
38
41
  from .ports_protocol import *
39
42
  from .privacy import *
40
43
  from .profile import *
@@ -48,6 +51,7 @@ from .questionnaire_instance import *
48
51
  from .reference import *
49
52
  from .requirement import *
50
53
  from .risk import *
54
+ from .risk_trend import *
51
55
  from .sbom import *
52
56
  from .scan_history import *
53
57
  from .security_control import *
@@ -55,6 +59,7 @@ from .security_plan import *
55
59
  from .software_inventory import *
56
60
  from .stake_holder import *
57
61
  from .stig import *
62
+ from .supply_chain import *
58
63
  from .system_role import *
59
64
  from .system_role_external_assignment import *
60
65
  from .task import *
@@ -0,0 +1,71 @@
1
+ """
2
+ This module contains the Business Impact Assessment model for RegScale.
3
+ """
4
+
5
+ from typing import List
6
+
7
+ from pydantic import ConfigDict
8
+
9
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
10
+
11
+
12
+ class BusinessImpactAssessment(RegScaleModel):
13
+ """RegScale Business Impact Assessment
14
+
15
+ :return: RegScale Business Impact Assessment
16
+ """
17
+
18
+ _module_slug = "business-impact-assessments"
19
+ _module_string = "business-impact-assessments"
20
+ # Should we include baseline, ruleId, check, and results in unique fields?
21
+ _unique_fields = [
22
+ [
23
+ "riskId",
24
+ "category",
25
+ ],
26
+ ]
27
+ _parent_id_field = "riskId"
28
+ # Required
29
+ id: int = 0
30
+ isPublic: bool = True
31
+ uuid: str = ""
32
+ category: str = ""
33
+ probability: str = ""
34
+ consequence: str = ""
35
+ notes: str = ""
36
+ riskType: str = ""
37
+ riskScore: int = 0
38
+ riskId: int = 0
39
+
40
+ @staticmethod
41
+ def _get_additional_endpoints() -> ConfigDict:
42
+ """
43
+ Get additional endpoints for the Catalogues model
44
+
45
+ :return: A dictionary of additional endpoints
46
+ :rtype: ConfigDict
47
+ """
48
+ return ConfigDict( # type: ignore
49
+ get_all_by_risk="/api/{model_slug}/getAllByRisk/{intID}",
50
+ get_all_by_risk_and_type="/api/{model_slug}/getAllByRiskAndType/{intID}/{strType}",
51
+ )
52
+
53
+ @classmethod
54
+ def get_all_by_risk(cls, risk_id: int) -> List["BusinessImpactAssessment"]:
55
+ """
56
+ Get all Business Impact Assessments by risk ID
57
+ """
58
+ endpoint = cls.get_endpoint("get_all_by_risk").format(model_slug=cls.get_module_slug(), intID=risk_id)
59
+ res = cls._handle_list_response(cls._get_api_handler().get(endpoint))
60
+ return res
61
+
62
+ @classmethod
63
+ def get_all_by_risk_and_type(cls, risk_id: int, risk_type: str) -> List["BusinessImpactAssessment"]:
64
+ """
65
+ Get all Business Impact Assessments by risk ID and type
66
+ """
67
+ endpoint = cls.get_endpoint("get_all_by_risk_and_type").format(
68
+ model_slug=cls.get_module_slug(), intID=risk_id, strType=risk_type
69
+ )
70
+ res = cls._handle_list_response(cls._get_api_handler().get(endpoint))
71
+ return res
@@ -39,6 +39,21 @@ class ControlImplementationStatus(str, Enum):
39
39
  Alternative = "Alternate Implementation"
40
40
 
41
41
 
42
+ class ImplementationControlOrigin(str, Enum):
43
+ SERVICE_PROVIDER_CORPORATE = "Service Provider Corporate"
44
+ SERVICE_PROVIDER_SYSTEM = "Service Provider System Specific"
45
+ SERVICE_PROVIDER_HYBRID = "Service Provider Hybrid (Corporate and System Specific)"
46
+ CONFIGURED_BY_CUSTOMER = "Configured by Customer (Customer System Specific)"
47
+ PROVIDED_BY_CUSTOMER = "Provided by Customer (Customer Specific)"
48
+ SHARED = "Shared (Service Provider and Customer Responsibility)"
49
+ INHERITED_FROM_PRE_EXISTING_FEDRAMP_AUTHORIZATION = (
50
+ "Inherited from pre-existing FedRAMP Authorization" # noqa: E501
51
+ )
52
+
53
+ def __str__(self):
54
+ return self.value
55
+
56
+
42
57
  class ControlImplementationOrigin(str, Enum):
43
58
  """Control Origination"""
44
59
 
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
3
  """Model for a RegScale Assessment"""
4
+ from enum import Enum
4
5
  from typing import List, Optional
5
6
 
6
7
  from pydantic import ConfigDict, Field
@@ -9,6 +10,13 @@ from regscale.models.regscale_models.assessment import Assessment
9
10
  from regscale.models.regscale_models.regscale_model import RegScaleModel
10
11
 
11
12
 
13
+ class MasterAssessmentStatus(Enum):
14
+ """Enum representing different status states with string values."""
15
+
16
+ InProgress = "In Progress"
17
+ Completed = "Completed"
18
+
19
+
12
20
  class MasterAssessment(RegScaleModel):
13
21
  """
14
22
  Model for a RegScale Assessment
@@ -125,3 +133,14 @@ class MasterAssessment(RegScaleModel):
125
133
  if ci := cls.get_object(object_id=ci["id"]):
126
134
  assessments.append(ci)
127
135
  return assessments
136
+
137
+ @classmethod
138
+ def is_date_field(cls, field_name: str) -> bool:
139
+ """
140
+ Overrides the base method.
141
+
142
+ :param str field_name: The property name to provide enum values for
143
+ :return: bool if the field should be formatted as a date
144
+ :rtype: bool
145
+ """
146
+ return field_name in ["plannedStart", "plannedFinish", "actualFinish"]
@@ -0,0 +1,90 @@
1
+ """This module contains the Policy models."""
2
+
3
+ from datetime import datetime
4
+ from typing import List, Optional
5
+
6
+ from pydantic import ConfigDict
7
+
8
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
9
+
10
+
11
+ class PolicyParameter(RegScaleModel):
12
+ """Policy Parameter Model"""
13
+
14
+ _module_slug = "policyparameter"
15
+ _unique_fields = [
16
+ ["policyId", "name"],
17
+ ]
18
+ id: int = 0
19
+ policyId: int
20
+ name: str = ""
21
+ value: str = ""
22
+ default: str = ""
23
+
24
+
25
+ class Policy(RegScaleModel):
26
+ """Policy Model"""
27
+
28
+ _module_slug = "policies"
29
+ _unique_fields = [
30
+ ["integrationFindingId", "vulnerabilityId", "status"],
31
+ ["otherIdentifier", "parentModule", "parentId", "status"],
32
+ ]
33
+
34
+ id: int = 0
35
+ policyNumber: str = ""
36
+ policyOwnerId: str = ""
37
+ policyType: str = ""
38
+ dateApproved: str = ""
39
+ expirationDate: str = ""
40
+ status: str = ""
41
+ title: str = ""
42
+ description: str = ""
43
+ practiceLevel: str = ""
44
+ processLevel: str = ""
45
+ facilityId: Optional[int] = None
46
+ orgId: int = 0
47
+ parentModule: str = ""
48
+ parentId: int = 0
49
+ isPublic: bool = True
50
+ policyTemplate: str = ""
51
+ policyTemplateId: str = ""
52
+ policyParameters: List[PolicyParameter] = []
53
+
54
+ @staticmethod
55
+ def _get_additional_endpoints() -> ConfigDict:
56
+ """
57
+ Get additional endpoints for the ProfileMapping model, using {model_slug} as a placeholder for the model slug.
58
+
59
+ :return: A dictionary of additional endpoints
60
+ :rtype: ConfigDict
61
+ """
62
+
63
+ return ConfigDict( # type: ignore
64
+ get_list="/api/{model_slug}/getList",
65
+ )
66
+
67
+ @classmethod
68
+ def get_list(cls) -> List[dict]:
69
+ """
70
+ Get a list of policies.
71
+
72
+ :return: A list of policies
73
+ :rtype: List[dict]
74
+ """
75
+ endpoint = cls.get_endpoint("get_list")
76
+ res = cls._get_api_handler().get(endpoint=endpoint)
77
+ return res.json()
78
+
79
+ def convert_datetime_to_date_str(self, dt: Optional[datetime]) -> str:
80
+ """
81
+ Convert a datetime object to a date string in the format 'MMM DD, YYYY'.
82
+
83
+ :param dt: The datetime object to convert
84
+ :type dt: Optional[datetime]
85
+ :return: The date string in format 'MMM DD, YYYY'
86
+ :rtype: str
87
+ """
88
+ if dt is None:
89
+ return ""
90
+ return dt.strftime("%b %d, %Y")
@@ -3,9 +3,13 @@ This module contains the Questions model for RegScale.
3
3
  """
4
4
 
5
5
  from enum import Enum
6
- from typing import Optional, List, Dict
6
+ from typing import Dict, List, Optional
7
+
7
8
  from pydantic import ConfigDict, Field
9
+
10
+ from regscale.core.app.utils.api_handler import APIRetrieveError
8
11
  from regscale.core.app.utils.app_utils import get_current_datetime
12
+
9
13
  from .regscale_model import RegScaleModel
10
14
 
11
15
 
@@ -62,6 +66,30 @@ class Questions(RegScaleModel):
62
66
  uploadEnabled: bool = False
63
67
  response: Optional[str] = None # Adjust the type if it's not a string
64
68
 
69
+ @classmethod
70
+ def get_all_by_parent(cls, parent_questionnaire_id: int) -> List["Questions"]:
71
+ """
72
+ Retrieve all questions associated with a parent questionnaire.
73
+
74
+ :param parent_questionnaire_id: The ID of the parent questionnaire to fetch questions for.
75
+ :return: A list of Questions objects associated with the parent questionnaire.
76
+ :raises ValueError: If parent_questionnaire_id is less than or equal to 0.
77
+ :raises APIRetrieveError: If the API request fails.
78
+ """
79
+ if parent_questionnaire_id <= 0:
80
+ raise ValueError("parent_questionnaire_id must be a positive integer")
81
+
82
+ params = {"parentId": parent_questionnaire_id}
83
+ endpoint = cls.get_endpoint("get_all_by_parent").format(
84
+ model_slug=cls._module_slug,
85
+ )
86
+
87
+ response = cls._get_api_handler().get(endpoint=endpoint, params=params)
88
+ if not response.ok:
89
+ raise APIRetrieveError(f"Failed to fetch questions: {response.status_code} - {response.text}")
90
+
91
+ return [cls(**ques) for ques in response.json()]
92
+
65
93
  @staticmethod
66
94
  def _get_additional_endpoints() -> ConfigDict:
67
95
  """
@@ -71,7 +99,7 @@ class Questions(RegScaleModel):
71
99
  :rtype: ConfigDict
72
100
  """
73
101
  return ConfigDict(
74
- get_all_by_parent_get="/api/{model_slug}/getAllByParent",
102
+ get_all_by_parent="/api/{model_slug}/getAllByParent",
75
103
  get="/api/{model_slug}/find/{id}",
76
104
  insert="/api/{model_slug}/create",
77
105
  update="/api/{model_slug}/update",
@@ -1,9 +1,10 @@
1
+ # pylint: disable=C0301
1
2
  """
2
3
  This module contains the Questionnaires model in RegScale.
3
4
  """
4
5
 
5
6
  import logging
6
- from typing import Optional, List, Dict
7
+ from typing import List, Optional
7
8
 
8
9
  from pydantic import ConfigDict
9
10
 
@@ -19,6 +20,7 @@ class Questionnaires(RegScaleModel):
19
20
  """
20
21
 
21
22
  _module_slug = "questionnaires"
23
+ _unique_fields = [["title", "parentQuestionnaireId"]]
22
24
 
23
25
  id: Optional[int] = 0
24
26
  uuid: Optional[str] = None
@@ -82,6 +84,5 @@ class Questionnaires(RegScaleModel):
82
84
  if response.ok:
83
85
  response_json = response.json()
84
86
  return [QuestionnaireInstance(**instance) for instance in response_json.get("createdInstances", [])]
85
- else:
86
- logger.info(f"Failed to create instances from questionnaires {response.status_code} - {response.text}")
87
+ logger.info("Failed to create instances from questionnaires %i - %s", response.status_code, response.text)
87
88
  return None
@@ -2,14 +2,15 @@
2
2
  This module contains the QuestionnaireInstances model.
3
3
  """
4
4
 
5
+ import logging
5
6
  from enum import Enum
6
- from typing import Optional, List, Dict, Any
7
+ from typing import Any, Dict, List, Optional
7
8
 
8
- from pydantic import Field, ConfigDict
9
+ from pydantic import ConfigDict, Field
10
+ from requests import Response
9
11
 
10
12
  from regscale.core.app.utils.app_utils import get_current_datetime
11
13
  from regscale.models.regscale_models.regscale_model import RegScaleModel
12
- import logging
13
14
 
14
15
  logger = logging.getLogger(__name__)
15
16
 
@@ -113,26 +114,48 @@ class QuestionnaireInstance(RegScaleModel):
113
114
  return None
114
115
 
115
116
  @classmethod
116
- def link_feedback(cls, id: int) -> Optional[Dict[str, Any]]:
117
+ def _handle_response(cls, response: Optional[Response]) -> Optional[Dict[str, Any]]:
117
118
  """
118
- Retrieves a questionnaire based on its ID for feedback purposes.
119
+ Helper method to handle API responses consistently.
119
120
 
120
- :param int id: The ID of the questionnaire
121
- :return: The response from the API or None
121
+ :param Optional[Response] response: The response from the API
122
+ :return: The JSON response if successful, None otherwise
122
123
  :rtype: Optional[Dict[str, Any]]
123
124
  """
124
- endpoint = cls.get_endpoint("link_feedback").format(model_slug=cls._module_slug, id=id)
125
- response = cls._get_api_handler().get(endpoint)
126
-
127
125
  if not response or response.status_code in [204, 404]:
128
126
  return None
129
127
  if response.ok:
130
- try:
131
- return response.json()
132
- except Exception:
133
- return None
128
+ return response.json()
134
129
  return None
135
130
 
131
+ @classmethod
132
+ def submit_for_feedback(cls, quid: str, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
133
+ """
134
+ Submits a questionnaire instance for feedback.
135
+
136
+ :param str quid: The QUID of the questionnaire instance
137
+ :param Dict[str, Any] payload: The data to be sent in the request body
138
+ :return: The response from the API or None
139
+ :rtype: Optional[Dict[str, Any]]
140
+ """
141
+ endpoint = cls.get_endpoint("submit_for_feedback").format(model_slug=cls._module_slug, uuid=quid)
142
+ response = cls._get_api_handler().put(endpoint, data=payload)
143
+ return cls._handle_response(response)
144
+
145
+ @classmethod
146
+ def update_response(cls, quid: str, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
147
+ """
148
+ Updates questionnaire instance responses.
149
+
150
+ :param str quid: The QUID of the questionnaire instance
151
+ :param Dict[str, Any] payload: The data to be sent in the request body containing instance and questions
152
+ :return: The response from the API or None
153
+ :rtype: Optional[Dict[str, Any]]
154
+ """
155
+ endpoint = cls.get_endpoint("update_responses").format(model_slug=cls._module_slug, uuid=quid)
156
+ response = cls._get_api_handler().put(endpoint, data=payload)
157
+ return cls._handle_response(response)
158
+
136
159
  @classmethod
137
160
  def get_all_by_parent(cls, parent_questionnaire_id: int) -> List["QuestionnaireInstance"]:
138
161
  """
@@ -8,7 +8,6 @@ logger = logging.getLogger(__name__)
8
8
 
9
9
 
10
10
  class RBAC(RegScaleModel):
11
-
12
11
  _module_slug = "rbac"
13
12
  id: Optional[int] = Field(alias="rbacId")
14
13
  moduleId: Optional[int] = None
@@ -32,6 +32,8 @@ T = TypeVar("T", bound="RegScaleModel")
32
32
 
33
33
  logger = logging.getLogger("regscale")
34
34
 
35
+ IS_DISABLE_CACHE = False # flag to disable caching
36
+
35
37
 
36
38
  class RegScaleModel(BaseModel, ABC):
37
39
  """Mixin class for RegScale Models to add functionality to interact with RegScale API"""
@@ -52,8 +54,6 @@ class RegScaleModel(BaseModel, ABC):
52
54
  _exclude_graphql_fields: ClassVar[List[str]] = ["extra_data", "tenantsId"]
53
55
  _original_data: Optional[Dict[str, Any]] = None
54
56
 
55
- # Caching
56
- _disable_cache: bool = False # flag to disable caching
57
57
  _object_cache: ClassVar[Cache] = Cache(maxsize=100000)
58
58
  _parent_cache: ClassVar[Cache] = Cache(maxsize=50000)
59
59
  _lock_registry: ClassVar[ThreadSafeDict] = ThreadSafeDict()
@@ -78,11 +78,12 @@ class RegScaleModel(BaseModel, ABC):
78
78
  :rtype: None
79
79
  """
80
80
  try:
81
+ global IS_DISABLE_CACHE
81
82
  super().__init__(*args, **data)
82
83
  # Capture initial state after initialization
83
84
  self._original_data = self.dict(exclude_unset=True)
84
- self._disable_cache = self._fetch_disabled_cache_setting()
85
- if self._disable_cache:
85
+ IS_DISABLE_CACHE = self._fetch_disabled_cache_setting()
86
+ if IS_DISABLE_CACHE:
86
87
  logger.debug("cache is disabled")
87
88
  except Exception as e:
88
89
  logger.error(f"Error creating {self.__class__.__name__}: {e} {data}", exc_info=True)
@@ -107,8 +108,9 @@ class RegScaleModel(BaseModel, ABC):
107
108
  :return: True if caching is disabled, False otherwise
108
109
  :rtype: bool
109
110
  """
110
- cls._disable_cache = True
111
- return cls._disable_cache
111
+ global IS_DISABLE_CACHE
112
+ IS_DISABLE_CACHE = True
113
+ return IS_DISABLE_CACHE
112
114
 
113
115
  @classmethod
114
116
  def enable_cache(cls) -> bool:
@@ -118,8 +120,9 @@ class RegScaleModel(BaseModel, ABC):
118
120
  :return: True if caching is enabled, False otherwise
119
121
  :rtype: bool
120
122
  """
121
- cls._disable_cache = False
122
- return cls._disable_cache
123
+ global IS_DISABLE_CACHE
124
+ IS_DISABLE_CACHE = False
125
+ return IS_DISABLE_CACHE
123
126
 
124
127
  @classmethod
125
128
  def _get_api_handler(cls) -> APIHandler:
@@ -207,7 +210,7 @@ class RegScaleModel(BaseModel, ABC):
207
210
  :return: The cached object if found, None otherwise
208
211
  :rtype: Optional[T]
209
212
  """
210
- if cls._disable_cache:
213
+ if IS_DISABLE_CACHE:
211
214
  return None
212
215
  with cls._get_lock(cache_key):
213
216
  return cls._object_cache.get(cache_key)
@@ -221,7 +224,7 @@ class RegScaleModel(BaseModel, ABC):
221
224
  :return: None
222
225
  :rtype: None
223
226
  """
224
- if cls._disable_cache:
227
+ if IS_DISABLE_CACHE:
225
228
  return
226
229
  try:
227
230
  if not obj:
@@ -271,7 +274,7 @@ class RegScaleModel(BaseModel, ABC):
271
274
  :return: None
272
275
  :rtype: None
273
276
  """
274
- if cls._disable_cache:
277
+ if IS_DISABLE_CACHE:
275
278
  return
276
279
  parent_id = getattr(obj, cls._parent_id_field, None)
277
280
  parent_module = getattr(obj, "parentModule", getattr(obj, "parent_module", ""))
@@ -296,7 +299,7 @@ class RegScaleModel(BaseModel, ABC):
296
299
  :return: None
297
300
  :rtype: None
298
301
  """
299
- if cls._disable_cache:
302
+ if IS_DISABLE_CACHE:
300
303
  return
301
304
  with cls._get_lock(cache_key):
302
305
  for obj in objects:
@@ -311,8 +314,6 @@ class RegScaleModel(BaseModel, ABC):
311
314
  :return: None
312
315
  :rtype: None
313
316
  """
314
- if cls._disable_cache:
315
- return
316
317
  cls._object_cache.clear()
317
318
 
318
319
  @classmethod
@@ -324,7 +325,7 @@ class RegScaleModel(BaseModel, ABC):
324
325
  :return: None
325
326
  :rtype: None
326
327
  """
327
- if cls._disable_cache:
328
+ if IS_DISABLE_CACHE:
328
329
  return
329
330
  cache_key = cls._get_cache_key(obj)
330
331
  with cls._get_lock(cache_key):
@@ -0,0 +1,67 @@
1
+ """
2
+ This module contains the Risk Trends model for RegScale.
3
+ """
4
+
5
+ from typing import Optional
6
+
7
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
8
+
9
+
10
+ class RiskTrend(RegScaleModel):
11
+ """RegScale Risk Trends
12
+
13
+ :return: RegScale Business Impact Assessment
14
+ """
15
+
16
+ _module_slug = "riskTrends"
17
+ _module_string = "riskTrends"
18
+ # Should we include baseline, ruleId, check, and results in unique fields?
19
+ _unique_fields = [
20
+ [
21
+ "riskId",
22
+ "category",
23
+ ],
24
+ ]
25
+ _parent_id_field = "riskId"
26
+ # Required fields (Nullable = "NO")
27
+ id: int
28
+ analysis: str = ""
29
+ riskTrend: str = ""
30
+ costImpact: float = 0.0
31
+ scheduleImpact: int = 0
32
+ dateAssessed: str = ""
33
+ riskId: int
34
+ isPublic: bool = True
35
+ difference: float = 0.0
36
+ inherentConsequence: str
37
+ inherentProbability: str
38
+ inherentRiskScore: float = 0.0
39
+
40
+ residualConsequence: str
41
+ residualProbability: str
42
+ residualRisk: str
43
+ residualRiskScore: float = 0.0
44
+
45
+ targetRiskScore: float = 0.0
46
+
47
+ annualLossExpectancy: float = 0.0
48
+
49
+ expectedLost: float = 0.0
50
+
51
+ lossEventFrequency: float = 0.0
52
+
53
+ maximumLoss: float = 0.0
54
+
55
+ minimumLoss: float = 0.0
56
+
57
+ riskExposure: float = 0.0
58
+ threatEventFrequency: float = 0.0
59
+
60
+ # Optional fields (Nullable = "YES")
61
+ uuid: Optional[str] = None
62
+ mitigationEffectiveness: Optional[str] = None
63
+ threatChanges: Optional[str] = None
64
+ impactDescription: Optional[str] = None
65
+ operationalRequirements: Optional[str] = None
66
+ riskStrategy: Optional[str] = None
67
+ assumptions: Optional[str] = None
@@ -27,6 +27,7 @@ class PaginatedGraphQLClient:
27
27
  headers: Optional[Dict[str, str]] = None,
28
28
  logging_level: str = logging.CRITICAL,
29
29
  ) -> None:
30
+ from regscale.integrations.variables import ScannerVariables
30
31
  from gql import gql, Client # Optimize import performance
31
32
  from gql.transport.requests import RequestsHTTPTransport
32
33
  from gql.transport.requests import log as requests_logger
@@ -35,7 +36,7 @@ class PaginatedGraphQLClient:
35
36
  self.endpoint = endpoint
36
37
  self.query = gql(query)
37
38
  self.headers = headers or {} # Ensure headers are a dictionary
38
- self.transport = RequestsHTTPTransport(url=endpoint, headers=self.headers)
39
+ self.transport = RequestsHTTPTransport(url=endpoint, headers=self.headers, verify=ScannerVariables.sslVerify)
39
40
  self.client = Client(transport=self.transport)
40
41
  self.job_progress = create_progress_object()
41
42
  requests_logger.setLevel(level=self.log_level)