regscale-cli 6.20.9.1__py3-none-any.whl → 6.21.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 (56) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/application.py +12 -5
  3. regscale/core/app/internal/set_permissions.py +58 -27
  4. regscale/integrations/commercial/defender.py +9 -0
  5. regscale/integrations/commercial/nessus/scanner.py +2 -0
  6. regscale/integrations/commercial/sonarcloud.py +35 -36
  7. regscale/integrations/commercial/synqly/ticketing.py +51 -0
  8. regscale/integrations/commercial/wizv2/async_client.py +325 -0
  9. regscale/integrations/commercial/wizv2/constants.py +756 -0
  10. regscale/integrations/commercial/wizv2/scanner.py +1301 -89
  11. regscale/integrations/commercial/wizv2/utils.py +280 -36
  12. regscale/integrations/commercial/wizv2/variables.py +2 -10
  13. regscale/integrations/integration_override.py +15 -6
  14. regscale/integrations/scanner_integration.py +221 -37
  15. regscale/integrations/variables.py +1 -0
  16. regscale/models/integration_models/amazon_models/inspector_scan.py +32 -57
  17. regscale/models/integration_models/aqua.py +92 -78
  18. regscale/models/integration_models/cisa_kev_data.json +47 -4
  19. regscale/models/integration_models/defenderimport.py +64 -59
  20. regscale/models/integration_models/ecr_models/ecr.py +100 -147
  21. regscale/models/integration_models/flat_file_importer/__init__.py +52 -38
  22. regscale/models/integration_models/ibm.py +29 -47
  23. regscale/models/integration_models/nexpose.py +156 -68
  24. regscale/models/integration_models/prisma.py +46 -66
  25. regscale/models/integration_models/qualys.py +99 -93
  26. regscale/models/integration_models/snyk.py +229 -158
  27. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  28. regscale/models/integration_models/veracode.py +15 -20
  29. regscale/models/integration_models/xray.py +276 -82
  30. regscale/models/regscale_models/__init__.py +13 -0
  31. regscale/models/regscale_models/classification.py +23 -0
  32. regscale/models/regscale_models/control_implementation.py +14 -12
  33. regscale/models/regscale_models/cryptography.py +56 -0
  34. regscale/models/regscale_models/deviation.py +4 -4
  35. regscale/models/regscale_models/group.py +3 -2
  36. regscale/models/regscale_models/interconnection.py +1 -1
  37. regscale/models/regscale_models/issue.py +140 -41
  38. regscale/models/regscale_models/milestone.py +40 -0
  39. regscale/models/regscale_models/property.py +0 -1
  40. regscale/models/regscale_models/rbac.py +22 -0
  41. regscale/models/regscale_models/regscale_model.py +29 -18
  42. regscale/models/regscale_models/team.py +55 -0
  43. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/METADATA +1 -1
  44. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/RECORD +56 -49
  45. tests/fixtures/test_fixture.py +58 -2
  46. tests/regscale/core/test_app.py +5 -3
  47. tests/regscale/integrations/test_integration_mapping.py +522 -40
  48. tests/regscale/integrations/test_issue_due_date.py +1 -1
  49. tests/regscale/integrations/test_property_and_milestone_creation.py +684 -0
  50. tests/regscale/integrations/test_update_finding_dates.py +336 -0
  51. tests/regscale/models/test_asset.py +406 -50
  52. tests/regscale/models/test_report.py +105 -29
  53. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/LICENSE +0 -0
  54. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/WHEEL +0 -0
  55. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/entry_points.txt +0 -0
  56. {regscale_cli-6.20.9.1.dist-info → regscale_cli-6.21.0.0.dist-info}/top_level.txt +0 -0
@@ -5,9 +5,7 @@ from typing import List, Optional
5
5
  from pydantic import ConfigDict, Field
6
6
 
7
7
  from regscale.core.app.utils.app_utils import get_current_datetime
8
-
9
- from .. import Property
10
- from .regscale_model import RegScaleModel
8
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
11
9
 
12
10
  logger = logging.getLogger("regscale")
13
11
 
@@ -143,7 +141,7 @@ class Deviation(RegScaleModel):
143
141
  return []
144
142
 
145
143
  @classmethod
146
- def get_dr_ids(cls, issue_id: int) -> Optional[Property]:
144
+ def get_dr_ids(cls, issue_id: int) -> Optional["Property"]:
147
145
  """
148
146
  Get a list of control implementations by plan ID.
149
147
 
@@ -151,6 +149,8 @@ class Deviation(RegScaleModel):
151
149
  :return: A single Property object with the DR number if it exists or None
152
150
  :rtype: Optional[Property]
153
151
  """
152
+ from regscale.models import Property
153
+
154
154
  properties = [
155
155
  prop
156
156
  for prop in Property.get_all_by_parent(parent_id=issue_id, parent_module="issues")
@@ -8,11 +8,12 @@ from typing import Optional, List, Tuple, cast
8
8
  from pydantic import ConfigDict, Field
9
9
 
10
10
  from regscale.core.app.utils.app_utils import get_current_datetime
11
- from regscale.models import User, deprecated
11
+ from regscale.utils.decorators import deprecated
12
12
  from regscale.models.regscale_models.regscale_model import RegScaleModel, T
13
+ from regscale.models.regscale_models.user import User
13
14
  from regscale.models.regscale_models.user_group import UserGroup
14
15
 
15
- logger = logging.getLogger(__name__)
16
+ logger = logging.getLogger("regscale")
16
17
 
17
18
 
18
19
  class Group(RegScaleModel):
@@ -19,7 +19,7 @@ class InterConnection(RegScaleModel):
19
19
  name: str
20
20
  organization: str
21
21
  status: str
22
- aOId: str
22
+ aoId: str
23
23
  interconnectOwnerId: str
24
24
  parentId: int = 0
25
25
  parentModule: Optional[str] = None
@@ -2,6 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  """Model for a RegScale Issue"""
4
4
  import datetime
5
+ import time
5
6
  from collections import defaultdict
6
7
  from concurrent.futures import ThreadPoolExecutor, as_completed
7
8
  from enum import Enum
@@ -25,6 +26,11 @@ from regscale.models.regscale_models.regscale_model import RegScaleModel
25
26
  from regscale.utils.version import RegscaleVersion
26
27
 
27
28
 
29
+ # Module-level cache for open issues - avoids Pydantic conflicts
30
+ _OPEN_ISSUES_CACHE: Dict[int, Tuple[float, Dict[int, List["OpenIssueDict"]]]] = {}
31
+ _CACHE_TTL: float = 300.0 # 5 minutes TTL in seconds
32
+
33
+
28
34
  class OpenIssueDict(TypedDict):
29
35
  """TypedDict for open issues"""
30
36
 
@@ -280,6 +286,59 @@ class Issue(RegScaleModel):
280
286
  "find_by_integration_finding_id": "/api/{model_slug}/findByIntegrationFindingId/{id}",
281
287
  }
282
288
 
289
+ @classmethod
290
+ def _is_cache_valid(cls, plan_id: int) -> bool:
291
+ """
292
+ Check if cached data for a plan_id is still valid
293
+
294
+ :param int plan_id: The plan ID to check cache validity for
295
+ :return: True if cache is valid, False otherwise
296
+ :rtype: bool
297
+ """
298
+ if plan_id not in _OPEN_ISSUES_CACHE:
299
+ return False
300
+
301
+ cached_time, _ = _OPEN_ISSUES_CACHE[plan_id]
302
+ return (time.time() - cached_time) < _CACHE_TTL
303
+
304
+ @classmethod
305
+ def _get_from_cache(cls, plan_id: int) -> Optional[Dict[int, List[OpenIssueDict]]]:
306
+ """
307
+ Get cached data for a plan_id if it exists and is valid
308
+
309
+ :param int plan_id: The plan ID to get cached data for
310
+ :return: Cached data if valid, None otherwise
311
+ :rtype: Optional[Dict[int, List[OpenIssueDict]]]
312
+ """
313
+ if cls._is_cache_valid(plan_id):
314
+ _, cached_data = _OPEN_ISSUES_CACHE[plan_id]
315
+ return cached_data
316
+ return None
317
+
318
+ @classmethod
319
+ def _cache_data(cls, plan_id: int, data: Dict[int, List[OpenIssueDict]]) -> None:
320
+ """
321
+ Cache data for a plan_id
322
+
323
+ :param int plan_id: The plan ID to cache data for
324
+ :param Dict[int, List[OpenIssueDict]] data: The data to cache
325
+ :rtype: None
326
+ """
327
+ _OPEN_ISSUES_CACHE[plan_id] = (time.time(), data)
328
+
329
+ @classmethod
330
+ def clear_cache(cls, plan_id: Optional[int] = None) -> None:
331
+ """
332
+ Clear cache for a specific plan_id or all cached data
333
+
334
+ :param Optional[int] plan_id: The plan ID to clear cache for, or None to clear all cache
335
+ :rtype: None
336
+ """
337
+ if plan_id is not None:
338
+ _OPEN_ISSUES_CACHE.pop(plan_id, None)
339
+ else:
340
+ _OPEN_ISSUES_CACHE.clear()
341
+
283
342
  @classmethod
284
343
  def find_by_other_identifier(cls, other_identifier: str) -> List["Issue"]:
285
344
  """
@@ -826,70 +885,110 @@ class Issue(RegScaleModel):
826
885
  cls, plan_id: int, is_component: Optional[bool] = False
827
886
  ) -> Dict[int, List[OpenIssueDict]]:
828
887
  """
829
- Get all open issues by implementation id for a given security plan
888
+ Get all open issues by implementation id for a given security plan with optimized performance and caching
830
889
 
831
890
  :param int plan_id: The ID of the parent
891
+ :param bool is_component: Optional[bool] Defaults to False
832
892
  :return: A dictionary of control ids and their associated issue ids
833
893
  :rtype: Dict[int, List[OpenIssueDict]]
834
894
  """
835
895
  import logging
836
896
 
897
+ cache_disabled = cls._is_cache_disabled()
898
+ use_cache: bool = not cache_disabled
899
+
837
900
  logger = logging.getLogger("regscale")
838
- take = 50
901
+ # Check cache first
902
+ if use_cache:
903
+ cached_data = cls._get_from_cache(plan_id)
904
+ if cached_data is not None:
905
+ logger.info(f"Using cached open issues data for security plan {plan_id}")
906
+ return cached_data
907
+
908
+ # Performance optimization: Use larger batch size and optimize query
909
+ take = 50 # Increased from 50 to reduce API roundtrips
839
910
  skip = 0
840
911
  control_issues: Dict[int, List[OpenIssueDict]] = defaultdict(list)
912
+
913
+ start_time = time.time()
914
+ logger.info(f"Fetching open issues for controls and for security plan {plan_id}...")
915
+
841
916
  module_str = "component" if is_component else "security plan"
842
917
  logger.info(
843
918
  f"Fetching open issues for controls and for {module_str} {plan_id}...",
844
919
  )
845
920
  supports_multiple_controls: bool = cls.is_multiple_controls_supported()
846
921
 
847
- # Define fields based on version
848
- fields = """
849
- id,
850
- controlId
851
- otherIdentifier
852
- {extra_fields}
853
- """.format(
854
- extra_fields="controlImplementations { id }" if supports_multiple_controls else ""
855
- )
922
+ # Optimize field selection - only get what we need
923
+ if supports_multiple_controls:
924
+ fields = "id, otherIdentifier, integrationFindingId, controlImplementations { id }"
925
+ else:
926
+ fields = "id, controlId, otherIdentifier, integrationFindingId"
927
+
928
+ total_fetched = 0
856
929
 
857
- while True:
858
- query = f"""
859
- query MyQuery() {{
860
- {cls.get_module_string()}(
861
- skip: {skip},
862
- take: {take},
863
- where: {{
864
- {"componentId" if is_component else "securityPlanId"}: {{eq: {plan_id}}},
865
- status: {{eq: "Open"}}
930
+ try:
931
+ while True:
932
+ query = f"""
933
+ query GetOpenIssuesByPlanOrComponent {{
934
+ {cls.get_module_string()}(
935
+ skip: {skip},
936
+ take: {take},
937
+ where: {{
938
+ {"componentId" if is_component else "securityPlanId"}: {{eq: {plan_id}}},
939
+ status: {{eq: "Open"}}
940
+ }}
941
+ ) {{
942
+ items {{ {fields} }}
943
+ pageInfo {{ hasNextPage }}
944
+ totalCount
866
945
  }}
867
- ) {{
868
- items {{ {fields} }}
869
- pageInfo {{ hasNextPage }}
870
- totalCount
871
946
  }}
872
- }}
873
- """
947
+ """
874
948
 
875
- response = cls._get_api_handler().graph(query)
876
- items = response.get(cls.get_module_string(), {}).get("items", [])
949
+ response = cls._get_api_handler().graph(query)
950
+ items = response.get(cls.get_module_string(), {}).get("items", [])
951
+ total_count = response.get(cls.get_module_string(), {}).get("totalCount", 0)
877
952
 
878
- for item in items:
879
- if supports_multiple_controls and item.get("controlImplementations"):
880
- for control in item.get("controlImplementations", []):
881
- control_issues[control["id"]].append(
882
- OpenIssueDict(id=item["id"], otherIdentifier=item["otherIdentifier"])
883
- )
884
- else:
885
- control_issues[item["controlId"]].append(
886
- OpenIssueDict(id=item["id"], otherIdentifier=item["otherIdentifier"])
953
+ # Log progress for large datasets
954
+ if total_count > 1000:
955
+ logger.info(
956
+ f"Processing batch {skip // take + 1} - fetched {len(items)} items ({skip + len(items)}/{total_count})"
957
+ )
958
+
959
+ for item in items:
960
+ issue_dict = OpenIssueDict(
961
+ id=item["id"],
962
+ otherIdentifier=item.get("otherIdentifier", ""),
963
+ integrationFindingId=item.get("integrationFindingId", ""),
887
964
  )
888
965
 
889
- if not response.get(cls.get_module_string(), {}).get("pageInfo", {}).get("hasNextPage", False):
890
- break
891
- skip += take
892
- logger.info("Finished fetching %i open control issue(s) for %s %i", len(control_issues), module_str, plan_id)
966
+ if supports_multiple_controls and item.get("controlImplementations"):
967
+ for control in item.get("controlImplementations", []):
968
+ control_issues[control["id"]].append(issue_dict)
969
+ elif item.get("controlId"):
970
+ control_issues[item["controlId"]].append(issue_dict)
971
+
972
+ total_fetched += len(items)
973
+ if not response.get(cls.get_module_string(), {}).get("pageInfo", {}).get("hasNextPage", False):
974
+ break
975
+ skip += take
976
+
977
+ except Exception as e:
978
+ logger.error(f"Error fetching open issues for security plan {plan_id}: {e}")
979
+ # Return empty dict on error to prevent breaking the calling code
980
+ return defaultdict(list)
981
+
982
+ elapsed_time = time.time() - start_time
983
+ logger.info(
984
+ f"Finished fetching {total_fetched} open issue(s) for {len(control_issues)} control(s) "
985
+ f"in security plan {plan_id} - took {elapsed_time:.2f} seconds"
986
+ )
987
+
988
+ # Cache the results
989
+ if use_cache:
990
+ cls._cache_data(plan_id, control_issues)
991
+
893
992
  return control_issues
894
993
 
895
994
  @classmethod
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Class for milestone model in RegScale platform"""
4
+
5
+ from typing import Optional
6
+ from pydantic import ConfigDict, Field
7
+
8
+ from regscale.core.app.utils.app_utils import get_current_datetime
9
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
10
+
11
+
12
+ class Milestone(RegScaleModel):
13
+ """Milestone Model"""
14
+
15
+ _module_slug = "milestones"
16
+ _module_string = "milestones"
17
+
18
+ title: str
19
+ id: int = 0
20
+ isPublic: Optional[bool] = True
21
+ milestoneDate: Optional[str] = Field(default_factory=get_current_datetime)
22
+ responsiblePersonId: Optional[str] = None
23
+ predecessorStepId: Optional[int] = 0
24
+ completed: Optional[bool] = False
25
+ dateCompleted: Optional[str] = Field(default_factory=get_current_datetime)
26
+ notes: Optional[str] = ""
27
+ parentID: Optional[int] = None
28
+ parentModule: str = ""
29
+
30
+ @staticmethod
31
+ def _get_additional_endpoints() -> ConfigDict:
32
+ """
33
+ Get additional endpoints for the Milestone model
34
+
35
+ :return: A dictionary of additional endpoints
36
+ :rtype: ConfigDict
37
+ """
38
+ return ConfigDict(
39
+ get_all_by_parent="/api/{model_slug}/getAllByParent/{intParentID}",
40
+ )
@@ -10,7 +10,6 @@ from pydantic import ConfigDict, Field, field_validator
10
10
 
11
11
  from regscale.core.app.api import Api
12
12
  from regscale.core.app.application import Application
13
- from regscale.core.app.internal.model_editor import get_all_by_parent
14
13
  from regscale.core.app.utils.app_utils import get_current_datetime, recursive_items
15
14
  from regscale.models.regscale_models.regscale_model import RegScaleModel
16
15
  from regscale.utils import flatten_dict
@@ -28,6 +28,7 @@ class RBAC(RegScaleModel):
28
28
  add="/api/{model_slug}/add/{moduleId}/{parentId}/{groupId}/{permissionType}",
29
29
  public="/api/{model_slug}/public/{moduleId}/{parentId}/{public}",
30
30
  none_standard_delete="/api/{model_slug}/{moduleId}/{parentId}/{rbacId}",
31
+ reset="/api/{model_slug}/reset/{moduleId}/{parentId}",
31
32
  )
32
33
 
33
34
  @classmethod
@@ -129,3 +130,24 @@ class RBAC(RegScaleModel):
129
130
  else:
130
131
  cls.log_response_error(response=response)
131
132
  return False
133
+
134
+ @classmethod
135
+ def reset(cls, module_id: int, parent_id: int) -> bool:
136
+ """
137
+ Proliferates the RBAC entry to all its children
138
+
139
+ :param int module_id: The ID of the module
140
+ :param int parent_id: The ID of the parent
141
+ :return: True if the RBAC entry was added, False otherwise
142
+ :rtype: bool
143
+ """
144
+ response = cls._get_api_handler().get(
145
+ endpoint=cls.get_endpoint("reset").format(
146
+ model_slug=cls._module_slug, moduleId=module_id, parentId=parent_id
147
+ )
148
+ )
149
+ if response and response.ok:
150
+ return True
151
+ else:
152
+ cls.log_response_error(response=response)
153
+ return False
@@ -32,8 +32,6 @@ 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
-
37
35
 
38
36
  class RegScaleModel(BaseModel, ABC):
39
37
  """Mixin class for RegScale Models to add functionality to interact with RegScale API"""
@@ -58,6 +56,7 @@ class RegScaleModel(BaseModel, ABC):
58
56
  _parent_cache: ClassVar[Cache] = Cache(maxsize=50000)
59
57
  _lock_registry: ClassVar[ThreadSafeDict] = ThreadSafeDict()
60
58
  _global_lock: ClassVar[threading.Lock] = threading.Lock() # Class-level lock
59
+ _is_disable_cache: ClassVar[Optional[bool]] = None # Class-level cache setting
61
60
 
62
61
  _pending_updates: ClassVar[Dict[str, Set[int]]] = {}
63
62
  _pending_creations: ClassVar[Dict[str, Set[str]]] = {}
@@ -78,17 +77,19 @@ class RegScaleModel(BaseModel, ABC):
78
77
  :rtype: None
79
78
  """
80
79
  try:
81
- global IS_DISABLE_CACHE
82
80
  super().__init__(*args, **data)
83
81
  # Capture initial state after initialization
84
82
  self._original_data = self.dict(exclude_unset=True)
85
- IS_DISABLE_CACHE = self._fetch_disabled_cache_setting()
86
- if IS_DISABLE_CACHE:
83
+ # Initialize cache setting if not already set
84
+ if self.__class__._is_disable_cache is None:
85
+ self.__class__._is_disable_cache = self.__class__._fetch_disabled_cache_setting()
86
+ if self.__class__._is_disable_cache:
87
87
  logger.debug("cache is disabled")
88
88
  except Exception as e:
89
89
  logger.error(f"Error creating {self.__class__.__name__}: {e} {data}", exc_info=True)
90
90
 
91
- def _fetch_disabled_cache_setting(self) -> bool:
91
+ @classmethod
92
+ def _fetch_disabled_cache_setting(cls) -> bool:
92
93
  """
93
94
  Check if caching is disabled based on the application config.
94
95
 
@@ -96,10 +97,22 @@ class RegScaleModel(BaseModel, ABC):
96
97
  :rtype: bool
97
98
  """
98
99
  is_disabled = False
99
- if config := self._get_api_handler().config:
100
+ if config := cls._get_api_handler().config:
100
101
  is_disabled = config.get("disableCache", False)
101
102
  return is_disabled
102
103
 
104
+ @classmethod
105
+ def _is_cache_disabled(cls) -> bool:
106
+ """
107
+ Check if caching is disabled for this class.
108
+
109
+ :return: True if caching is disabled, False otherwise
110
+ :rtype: bool
111
+ """
112
+ if cls._is_disable_cache is None:
113
+ cls._is_disable_cache = cls._fetch_disabled_cache_setting()
114
+ return cls._is_disable_cache
115
+
103
116
  @classmethod
104
117
  def disable_cache(cls) -> bool:
105
118
  """
@@ -108,9 +121,8 @@ class RegScaleModel(BaseModel, ABC):
108
121
  :return: True if caching is disabled, False otherwise
109
122
  :rtype: bool
110
123
  """
111
- global IS_DISABLE_CACHE
112
- IS_DISABLE_CACHE = True
113
- return IS_DISABLE_CACHE
124
+ cls._is_disable_cache = True
125
+ return cls._is_disable_cache
114
126
 
115
127
  @classmethod
116
128
  def enable_cache(cls) -> bool:
@@ -120,9 +132,8 @@ class RegScaleModel(BaseModel, ABC):
120
132
  :return: True if caching is enabled, False otherwise
121
133
  :rtype: bool
122
134
  """
123
- global IS_DISABLE_CACHE
124
- IS_DISABLE_CACHE = False
125
- return IS_DISABLE_CACHE
135
+ cls._is_disable_cache = False
136
+ return cls._is_disable_cache
126
137
 
127
138
  @classmethod
128
139
  def _get_api_handler(cls) -> APIHandler:
@@ -210,7 +221,7 @@ class RegScaleModel(BaseModel, ABC):
210
221
  :return: The cached object if found, None otherwise
211
222
  :rtype: Optional[T]
212
223
  """
213
- if IS_DISABLE_CACHE:
224
+ if cls._is_cache_disabled():
214
225
  return None
215
226
  with cls._get_lock(cache_key):
216
227
  return cls._object_cache.get(cache_key)
@@ -224,7 +235,7 @@ class RegScaleModel(BaseModel, ABC):
224
235
  :return: None
225
236
  :rtype: None
226
237
  """
227
- if IS_DISABLE_CACHE:
238
+ if cls._is_cache_disabled():
228
239
  return
229
240
  try:
230
241
  if not obj:
@@ -274,7 +285,7 @@ class RegScaleModel(BaseModel, ABC):
274
285
  :return: None
275
286
  :rtype: None
276
287
  """
277
- if IS_DISABLE_CACHE:
288
+ if cls._is_cache_disabled():
278
289
  return
279
290
  parent_id = getattr(obj, cls._parent_id_field, None)
280
291
  parent_module = getattr(obj, "parentModule", getattr(obj, "parent_module", ""))
@@ -299,7 +310,7 @@ class RegScaleModel(BaseModel, ABC):
299
310
  :return: None
300
311
  :rtype: None
301
312
  """
302
- if IS_DISABLE_CACHE:
313
+ if cls._is_cache_disabled():
303
314
  return
304
315
  with cls._get_lock(cache_key):
305
316
  for obj in objects:
@@ -325,7 +336,7 @@ class RegScaleModel(BaseModel, ABC):
325
336
  :return: None
326
337
  :rtype: None
327
338
  """
328
- if IS_DISABLE_CACHE:
339
+ if cls._is_cache_disabled():
329
340
  return
330
341
  cache_key = cls._get_cache_key(obj)
331
342
  with cls._get_lock(cache_key):
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for Teams in the application"""
4
+
5
+ from typing import Optional, Union
6
+
7
+ from pydantic import ConfigDict
8
+
9
+ from regscale.core.app.api import Api
10
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
11
+
12
+
13
+ class Team(RegScaleModel):
14
+ _module_slug = "teams"
15
+
16
+ id: Optional[int] = None
17
+ member: Optional[str] = None
18
+ memberId: Optional[str] = None
19
+ memberType: Optional[str] = None
20
+ bExecutive: Optional[bool] = False
21
+ bOversight: Optional[bool] = False
22
+ bCommunications: Optional[bool] = False
23
+ bEngineer: Optional[bool] = False
24
+ bAssessor: Optional[bool] = False
25
+ bQuality: Optional[bool] = False
26
+ bSafety: Optional[bool] = False
27
+ bSecurity: Optional[bool] = False
28
+ bAnalyst: Optional[bool] = False
29
+ bScheduler: Optional[bool] = False
30
+ bAdministrative: Optional[bool] = False
31
+ bProjectManager: Optional[bool] = False
32
+ bFinance: Optional[bool] = False
33
+ bHumanResources: Optional[bool] = False
34
+ bOperations: Optional[bool] = False
35
+ bISSO: Optional[bool] = False
36
+ bISSM: Optional[bool] = False
37
+ bAO: Optional[bool] = False
38
+ bCISO: Optional[bool] = False
39
+ bSCA: Optional[bool] = False
40
+ bDevOps: Optional[bool] = False
41
+ bProgrammer: Optional[bool] = False
42
+ bSystemOwner: Optional[bool] = False
43
+ bRiskAnalyst: Optional[bool] = False
44
+ bInternalAudit: Optional[bool] = False
45
+ bExternalAudit: Optional[bool] = False
46
+ bInformationOwner: Optional[bool] = False
47
+ bAODR: Optional[bool] = False
48
+ bContingencyCoordinator: Optional[bool] = False
49
+ bContingencyDirector: Optional[bool] = False
50
+ bResponsible: Optional[bool] = False
51
+ bAccountable: Optional[bool] = False
52
+ bConsulted: Optional[bool] = False
53
+ bInformed: Optional[bool] = False
54
+ parentId: Optional[int] = None
55
+ parentModule: Optional[str] = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: regscale-cli
3
- Version: 6.20.9.1
3
+ Version: 6.21.0.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