regscale-cli 6.19.2.0__py3-none-any.whl → 6.20.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 (31) 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/synqly/assets.py +26 -0
  8. regscale/integrations/public/fedramp/appendix_parser.py +499 -104
  9. regscale/integrations/public/fedramp/fedramp_cis_crm.py +5 -3
  10. regscale/integrations/public/fedramp/fedramp_five.py +89 -43
  11. regscale/models/integration_models/cisa_kev_data.json +277 -22
  12. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  13. regscale/models/regscale_models/__init__.py +7 -0
  14. regscale/models/regscale_models/business_impact_assessment.py +71 -0
  15. regscale/models/regscale_models/control_implementation.py +15 -0
  16. regscale/models/regscale_models/evidence.py +72 -4
  17. regscale/models/regscale_models/evidence_mapping.py +1 -1
  18. regscale/models/regscale_models/master_assessment.py +19 -0
  19. regscale/models/regscale_models/policy.py +90 -0
  20. regscale/models/regscale_models/question.py +30 -2
  21. regscale/models/regscale_models/questionnaire.py +4 -3
  22. regscale/models/regscale_models/questionnaire_instance.py +37 -14
  23. regscale/models/regscale_models/rbac.py +0 -1
  24. regscale/models/regscale_models/risk_trend.py +67 -0
  25. regscale/models/regscale_models/task.py +14 -1
  26. {regscale_cli-6.19.2.0.dist-info → regscale_cli-6.20.1.0.dist-info}/METADATA +114 -55
  27. {regscale_cli-6.19.2.0.dist-info → regscale_cli-6.20.1.0.dist-info}/RECORD +31 -28
  28. {regscale_cli-6.19.2.0.dist-info → regscale_cli-6.20.1.0.dist-info}/LICENSE +0 -0
  29. {regscale_cli-6.19.2.0.dist-info → regscale_cli-6.20.1.0.dist-info}/WHEEL +0 -0
  30. {regscale_cli-6.19.2.0.dist-info → regscale_cli-6.20.1.0.dist-info}/entry_points.txt +0 -0
  31. {regscale_cli-6.19.2.0.dist-info → regscale_cli-6.20.1.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 *
@@ -21,6 +22,8 @@ from .control_test_result import *
21
22
  from .custom_field import *
22
23
  from .data import *
23
24
  from .data_center import *
25
+ from .evidence import *
26
+ from .evidence_mapping import *
24
27
  from .email import *
25
28
  from .facility import *
26
29
  from .file import *
@@ -32,9 +35,11 @@ from .interconnection import *
32
35
  from .issue import *
33
36
  from .leveraged_authorization import *
34
37
  from .link import *
38
+ from .master_assessment import *
35
39
  from .meta_data import *
36
40
  from .objective import *
37
41
  from .parameter import *
42
+ from .policy import *
38
43
  from .ports_protocol import *
39
44
  from .privacy import *
40
45
  from .profile import *
@@ -48,6 +53,7 @@ from .questionnaire_instance import *
48
53
  from .reference import *
49
54
  from .requirement import *
50
55
  from .risk import *
56
+ from .risk_trend import *
51
57
  from .sbom import *
52
58
  from .scan_history import *
53
59
  from .security_control import *
@@ -55,6 +61,7 @@ from .security_plan import *
55
61
  from .software_inventory import *
56
62
  from .stake_holder import *
57
63
  from .stig import *
64
+ from .supply_chain import *
58
65
  from .system_role import *
59
66
  from .system_role_external_assignment import *
60
67
  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
 
@@ -3,8 +3,10 @@
3
3
  """Class for evidence model in RegScale platform"""
4
4
 
5
5
  from typing import Optional
6
+
6
7
  from pydantic import ConfigDict, Field
7
8
 
9
+ from regscale.core.app.utils.app_utils import get_current_datetime
8
10
  from regscale.models.regscale_models.regscale_model import RegScaleModel
9
11
 
10
12
 
@@ -12,7 +14,7 @@ class Evidence(RegScaleModel):
12
14
  """Evidence Model"""
13
15
 
14
16
  _module_slug = "evidence"
15
- _unique_fields: list[str] = [["title"]]
17
+ _unique_fields = [["title"]]
16
18
 
17
19
  id: int = 0
18
20
  isPublic: Optional[bool] = True
@@ -20,9 +22,14 @@ class Evidence(RegScaleModel):
20
22
  title: Optional[str] = None
21
23
  description: Optional[str] = None
22
24
  evidenceOwnerId: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
25
+ evidenceApproverId: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
26
+ status: Optional[str] = None
23
27
  updateFrequency: Optional[int] = 365
24
- lastEvidenceUpdate: Optional[str] = None # YY-mm-dd
25
- dueDate: Optional[str] = None # YY-mm-dd
28
+ lastEvidenceUpdate: Optional[str] = Field(default_factory=get_current_datetime)
29
+ dueDate: Optional[str] = Field(default_factory=get_current_datetime)
30
+ dateLastApproved: Optional[str] = Field(default_factory=get_current_datetime)
31
+
32
+ _unique_fields = ["title"]
26
33
 
27
34
  @staticmethod
28
35
  def _get_additional_endpoints() -> ConfigDict:
@@ -42,6 +49,67 @@ class Evidence(RegScaleModel):
42
49
  get_evidence_by_security_plan="/api/{model_slug}/getEvidenceBySecurityPlan/{intId}",
43
50
  filter_evidence="/api/{model_slug}/filterEvidence",
44
51
  query_by_custom_field="/api/{model_slug}/queryByCustomField/{strFieldName}/{strValue}",
45
- mega_api="/api/{model_slug}/megaApi/{intId}",
46
52
  get_my_evidence_due_soon="/api/{model_slug}/getMyEvidenceDueSoon/{intDays}/{intPage}/{intPageSize}",
47
53
  )
54
+
55
+ @classmethod
56
+ def filter_evidence(
57
+ cls,
58
+ field: Optional[str] = None,
59
+ type: Optional[str] = None,
60
+ operator: Optional[str] = None,
61
+ value: Optional[str] = None,
62
+ page: Optional[int] = 1,
63
+ page_size: Optional[int] = 10,
64
+ ) -> list:
65
+ """
66
+ Filter evidence based on the given filter parameters.
67
+
68
+ :param Optional[str] field: Filter field
69
+ :param Optional[str] type: Filter type
70
+ :param Optional[str] operator: Filter operator
71
+ :param Optional[str] value: Filter value
72
+ :param Optional[int] page: Page number, defaults to 1
73
+ :param Optional[int] page_size: Page size, defaults to 10
74
+ :return: A list of filtered evidence
75
+ :rtype: list
76
+ """
77
+ query = {
78
+ "parentID": 0,
79
+ "module": "",
80
+ "friendlyName": "",
81
+ "workbench": "",
82
+ "base": "",
83
+ "sort": "dueDate",
84
+ "direction": "Ascending",
85
+ "simpleSearch": "",
86
+ "page": "",
87
+ "pageSize": "",
88
+ "query": {
89
+ "id": 0,
90
+ "viewName": "",
91
+ "module": "",
92
+ "scope": "",
93
+ "createdById": "",
94
+ "dateCreated": "",
95
+ "parameters": [
96
+ {"id": 0, "field": "", "type": "", "operator": "", "value": "", "viewName": "", "name": ""}
97
+ ],
98
+ },
99
+ "groupBy": "",
100
+ "intDays": 0,
101
+ "subTab": False,
102
+ }
103
+ query["page"] = page
104
+ query["pageSize"] = page_size
105
+ query["query"]["parameters"][0]["field"] = field
106
+ query["query"]["parameters"][0]["type"] = type
107
+ query["query"]["parameters"][0]["operator"] = operator
108
+ query["query"]["parameters"][0]["value"] = value
109
+
110
+ response = cls._get_api_handler().post(
111
+ endpoint=cls.get_endpoint("filter_evidence").format(module_slug=cls._module_slug), data=query
112
+ )
113
+ if not response.raise_for_status():
114
+ return response.json()
115
+ return []
@@ -34,7 +34,7 @@ class EvidenceMapping(RegScaleModel):
34
34
  :rtype: ConfigDict
35
35
  """
36
36
  return ConfigDict(
37
- get_all_by_evidence="/api/{model_slug}/getAllByEvudence/{intID}",
37
+ get_all_by_parent="/api/{model_slug}/getAllByEvidence/{intParentID}",
38
38
  get_summary_by_evidence="/api/{model_slug}/getSummaryByEvidence/{intID}",
39
39
  batch_create="/api/{model_slug}/batchCreate",
40
40
  )
@@ -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
@@ -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
@@ -2,7 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  """Model for Task in the application"""
4
4
 
5
- from typing import Optional, List
5
+ from typing import List, Optional
6
6
 
7
7
  from pydantic import ConfigDict, Field, field_validator
8
8
 
@@ -61,6 +61,19 @@ class Task(RegScaleModel):
61
61
  get_by_date_range="/api/{model_slug}/getByDateRangeAll/{dtStart}/{dtEnd}",
62
62
  )
63
63
 
64
+ @classmethod
65
+ def other_identifier_starts_with(cls, starts_with: str) -> List["Task"]:
66
+ """
67
+ Get tasks based on otherIdentifier field, starts with.
68
+
69
+ :param str starts_with: The starting characters of a string.
70
+ :return: A list of Task instances matching the query
71
+ :rtype: List[Task]
72
+ """
73
+ endpoint = cls.get_endpoint("other_identifier_starts_with").format(strId=starts_with)
74
+ response = cls._get_api_handler().get(endpoint=endpoint)
75
+ return cls._handle_list_response(response)
76
+
64
77
  @classmethod
65
78
  def query_by_custom_field(cls, field_name: str, field_value: str) -> List["Task"]:
66
79
  """