regscale-cli 6.27.0.1__py3-none-any.whl → 6.27.2.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 (26) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/utils/app_utils.py +41 -7
  3. regscale/integrations/commercial/aws/scanner.py +3 -2
  4. regscale/integrations/commercial/microsoft_defender/defender_api.py +1 -1
  5. regscale/integrations/commercial/sicura/api.py +65 -29
  6. regscale/integrations/commercial/sicura/scanner.py +36 -7
  7. regscale/integrations/commercial/tenablev2/commands.py +4 -4
  8. regscale/integrations/commercial/tenablev2/scanner.py +1 -2
  9. regscale/integrations/commercial/wizv2/scanner.py +40 -16
  10. regscale/integrations/public/cci_importer.py +400 -9
  11. regscale/models/integration_models/aqua.py +2 -2
  12. regscale/models/integration_models/cisa_kev_data.json +164 -3
  13. regscale/models/integration_models/flat_file_importer/__init__.py +4 -6
  14. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  15. regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +11 -10
  16. regscale/models/integration_models/synqly_models/ocsf_mapper.py +48 -8
  17. regscale/models/integration_models/synqly_models/synqly_model.py +34 -12
  18. {regscale_cli-6.27.0.1.dist-info → regscale_cli-6.27.2.0.dist-info}/METADATA +1 -1
  19. {regscale_cli-6.27.0.1.dist-info → regscale_cli-6.27.2.0.dist-info}/RECORD +26 -26
  20. tests/regscale/integrations/commercial/test_sicura.py +0 -1
  21. tests/regscale/integrations/commercial/wizv2/test_wizv2.py +86 -0
  22. tests/regscale/integrations/public/test_cci.py +596 -1
  23. {regscale_cli-6.27.0.1.dist-info → regscale_cli-6.27.2.0.dist-info}/LICENSE +0 -0
  24. {regscale_cli-6.27.0.1.dist-info → regscale_cli-6.27.2.0.dist-info}/WHEEL +0 -0
  25. {regscale_cli-6.27.0.1.dist-info → regscale_cli-6.27.2.0.dist-info}/entry_points.txt +0 -0
  26. {regscale_cli-6.27.0.1.dist-info → regscale_cli-6.27.2.0.dist-info}/top_level.txt +0 -0
@@ -122,16 +122,6 @@ class Vulnerabilities(SynqlyModel):
122
122
  if asset_filter:
123
123
  self.logger.debug(f"Asset filter: {asset_filter}")
124
124
 
125
- self.logger.info(f"Fetching vulnerability data from {self.integration_name}...")
126
- findings = (
127
- self.fetch_integration_data(
128
- func=self.tenant.engine_client.vulnerabilities.query_findings,
129
- filter=vuln_filter, # Only severity/date filters for findings
130
- **kwargs,
131
- )
132
- if self.can_fetch_vulns
133
- else []
134
- )
135
125
  self.logger.info(f"Fetching asset data from {self.integration_name}...")
136
126
  assets = (
137
127
  self.fetch_integration_data(
@@ -143,6 +133,17 @@ class Vulnerabilities(SynqlyModel):
143
133
  else []
144
134
  )
145
135
 
136
+ self.logger.info(f"Fetching vulnerability data from {self.integration_name}...")
137
+ findings = (
138
+ self.fetch_integration_data(
139
+ func=self.tenant.engine_client.vulnerabilities.query_findings,
140
+ filter=vuln_filter, # Only severity/date filters for findings
141
+ **kwargs,
142
+ )
143
+ if self.can_fetch_vulns
144
+ else []
145
+ )
146
+
146
147
  self.scanner_integration = VulnerabilitiesIntegration(plan_id=regscale_ssp_id)
147
148
  self.logger.info(f"Mapping {self.provider} asset(s) data to RegScale asset(s)...")
148
149
  if assets:
@@ -5,7 +5,11 @@ from typing import Any, Union, TYPE_CHECKING, Optional
5
5
 
6
6
  if TYPE_CHECKING:
7
7
  from regscale.models.integration_models.synqly_models.connectors import Edr, Ticketing, Vulnerabilities
8
- from synqly.engine.resources.ocsf.resources.v_1_3_0.resources.securityfinding import ResourceDetails, Vulnerability
8
+ from synqly.engine.resources.ocsf.resources.v_1_3_0.resources.securityfinding import (
9
+ Finding,
10
+ ResourceDetails,
11
+ Vulnerability,
12
+ )
9
13
 
10
14
  from synqly import engine
11
15
  from synqly.engine import CreateTicketRequest
@@ -152,7 +156,39 @@ class Mapper:
152
156
  )
153
157
 
154
158
  @staticmethod
155
- def _parse_finding_data(finding: "SecurityFinding", vuln: Optional["Vulnerability"] = None) -> dict:
159
+ def _determine_date(
160
+ attribute: str, finding: Optional["Finding"] = None, vuln: Optional["Vulnerability"] = None
161
+ ) -> datetime:
162
+ """
163
+ Determine the date based on the provided vulnerability or finding
164
+
165
+ :param str attribute: The attribute to determine the date for
166
+ :param Optional[SecurityFinding] finding: The finding to determine the date for
167
+ :param Optional[Vulnerability] vuln: The vulnerability to determine the date for
168
+ :return: The date
169
+ :rtype: datetime
170
+ """
171
+ from regscale.core.utils.date import normalize_timestamp
172
+
173
+ vuln_date = getattr(vuln, attribute) if vuln else None
174
+ fallback_vuln_date = getattr(vuln, attribute.replace("_dt", ""), None) if vuln else None
175
+ finding_date = getattr(finding, attribute) if finding else None
176
+ fallback_finding_date = getattr(finding, attribute.replace("_dt", ""), None) if finding else None
177
+ if vuln_date:
178
+ return vuln_date
179
+ elif finding_date:
180
+ return finding_date
181
+ # No datetime objects, lets try the epoch integers
182
+ if fallback_vuln_date:
183
+ fallback_vuln_date = normalize_timestamp(fallback_vuln_date)
184
+ return datetime.fromtimestamp(fallback_vuln_date)
185
+ elif fallback_finding_date:
186
+ fallback_finding_date = normalize_timestamp(fallback_finding_date)
187
+ return datetime.fromtimestamp(fallback_finding_date)
188
+ else:
189
+ return datetime.now()
190
+
191
+ def _parse_finding_data(self, finding: "SecurityFinding", vuln: Optional["Vulnerability"] = None) -> dict:
156
192
  """
157
193
  Parse the data from the SecurityFinding object
158
194
 
@@ -164,16 +200,20 @@ class Mapper:
164
200
 
165
201
  finding_data = {
166
202
  "cve": None,
167
- "first_seen": vuln.first_seen_time_dt if vuln else finding.finding.first_seen_time_dt,
168
- "last_seen": vuln.last_seen_time_dt if vuln else finding.finding.last_seen_time_dt,
203
+ "first_seen": self._determine_date("first_seen_time_dt", getattr(finding, "finding", None), vuln),
204
+ "last_seen": self._determine_date("last_seen_time_dt", getattr(finding, "finding", None), vuln),
169
205
  "plugin_id": vuln.cve.uid if vuln else finding.finding.product_uid,
170
- "severity": int(vuln.severity) if vuln else finding.severity_id,
206
+ "severity": vuln.severity if vuln and getattr(vuln, "severity") else finding.severity_id,
171
207
  "remediation": getattr(vuln, "remediation") if vuln else finding.finding.remediation.desc,
172
208
  }
173
209
  if vuln:
174
210
  finding_data["cve"] = vuln.cve.uid
175
211
  else:
176
212
  finding_data["cve"] = finding.finding.title if "cve" in finding.finding.title.lower() else None
213
+ try:
214
+ finding_data["severity"] = int(finding_data["severity"])
215
+ except ValueError:
216
+ finding_data["severity"] = 0
177
217
  if isinstance(finding_data["remediation"], Remediation):
178
218
  finding_data["remediation"] = finding_data["remediation"].desc
179
219
  elif isinstance(finding_data["remediation"], dict):
@@ -227,9 +267,9 @@ class Mapper:
227
267
  """
228
268
  base = vuln if vuln else finding.finding
229
269
  finding_data = self._parse_finding_data(finding, vuln)
230
- if resource.data:
231
- dns = resource.data.get("hostname")
232
- ip_address = resource.data.get("ipv4")
270
+ if resource_data := getattr(resource, "data"):
271
+ dns = resource_data.get("hostname")
272
+ ip_address = resource_data.get("ipv4")
233
273
  else:
234
274
  dns = resource.uid if vuln else None
235
275
  ip_address = None
@@ -700,10 +700,7 @@ class SynqlyModel(BaseModel, ABC):
700
700
  if query_filter:
701
701
  query_filter = self.validate_filters(query_filter)
702
702
  integration_data: list = []
703
- fetch_res = func(
704
- filter=query_filter,
705
- limit=limit,
706
- )
703
+ fetch_res = self._fetch_data_with_retries(func=func, limit=limit, filter=query_filter)
707
704
  self.logger.info(f"Received {len(fetch_res.result)} record(s) from {self.integration_name}.")
708
705
  integration_data.extend(fetch_res.result)
709
706
  # check and handle pagination
@@ -711,24 +708,49 @@ class SynqlyModel(BaseModel, ABC):
711
708
  try:
712
709
  # fetch.cursor can be an int as a string, or a continuation token
713
710
  while int(fetch_res.cursor) == len(integration_data):
714
- fetch_res = func(
715
- filter=query_filter,
716
- limit=limit,
717
- cursor=fetch_res.cursor,
711
+ fetch_res = self._fetch_data_with_retries(
712
+ func=func, limit=limit, cursor=fetch_res.cursor, filter=query_filter
718
713
  )
719
714
  integration_data.extend(fetch_res.result)
720
715
  except ValueError:
721
716
  while fetch_res.cursor:
722
- fetch_res = func(
723
- filter=query_filter,
724
- limit=limit,
725
- cursor=fetch_res.cursor,
717
+ fetch_res = self._fetch_data_with_retries(
718
+ func=func, limit=limit, cursor=fetch_res.cursor, filter=query_filter
726
719
  )
727
720
  integration_data.extend(fetch_res.result)
728
721
  self.logger.info(f"Received {len(integration_data)} record(s) from {self.integration_name}...")
729
722
  self.logger.info(f"Fetched {len(integration_data)} total record(s) from {self.integration_name}...")
730
723
  return integration_data
731
724
 
725
+ def _fetch_data_with_retries(
726
+ self, func: Callable, limit: int, cursor: Union[str, int, None] = None, filter: Optional[str] = None
727
+ ) -> Any:
728
+ """
729
+ Fetches data from the integration using the provided function and handles pagination
730
+
731
+ :param Callable func: The function to fetch data from the integration
732
+ :param int limit: The limit of records to fetch
733
+ :param Optional[str] filter: The filter to apply to the data
734
+ :return: The data from the integration
735
+ :rtype: Any
736
+ """
737
+ import time
738
+
739
+ retries = 0
740
+ sleep_timers = [10, 20, 40]
741
+ while retries < 3:
742
+ try:
743
+ if cursor:
744
+ return func(limit=limit, filter=filter, cursor=cursor)
745
+ else:
746
+ return func(limit=limit, filter=filter)
747
+ except Exception as e:
748
+ self.logger.error(f"Error fetching data with retries: {e}")
749
+ self.logger.error(f"Retrying in {sleep_timers[retries]} seconds...")
750
+ time.sleep(sleep_timers[retries])
751
+ retries += 1
752
+ error_and_exit("Failed to fetch data after 3 retries")
753
+
732
754
  def run_integration_sync(self, *args, **kwargs) -> None:
733
755
  """
734
756
  Runs the sync process for the integration
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: regscale-cli
3
- Version: 6.27.0.1
3
+ Version: 6.27.2.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
@@ -1,5 +1,5 @@
1
1
  regscale/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
2
- regscale/_version.py,sha256=Osrs4pJBb55zQAQEB_LRVHlIdaSiQB-xSdkw85Zyotk,1198
2
+ regscale/_version.py,sha256=Lq40cZd2OT7sJZZWQh9y8KbuzbrUJbNhz2k2NIgwDVs,1198
3
3
  regscale/regscale.py,sha256=4LzcbkBxPh23cCLANVEEr6uNoZ0sebHec0N-VJm5_vA,31480
4
4
  regscale/airflow/__init__.py,sha256=yMwN0Bz4JbM0nl5qY_hPegxo_O2ilhTOL9PY5Njhn-s,270
5
5
  regscale/airflow/click_dags.py,sha256=H3SUR5jkvInNMv1gu-VG-Ja_H-kH145CpQYNalWNAbE,4520
@@ -57,7 +57,7 @@ regscale/core/app/internal/workflow.py,sha256=SpgYk1QyzdilVLOK1fFzaKhdLspumaugf5
57
57
  regscale/core/app/utils/XMLIR.py,sha256=M_RrCsbjznihatkucCKw6dPgHTPQczXyqIdUXWhuCLI,8328
58
58
  regscale/core/app/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  regscale/core/app/utils/api_handler.py,sha256=T1meKw6Yi3ZAgRbQ1xuKDVh9Q9B8mbMqqN_LrSwIlAM,11765
60
- regscale/core/app/utils/app_utils.py,sha256=c7V61VYaHaz_4o4YNmpQl0gZ3bHlbRwfpj-fUBVcb_s,37134
60
+ regscale/core/app/utils/app_utils.py,sha256=k_HEO4cFIddZMUtr56Z8A5NEjLz1Tl8vl2c3pqjXKvc,38652
61
61
  regscale/core/app/utils/file_utils.py,sha256=x7cqYPxJ-PgSb2lX_K6zhdqyGQjOCmr04lnqdBQV3hI,9269
62
62
  regscale/core/app/utils/parser_utils.py,sha256=aBEgcFwbJMD-ARf3wzf-tyWwR6NHvzEcdYcPMm8hGqo,2533
63
63
  regscale/core/app/utils/pickle_file_handler.py,sha256=iMdv4N8z00TB5LyPdxIcLKNRpDQVWQ8ZQWAqCKpqmF0,1695
@@ -145,7 +145,7 @@ regscale/integrations/commercial/aqua/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
145
145
  regscale/integrations/commercial/aqua/aqua.py,sha256=bdwqyir9ztGRwqZlWBQIHjtBEo2utSy5HJoraAx823I,2656
146
146
  regscale/integrations/commercial/aws/__init__.py,sha256=Pii3CMGvIwZnTSenuvDvuybWXBtIRdGyvF02sykzg1A,203
147
147
  regscale/integrations/commercial/aws/cli.py,sha256=Q2QlUcbYRzZzg9VZ5RDOTdVkkWc4UFYX7f5cMNlOZMY,14853
148
- regscale/integrations/commercial/aws/scanner.py,sha256=odN8nWhIlxGLBdVVVgfhp9wHq5yE32pzr9BK7OIjDkw,56770
148
+ regscale/integrations/commercial/aws/scanner.py,sha256=2XtHT3En5VoFYt-qGnIsNenThofZHkzC3fbJwHA6gPI,56765
149
149
  regscale/integrations/commercial/aws/inventory/__init__.py,sha256=nBWBRs_lTbp3tfCcnmN855qQpnXtwyJ5miTXlD7Uhcs,4302
150
150
  regscale/integrations/commercial/aws/inventory/base.py,sha256=KL1Ntz0h0WGDu84LQf3y92uLl9a0sl4yIFi6-ZIFAMI,2068
151
151
  regscale/integrations/commercial/aws/inventory/resources/__init__.py,sha256=wP8TMIixWGCn2rBNFW6XzhME-xO8kpxi9edMUJgpso4,523
@@ -182,7 +182,7 @@ regscale/integrations/commercial/mappings/csf_controls.json,sha256=EHOLWrnFr0oRs
182
182
  regscale/integrations/commercial/mappings/nist_800_53_r5_controls.json,sha256=Vuh8RkKhX84U8VG2zoLG94QL7mvWIF28M-u8B4paxgw,123879
183
183
  regscale/integrations/commercial/microsoft_defender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
184
184
  regscale/integrations/commercial/microsoft_defender/defender.py,sha256=JQLdSiGMuDFGXH8wdb3NQXuobcBprg1PR11OEOEBYyQ,51702
185
- regscale/integrations/commercial/microsoft_defender/defender_api.py,sha256=_Gij8I26tTt6B0RTqRyKPAi58gwl_TnKwe1fu80CPIM,29433
185
+ regscale/integrations/commercial/microsoft_defender/defender_api.py,sha256=GJf0H-4BacSLNtCXFU1Yb02mYS-jVuX40Z75bn6UqjQ,29434
186
186
  regscale/integrations/commercial/microsoft_defender/defender_constants.py,sha256=pYIVii1ouy3FYM58UbAdlcYdVoC54vEv0M2FjFk0XmU,9516
187
187
  regscale/integrations/commercial/microsoft_defender/defender_scanner.py,sha256=gUTtbv-yB2gDa3xXZpx1Ygq0hqa77I28516UOrwvla4,10615
188
188
  regscale/integrations/commercial/nessus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -208,9 +208,9 @@ regscale/integrations/commercial/sarif/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
208
208
  regscale/integrations/commercial/sarif/sairf_importer.py,sha256=gCuDsybT0jbhCtQLJW0L88hLxUpWIgatVERU4D6_9Xc,17886
209
209
  regscale/integrations/commercial/sarif/sarif_converter.py,sha256=3KJ7GBt8iJzTKdlUNq5rRx9JaoIHcESdbQim7AfhvNk,1910
210
210
  regscale/integrations/commercial/sicura/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
211
- regscale/integrations/commercial/sicura/api.py,sha256=8qFzENIpso7fuTWxXmzaWUAkDSTMQkcXB_cbfHPSDBE,32109
211
+ regscale/integrations/commercial/sicura/api.py,sha256=dUpLcMgOVTxmfit7Mt118o6y_nQy1nwMLEbbW7euRYw,33982
212
212
  regscale/integrations/commercial/sicura/commands.py,sha256=bDphozdUeuEVwspIjqBCOrQUIGAIFJpmg8ltzh3i8kc,2052
213
- regscale/integrations/commercial/sicura/scanner.py,sha256=vkfwU7sUGGnLu4N1Ue-Ruhhq8n4i6kS7-0Kdx2lhKXE,17721
213
+ regscale/integrations/commercial/sicura/scanner.py,sha256=3n0OLvD0n-i1BRG4ZHIJOEVO0xj_IYEJ1h0YBvtKG3U,19046
214
214
  regscale/integrations/commercial/sicura/variables.py,sha256=FOdXj5bTtmsAYJYLdLxYMalKhkP1l0bWjA5bCmvgvdU,676
215
215
  regscale/integrations/commercial/stig_mapper_integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
216
216
  regscale/integrations/commercial/stig_mapper_integration/click_commands.py,sha256=tLD9WObChb4NBd_sWnX05QPqXbiXOzdAp-v5YAObuDc,1200
@@ -229,10 +229,10 @@ regscale/integrations/commercial/tenablev2/__init__.py,sha256=UpSY_oww83kz9c7amd
229
229
  regscale/integrations/commercial/tenablev2/authenticate.py,sha256=VPTmxaVCaah2gJYNeU9P1KoQ734ohGQ-wcVy6JfqDTE,1247
230
230
  regscale/integrations/commercial/tenablev2/cis_parsers.py,sha256=7F6OSgYXSKMNpEyyWxPilt1u9SZRuQY21Qbp9fGbD9o,17167
231
231
  regscale/integrations/commercial/tenablev2/cis_scanner.py,sha256=uMuE48-ZfYSMyFBdJsPgR-biV7OtGYV64-2QZBwKsn0,17550
232
- regscale/integrations/commercial/tenablev2/commands.py,sha256=ZB2rZ0RKQ0rkRGrbuw2CJogbEBee8u0I-2WAy4qYvnc,32605
232
+ regscale/integrations/commercial/tenablev2/commands.py,sha256=r7TnD1Aqk2qaIy8xx9baSErnbH5EQwrEHgu2QDfUwIE,32605
233
233
  regscale/integrations/commercial/tenablev2/jsonl_scanner.py,sha256=6dv92JslX_p_N6vuwCj4hj1OPy935a-ZjPz0dsWaXuw,83577
234
234
  regscale/integrations/commercial/tenablev2/sc_scanner.py,sha256=WQ7ctneHz3fYOrR_GvVUJL3BuKNoN515y7pG8ATMjOM,24102
235
- regscale/integrations/commercial/tenablev2/scanner.py,sha256=vQAa5_oSSceg6BlGCizsT3cHCG2-rphvN1ww_KAcfnE,21527
235
+ regscale/integrations/commercial/tenablev2/scanner.py,sha256=MEEyFKEdQdV8QUQUwL3eK7aLMvJppdACj2Mt7JZ4bv4,21462
236
236
  regscale/integrations/commercial/tenablev2/stig_parsers.py,sha256=xv68Vk7BhTIAM5RZqlCRK3fOd2qcVTGgtTM3DFiuhuY,7780
237
237
  regscale/integrations/commercial/tenablev2/sync_compliance.py,sha256=_7_VwJm2xHUk-4Pzaz-ywQ3FNuMgRUn9IlRW3m9e97M,22083
238
238
  regscale/integrations/commercial/tenablev2/utils.py,sha256=_MmvcR71PmvH4dQ1k4M-q4PYAg0EE_aQ9w4cUdP7SwE,3359
@@ -248,7 +248,7 @@ regscale/integrations/commercial/wizv2/file_cleanup.py,sha256=ENBO9RDXL2kyHkBYaS
248
248
  regscale/integrations/commercial/wizv2/issue.py,sha256=fTYRTpf1bjWfPe1MgKhUkv7-ahQzib4hDGJVCTbvDpI,46238
249
249
  regscale/integrations/commercial/wizv2/reports.py,sha256=GTP_bNGqxofKNEucDfbbE5RmjIEmMZgZLZT_sYdi0Ew,8794
250
250
  regscale/integrations/commercial/wizv2/sbom.py,sha256=gdjB33PG67LrZXZUji7KCLjJ_CuiXE5nX_EcACo-DNk,4471
251
- regscale/integrations/commercial/wizv2/scanner.py,sha256=AbNvmOHsLd-toVvQStft7sGhHd8c6KHFc8SB1qTt3gg,93886
251
+ regscale/integrations/commercial/wizv2/scanner.py,sha256=JREqiYYS-ZZUgg7gEzLdYzYh7tlILB6_OBjFYpxXshE,95413
252
252
  regscale/integrations/commercial/wizv2/variables.py,sha256=SdMZyKsAn-JxjVNMCWA6Im4h_7Sb2JlJ3vS6aorzHpc,3812
253
253
  regscale/integrations/commercial/wizv2/compliance/__init__.py,sha256=t0WhxpC75lVQ1P_abMlyrTqXJKXGI4ZRp9C-5_gF4A0,377
254
254
  regscale/integrations/commercial/wizv2/compliance/helpers.py,sha256=HXSFgYtYDE6TdpbEYxvqaz4s673oaveurnyuuG5lgV8,22983
@@ -271,7 +271,7 @@ regscale/integrations/integration/integration.py,sha256=pr_fbqBieYbqp3PdBjuqKuZC
271
271
  regscale/integrations/integration/inventory.py,sha256=gHL1a6VSV3zf4DTmksEy8qXNrqhIun8TwLxhRpuEMqY,341
272
272
  regscale/integrations/integration/issue.py,sha256=HaCF_5F_U_E5ecYlMgOZiM-yhXnt7OLj47OAJkf9X3g,3507
273
273
  regscale/integrations/public/__init__.py,sha256=oohbRYt88NZyMoFvQGrx6kVQROZrxAwlKIumL2yUh2g,3348
274
- regscale/integrations/public/cci_importer.py,sha256=HI6b3N3NXX7IBnqmEe0KSFnkSuATnfQWVC1ETCcAm3M,16390
274
+ regscale/integrations/public/cci_importer.py,sha256=MZLX1YlaVCiVgDiFZkQV-0iHmBqkuT_vSadbDUCDLdw,31494
275
275
  regscale/integrations/public/cisa.py,sha256=EE2rN4GWWEk5VLt4iMVwGMYB6yYPxe6KyW_tLs8dDmA,21870
276
276
  regscale/integrations/public/criticality_updater.py,sha256=bekadBBJkym5Dd9JZFNQmY3I0e1xgBvxkyVwgCNOKus,2806
277
277
  regscale/integrations/public/emass.py,sha256=culHHuXUlVYkB6DcVcnUvpBzU1eRyyVGgsJ3KqC8HOw,13672
@@ -336,12 +336,12 @@ regscale/models/app_models/mapping.py,sha256=tga2kCsEZT-YvnJIgiHy_qRcFp25Xzk0Ykb
336
336
  regscale/models/app_models/pipeline.py,sha256=qzrkQvvW6d8rqbBjMR8wkT2obez0tnKyY_TxtxLh6VE,909
337
337
  regscale/models/integration_models/CCI_List.xml,sha256=qwHzCrZ3KQnLLmrF6J9dE_trhVcUdIw-7WFTtvPmNLM,3226054
338
338
  regscale/models/integration_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
339
- regscale/models/integration_models/aqua.py,sha256=XR2qrzCOI_bXrFPVcgbxUyaE1m0Oe2NSH7ph1hn8q2w,10697
339
+ regscale/models/integration_models/aqua.py,sha256=MI_qltODiERdGpmwoRD7_U1ISmBMl30mjpPf8brjdhQ,10717
340
340
  regscale/models/integration_models/azure_alerts.py,sha256=2etrpvcxa7jVQrc98bJlVGd3xPcw-YwJ65c3pfSf0uA,8408
341
341
  regscale/models/integration_models/base64.py,sha256=sxV6O5qY1_TstJENX5jBPsSdQwmA83-NNhgJFunXiZE,570
342
342
  regscale/models/integration_models/burp.py,sha256=FBEBkH3U0Q8vq71FFoWnvgLRF5Hkr9GYmQFmNNHFrVk,16932
343
343
  regscale/models/integration_models/burp_models.py,sha256=UytDTAcCaxyu-knFkm_mEUH6UmWK3OTXKSC9Sc6OjVs,3669
344
- regscale/models/integration_models/cisa_kev_data.json,sha256=NQpI-0sN-kJdasvfcqjmjlWJZpNJbgYVs-l_MlOuTD8,1295585
344
+ regscale/models/integration_models/cisa_kev_data.json,sha256=g9yH6zg8DARdu4A1E4VvQJ5pGGffuCZRpsd2RkhwjGY,1306997
345
345
  regscale/models/integration_models/defender_data.py,sha256=jsAcjKxiGmumGerj7xSWkFd6r__YpuKDnYX5o7xHDiE,2844
346
346
  regscale/models/integration_models/defenderimport.py,sha256=Ze4kgwns-IYPyO7sBjEzW8PXWlxwU-DAo2fIyRcTC3k,6242
347
347
  regscale/models/integration_models/drf.py,sha256=Aq7AdLa_CH97NrnR-CxaFI22JjVN9uCxVN7Z-BBUaNU,18896
@@ -368,22 +368,22 @@ regscale/models/integration_models/axonius_models/connectors/assets.py,sha256=6m
368
368
  regscale/models/integration_models/ecr_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
369
369
  regscale/models/integration_models/ecr_models/data.py,sha256=l28DCidXar1JygYBQZL9MYenQA9N-Cx3Skf51IOjZcw,1017
370
370
  regscale/models/integration_models/ecr_models/ecr.py,sha256=oAkQ-SDS3Mjrn291dh9qF5LaRYGFJnmuNY28UyrzIfg,7293
371
- regscale/models/integration_models/flat_file_importer/__init__.py,sha256=HYO7mrqnBaXKyo7dBNGnVqYY7m_1OjTadJKfg4f_ae4,40595
371
+ regscale/models/integration_models/flat_file_importer/__init__.py,sha256=8RNe5LU_mHvO4bH2wO_1d2pijy2s4n7nhpjN25xZF2o,40633
372
372
  regscale/models/integration_models/sbom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
373
373
  regscale/models/integration_models/sbom/cyclone_dx.py,sha256=0pFR0BWBrF5c8_cC_8mj2MXvNOMHOdHbBYXvTVfFAh8,4058
374
374
  regscale/models/integration_models/synqly_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
375
- regscale/models/integration_models/synqly_models/capabilities.json,sha256=MqbVQ3qdu4cDHkAXF50zanx4CnFiIhIwW1Iw8CS-4j0,442882
375
+ regscale/models/integration_models/synqly_models/capabilities.json,sha256=oV1EzsM5z2abuVWhoxcgJ7Sg1mT6DQ7sNtJPbYwS330,442978
376
376
  regscale/models/integration_models/synqly_models/connector_types.py,sha256=8nxptkTexpskySnmL0obNAff_iu_fx6tJ7i1-4hJvao,461
377
377
  regscale/models/integration_models/synqly_models/filter_parser.py,sha256=8rdnHH7gW1A_uWRTexZXzCH-HzRVy5nlvFgtc7ztcsQ,12160
378
- regscale/models/integration_models/synqly_models/ocsf_mapper.py,sha256=ftObPhGg9CamnwRZ5z6qi8pW2Gu4JYy8apEo33o7q00,16960
378
+ regscale/models/integration_models/synqly_models/ocsf_mapper.py,sha256=3M1O8yz0jBRav30lK8BU1xUL5STixetRSpIp5bWhRzg,18746
379
379
  regscale/models/integration_models/synqly_models/param.py,sha256=Xt5Zm6lC_VkLj7LF2qXo72TJZHysqttsp5ai0NCf1po,2643
380
- regscale/models/integration_models/synqly_models/synqly_model.py,sha256=3nNELO4TcbvzS8u0eZqGVUUFycS5BR0NA8oWAbw3R_k,36801
380
+ regscale/models/integration_models/synqly_models/synqly_model.py,sha256=RPxieh3r9dVdkt7IliiNEqEqvhbXv3UFuEEZ4-MNqGc,37965
381
381
  regscale/models/integration_models/synqly_models/tenants.py,sha256=kewIZw-iv18bNXJGG3ghwuFJ4CK5iXQhn_x2-xvV0iM,1078
382
382
  regscale/models/integration_models/synqly_models/connectors/__init__.py,sha256=J3YS7KXLnTPRzeM3lUQpy6HKH7CxPPsWCB-sPXSWcYA,189
383
383
  regscale/models/integration_models/synqly_models/connectors/assets.py,sha256=HHNIAVh5pRuJe8sStqhFEc6VnX2wT0FcY5178nbQgkQ,3705
384
384
  regscale/models/integration_models/synqly_models/connectors/edr.py,sha256=kio3uoEYubCHretpDOJqxdwmzid1IzbVYz0BF64zeL0,5547
385
385
  regscale/models/integration_models/synqly_models/connectors/ticketing.py,sha256=yRBuCkRAVfa_C91r3WqJ9gxrQsoD0qV9cY48YXpJl70,25358
386
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py,sha256=nGS3XqRGTITz2XLSSr766DAfbngOT_D9DUFhaG--Plc,8239
386
+ regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py,sha256=7fsPHtWSrHxlqAXGURvQ4VWunmAs-acz7O8ABHshdBw,8240
387
387
  regscale/models/integration_models/tenable_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
388
388
  regscale/models/integration_models/tenable_models/integration.py,sha256=lplL8zmjTFuhLreW-4y7G1fiCOBgzNAaATq800jgTQc,10271
389
389
  regscale/models/integration_models/tenable_models/models.py,sha256=dmG7btkN4YkDWwnfW5Ldc3tWEAGjPiaRgJjrqMOkPEU,15846
@@ -559,7 +559,7 @@ tests/regscale/integrations/commercial/test_jira.py,sha256=oyPdDpjh4MiKlUYN14Za9
559
559
  tests/regscale/integrations/commercial/test_npm_audit.py,sha256=g8Dyvb3hmYPKgTF6l7MNKnuiBEStK5tM8jFbs594IBQ,988
560
560
  tests/regscale/integrations/commercial/test_okta.py,sha256=J3bBdotRRkIqdsEVLZLyt5PBI5u_dpmxXZnVFuSG1bs,47149
561
561
  tests/regscale/integrations/commercial/test_sarif_converter.py,sha256=uONCJEfiV2flUIDa-iwFd_h5RnHSaFHoyvNrXtcOhVU,11251
562
- tests/regscale/integrations/commercial/test_sicura.py,sha256=0N_8xjpDUgzrxFUPC1cTQs9Znk7qxgMRb500LVzozqw,13235
562
+ tests/regscale/integrations/commercial/test_sicura.py,sha256=FaY0uOOKf7zyd2ejLtg07hMRIHDapi5n4qvxBc1s6MM,13192
563
563
  tests/regscale/integrations/commercial/test_snow.py,sha256=LKAeme78hl0VzzLP-rXZnA5-3CCBrJLgYUlxOW2hYnM,16076
564
564
  tests/regscale/integrations/commercial/test_sonarcloud.py,sha256=IB3nD9KbkTBXJgjF4RujUod54VUI0CMYanqoQ40suBk,15291
565
565
  tests/regscale/integrations/commercial/test_sqlserver.py,sha256=TktSuFoyLUmdimRxoN8wxBQwr75igWxA8mN83Isnuvw,7119
@@ -592,7 +592,7 @@ tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py,s
592
592
  tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py,sha256=zieuADKOAlBjPPlUkgSvMMZOr4CvnIZTl_0MvsyK4XA,14955
593
593
  tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py,sha256=2vEB9Hz_M1D2YQyZC3fD6RJCeXlRbUT3PRsu3DDek-A,27089
594
594
  tests/regscale/integrations/commercial/wizv2/test_wiz_status_mapping.py,sha256=ZUeRHUt547FV0svfiGEIwyRuItoTDKtMeJFvBWuhWhg,6967
595
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py,sha256=qZ6Dh54NTfIJHy5PbaoLl1W4syTPl3htVqZvM5o6pAc,61072
595
+ tests/regscale/integrations/commercial/wizv2/test_wizv2.py,sha256=WoRyyrJLW6Nnie1G6McWZc24OAe0A2KYhqXMyOiOSnw,66522
596
596
  tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py,sha256=U3qOibYbzF1adPPdpTbqyeWCT6t8cRaLy__o9F8mLO0,25182
597
597
  tests/regscale/integrations/commercial/wizv2/compliance/__init__.py,sha256=_ceZ5sfxe2B6jHQuisE8iYg_G68IkArHYq1oTC9Ede0,47
598
598
  tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py,sha256=0fuC9cuSSXzWeRrm9Y0KC7uOZsOPpiOz48m_C8nF6lg,35411
@@ -610,7 +610,7 @@ tests/regscale/integrations/commercial/wizv2/utils/__init__.py,sha256=PIKcAU5kcq
610
610
  tests/regscale/integrations/commercial/wizv2/utils/test_main.py,sha256=VExH4ORw3C4KBzZiQwwtRpeGnsQhl5r0FMk0wD6OCBo,60749
611
611
  tests/regscale/integrations/public/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
612
612
  tests/regscale/integrations/public/test_alienvault.py,sha256=epxuflNgibIl1aYCU0FTVXXFWJbiqt0mYBV4HVaZYuw,9211
613
- tests/regscale/integrations/public/test_cci.py,sha256=Zv5igmyYJpAwIAHrGQ-3Pd8MLvY8bh-B5FALL41PPU8,19525
613
+ tests/regscale/integrations/public/test_cci.py,sha256=Xtyuwv1N8wTgvnUs7oWkWwp7yOC3MO77gyqOKFXC5mI,44314
614
614
  tests/regscale/integrations/public/test_cisa.py,sha256=onfmI-8Nuhr7g0C87gweGoWhAubcqkmammRUD8QCQFE,41376
615
615
  tests/regscale/integrations/public/test_emass.py,sha256=fDjQcsiXFhWGB399fikfW_khCrixB3nEL3cBlAm4XbQ,21797
616
616
  tests/regscale/integrations/public/test_fedramp.py,sha256=ppVsyj-zQRq5isH0Ht1_s9jrJUSBJSs9y976-LDHpwE,70161
@@ -635,9 +635,9 @@ tests/regscale/models/test_regscale_model.py,sha256=ZsrEZkC4EtdIsoQuayn1xv2gEGcV
635
635
  tests/regscale/models/test_report.py,sha256=IqUq7C__a1_q_mLaz0PE9Lq6fHggBsB14-AzEYNBxLw,4666
636
636
  tests/regscale/models/test_tenable_integrations.py,sha256=y1qaW77H094VSGHjZdlvF66UCt-nPEib9Mv3cdwbM94,32435
637
637
  tests/regscale/models/test_user_model.py,sha256=e9olv28qBApgnvK6hFHOgXjUC-pkaV8aGDirEIWASL4,4427
638
- regscale_cli-6.27.0.1.dist-info/LICENSE,sha256=ytNhYQ9Rmhj_m-EX2pPq9Ld6tH5wrqqDYg-fCf46WDU,1076
639
- regscale_cli-6.27.0.1.dist-info/METADATA,sha256=_pivqE24yPp_EYyjmO1UZ7oa5cxPf_gox0TJrnNTfzA,34231
640
- regscale_cli-6.27.0.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
641
- regscale_cli-6.27.0.1.dist-info/entry_points.txt,sha256=cLOaIP1eRv1yZ2u7BvpE3aB4x3kDrDwkpeisKOu33z8,269
642
- regscale_cli-6.27.0.1.dist-info/top_level.txt,sha256=Uv8VUCAdxRm70bgrD4YNEJUmDhBThad_1aaEFGwRByc,15
643
- regscale_cli-6.27.0.1.dist-info/RECORD,,
638
+ regscale_cli-6.27.2.0.dist-info/LICENSE,sha256=ytNhYQ9Rmhj_m-EX2pPq9Ld6tH5wrqqDYg-fCf46WDU,1076
639
+ regscale_cli-6.27.2.0.dist-info/METADATA,sha256=urTKR5zkhFizHfI1rxRo29oWv7HRbGHOxLSVbO8U_Ts,34231
640
+ regscale_cli-6.27.2.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
641
+ regscale_cli-6.27.2.0.dist-info/entry_points.txt,sha256=cLOaIP1eRv1yZ2u7BvpE3aB4x3kDrDwkpeisKOu33z8,269
642
+ regscale_cli-6.27.2.0.dist-info/top_level.txt,sha256=Uv8VUCAdxRm70bgrD4YNEJUmDhBThad_1aaEFGwRByc,15
643
+ regscale_cli-6.27.2.0.dist-info/RECORD,,
@@ -15,7 +15,6 @@ class TestSicuraAPI(unittest.TestCase):
15
15
  def setUp(self):
16
16
  """Set up test environment."""
17
17
  self.api = SicuraAPI()
18
- self.api.csrf_token = "test_token"
19
18
  self.api.base_url = "https://sicura-test.example.com"
20
19
  self.api.session = mock.MagicMock()
21
20
 
@@ -522,6 +522,35 @@ class TestWizVulnerabilityIntegration(unittest.TestCase):
522
522
  severity = WizVulnerabilityIntegration.get_issue_severity("Unknown")
523
523
  self.assertEqual(severity, regscale_models.IssueSeverity.Low)
524
524
 
525
+ def test_get_issue_severity_none_maps_to_not_assigned(self, mock_parent_init):
526
+ """Test REG-17981: Handle NONE severity from Wiz config findings."""
527
+ severity = WizVulnerabilityIntegration.get_issue_severity("None")
528
+ self.assertEqual(severity, regscale_models.IssueSeverity.NotAssigned)
529
+
530
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
531
+ def test_should_process_finding_by_severity_none_treated_as_informational(
532
+ self, mock_authenticate, mock_parent_init
533
+ ):
534
+ """Test REG-17981: NONE severity should be treated as informational for filtering."""
535
+ mock_authenticate.return_value = None
536
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
537
+ self._initialize_scanner_attributes(integration)
538
+ integration.app.config["scanners"] = {"wiz": {"minimumSeverity": "low"}}
539
+ # NONE severity should be filtered out when min is "low" (treated as informational)
540
+ self.assertFalse(integration.should_process_finding_by_severity("NONE"))
541
+
542
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
543
+ def test_should_process_finding_by_severity_none_allowed_with_informational(
544
+ self, mock_authenticate, mock_parent_init
545
+ ):
546
+ """Test REG-17981: NONE severity should be allowed when min severity is informational."""
547
+ mock_authenticate.return_value = None
548
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
549
+ self._initialize_scanner_attributes(integration)
550
+ integration.app.config["scanners"] = {"wiz": {"minimumSeverity": "informational"}}
551
+ # NONE severity should be processed when min is "informational"
552
+ self.assertTrue(integration.should_process_finding_by_severity("NONE"))
553
+
525
554
  @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
526
555
  def test_should_process_finding_by_severity_critical(self, mock_authenticate, mock_parent_init):
527
556
  mock_authenticate.return_value = None
@@ -687,6 +716,63 @@ class TestWizVulnerabilityIntegration(unittest.TestCase):
687
716
  asset_id = integration.get_asset_id_from_node(node, WizVulnerabilityType.VULNERABILITY)
688
717
  self.assertIsNone(asset_id)
689
718
 
719
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
720
+ def test_get_asset_id_with_none_value_returns_none(self, mock_authenticate, mock_parent_init):
721
+ """Test REG-17981: Handle None value for asset container without AttributeError."""
722
+ from regscale.integrations.commercial.wizv2.core.constants import WizVulnerabilityType
723
+
724
+ mock_authenticate.return_value = None
725
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
726
+ node = {"vulnerableAsset": None}
727
+ asset_id = integration.get_asset_id_from_node(node, WizVulnerabilityType.VULNERABILITY)
728
+ self.assertIsNone(asset_id)
729
+
730
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
731
+ def test_get_asset_id_with_none_resource_returns_none(self, mock_authenticate, mock_parent_init):
732
+ """Test REG-17981: Handle None value for resource field without AttributeError."""
733
+ from regscale.integrations.commercial.wizv2.core.constants import WizVulnerabilityType
734
+
735
+ mock_authenticate.return_value = None
736
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
737
+ node = {"resource": None}
738
+ asset_id = integration.get_asset_id_from_node(node, WizVulnerabilityType.CONFIGURATION)
739
+ self.assertIsNone(asset_id)
740
+
741
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
742
+ def test_get_asset_id_with_non_dict_value_returns_none(self, mock_authenticate, mock_parent_init):
743
+ """Test REG-17981: Handle non-dict value for asset container without AttributeError."""
744
+ from regscale.integrations.commercial.wizv2.core.constants import WizVulnerabilityType
745
+
746
+ mock_authenticate.return_value = None
747
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
748
+ # Test with a string value instead of dict
749
+ node = {"vulnerableAsset": "not-a-dict"}
750
+ asset_id = integration.get_asset_id_from_node(node, WizVulnerabilityType.VULNERABILITY)
751
+ self.assertIsNone(asset_id)
752
+
753
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
754
+ def test_get_provider_unique_id_with_none_value_returns_none(self, mock_authenticate, mock_parent_init):
755
+ """Test REG-17981: Handle None value in get_provider_unique_id_from_node without AttributeError."""
756
+ from regscale.integrations.commercial.wizv2.core.constants import WizVulnerabilityType
757
+
758
+ mock_authenticate.return_value = None
759
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
760
+ node = {"vulnerableAsset": None}
761
+ provider_id = integration.get_provider_unique_id_from_node(node, WizVulnerabilityType.VULNERABILITY)
762
+ self.assertIsNone(provider_id)
763
+
764
+ @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
765
+ def test_get_provider_unique_id_with_non_dict_returns_none(self, mock_authenticate, mock_parent_init):
766
+ """Test REG-17981: Handle non-dict value in get_provider_unique_id_from_node without AttributeError."""
767
+ from regscale.integrations.commercial.wizv2.core.constants import WizVulnerabilityType
768
+
769
+ mock_authenticate.return_value = None
770
+ integration = WizVulnerabilityIntegration(plan_id=self.plan_id)
771
+ # Test with a list value instead of dict
772
+ node = {"vulnerableAsset": ["not", "a", "dict"]}
773
+ provider_id = integration.get_provider_unique_id_from_node(node, WizVulnerabilityType.VULNERABILITY)
774
+ self.assertIsNone(provider_id)
775
+
690
776
  @patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration.authenticate")
691
777
  def test_get_provider_unique_id_standard(self, mock_authenticate, mock_parent_init):
692
778
  from regscale.integrations.commercial.wizv2.core.constants import WizVulnerabilityType