regscale-cli 6.20.6.0__py3-none-any.whl → 6.20.8.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 (43) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/api.py +8 -1
  3. regscale/core/app/application.py +49 -3
  4. regscale/core/utils/date.py +16 -16
  5. regscale/integrations/commercial/aqua/aqua.py +1 -1
  6. regscale/integrations/commercial/aws/cli.py +1 -1
  7. regscale/integrations/commercial/defender.py +1 -1
  8. regscale/integrations/commercial/ecr.py +1 -1
  9. regscale/integrations/commercial/ibm.py +1 -1
  10. regscale/integrations/commercial/nexpose.py +1 -1
  11. regscale/integrations/commercial/prisma.py +1 -1
  12. regscale/integrations/commercial/qualys/__init__.py +157 -84
  13. regscale/integrations/commercial/qualys/containers.py +2 -1
  14. regscale/integrations/commercial/qualys/scanner.py +5 -3
  15. regscale/integrations/commercial/snyk.py +14 -4
  16. regscale/integrations/commercial/synqly/ticketing.py +23 -11
  17. regscale/integrations/commercial/veracode.py +15 -4
  18. regscale/integrations/commercial/xray.py +1 -1
  19. regscale/integrations/public/cisa.py +7 -1
  20. regscale/integrations/public/nist_catalog.py +8 -2
  21. regscale/integrations/scanner_integration.py +18 -36
  22. regscale/models/app_models/import_validater.py +5 -1
  23. regscale/models/app_models/mapping.py +3 -1
  24. regscale/models/integration_models/cisa_kev_data.json +139 -4
  25. regscale/models/integration_models/flat_file_importer/__init__.py +36 -22
  26. regscale/models/integration_models/qualys.py +24 -4
  27. regscale/models/integration_models/send_reminders.py +8 -2
  28. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  29. regscale/models/regscale_models/control_implementation.py +40 -0
  30. regscale/models/regscale_models/issue.py +7 -4
  31. regscale/models/regscale_models/parameter.py +3 -2
  32. regscale/models/regscale_models/ports_protocol.py +15 -5
  33. regscale/models/regscale_models/vulnerability.py +1 -1
  34. regscale/utils/graphql_client.py +3 -6
  35. regscale/utils/threading/threadhandler.py +12 -2
  36. {regscale_cli-6.20.6.0.dist-info → regscale_cli-6.20.8.0.dist-info}/METADATA +13 -13
  37. {regscale_cli-6.20.6.0.dist-info → regscale_cli-6.20.8.0.dist-info}/RECORD +43 -42
  38. tests/regscale/core/test_version_regscale.py +62 -0
  39. tests/regscale/test_init.py +2 -0
  40. {regscale_cli-6.20.6.0.dist-info → regscale_cli-6.20.8.0.dist-info}/LICENSE +0 -0
  41. {regscale_cli-6.20.6.0.dist-info → regscale_cli-6.20.8.0.dist-info}/WHEEL +0 -0
  42. {regscale_cli-6.20.6.0.dist-info → regscale_cli-6.20.8.0.dist-info}/entry_points.txt +0 -0
  43. {regscale_cli-6.20.6.0.dist-info → regscale_cli-6.20.8.0.dist-info}/top_level.txt +0 -0
regscale/_version.py CHANGED
@@ -33,7 +33,7 @@ def get_version_from_pyproject() -> str:
33
33
  return match.group(1)
34
34
  except Exception:
35
35
  pass
36
- return "6.20.6.0" # fallback version
36
+ return "6.20.8.0" # fallback version
37
37
 
38
38
 
39
39
  __version__ = get_version_from_pyproject()
regscale/core/app/api.py CHANGED
@@ -432,7 +432,14 @@ class Api:
432
432
  if json_list and len(json_list) > 0:
433
433
  with Progress(transient=False) as progress:
434
434
  task = progress.add_task(message, total=len(json_list))
435
- with concurrent.futures.ThreadPoolExecutor(max_workers=self.config["maxThreads"]) as executor:
435
+ # Ensure maxThreads is an integer for ThreadPoolExecutor
436
+ max_workers = self.config.get("maxThreads", 100)
437
+ if not isinstance(max_workers, int):
438
+ try:
439
+ max_workers = int(max_workers)
440
+ except (ValueError, TypeError):
441
+ max_workers = 100
442
+ with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
436
443
  if method.lower() == "post":
437
444
  result_futures = list(
438
445
  map(
@@ -298,7 +298,19 @@ class Application(metaclass=Singleton):
298
298
  self.config = self._gen_config(config)
299
299
  self.os = platform.system()
300
300
  self.input_host = ""
301
- self.thread_manager = ThreadManager(self.config.get("maxThreads", 100))
301
+ # Ensure maxThreads is an integer for ThreadManager
302
+ max_threads = self.config.get("maxThreads", 100)
303
+ if not isinstance(max_threads, int):
304
+ logger.debug(f"maxThreads is not an integer: {max_threads} (type: {type(max_threads)})")
305
+ try:
306
+ max_threads = int(max_threads)
307
+ logger.debug(f"Converted maxThreads to integer: {max_threads}")
308
+ except (ValueError, TypeError) as e:
309
+ logger.warning(
310
+ f"Failed to convert maxThreads '{max_threads}' to integer: {e}. Using default value 100."
311
+ )
312
+ max_threads = 100
313
+ self.thread_manager = ThreadManager(max_threads)
302
314
  logger.debug("Finished Initializing Application")
303
315
  logger.debug("*" * 80)
304
316
 
@@ -654,12 +666,46 @@ class Application(metaclass=Singleton):
654
666
  for key, template_value in template.items():
655
667
  config_value = config.get(key)
656
668
 
657
- # If key missing or value type mismatch, use template value
658
- if config_value is None or config_value == "" or not isinstance(config_value, type(template_value)):
669
+ # If key missing or empty, use template value
670
+ if config_value is None or config_value == "":
659
671
  updated_config[key] = template_value
660
672
  # If value is a dict, recurse
661
673
  elif isinstance(template_value, dict):
662
674
  updated_config[key] = self.verify_config(template_value, config.get(key, {}))
675
+ # If type mismatch, try to convert the value to the expected type
676
+ elif not isinstance(config_value, type(template_value)):
677
+ self.logger.debug(
678
+ f"Type mismatch for key '{key}': expected {type(template_value).__name__}, got {type(config_value).__name__} with value '{config_value}'"
679
+ )
680
+ try:
681
+ if isinstance(template_value, int):
682
+ updated_config[key] = int(config_value)
683
+ self.logger.debug(
684
+ f"Converted '{key}' from {type(config_value).__name__} to int: {config_value} -> {updated_config[key]}"
685
+ )
686
+ elif isinstance(template_value, float):
687
+ updated_config[key] = float(config_value)
688
+ self.logger.debug(
689
+ f"Converted '{key}' from {type(config_value).__name__} to float: {config_value} -> {updated_config[key]}"
690
+ )
691
+ elif isinstance(template_value, bool):
692
+ if isinstance(config_value, str):
693
+ updated_config[key] = config_value.lower() in ("true", "1", "yes", "on")
694
+ else:
695
+ updated_config[key] = bool(config_value)
696
+ self.logger.debug(
697
+ f"Converted '{key}' from {type(config_value).__name__} to bool: {config_value} -> {updated_config[key]}"
698
+ )
699
+ else:
700
+ # For other types, use template value as fallback
701
+ updated_config[key] = template_value
702
+ self.logger.debug(f"Using template value for '{key}': {template_value}")
703
+ except (ValueError, TypeError) as e:
704
+ # If conversion fails, use template value
705
+ self.logger.warning(
706
+ f"Failed to convert '{key}' from '{config_value}' to {type(template_value).__name__}: {e}. Using template value: {template_value}"
707
+ )
708
+ updated_config[key] = template_value
663
709
  # Else, retain the config value
664
710
  else:
665
711
  updated_config[key] = config_value
@@ -24,20 +24,23 @@ def date_str(date_object: Union[str, datetime.datetime, datetime.date, None], da
24
24
  :param Optional[str] date_format: The format to use for the date string.
25
25
  :return: The date as a string.
26
26
  """
27
- if isinstance(date_object, str):
28
- date_object = date_obj(date_object)
27
+ try:
28
+ if isinstance(date_object, str):
29
+ date_object = date_obj(date_object)
29
30
 
30
- # Handles passed None and date_obj returning None
31
- if not date_object:
32
- return ""
31
+ # Handles passed None and date_obj returning None
32
+ if not date_object:
33
+ return ""
33
34
 
34
- if isinstance(date_object, (datetime.datetime, Timestamp)):
35
- date_object = date_object.date()
35
+ if isinstance(date_object, (datetime.datetime, Timestamp)):
36
+ date_object = date_object.date()
36
37
 
37
- if date_format:
38
- return date_object.strftime(date_format)
38
+ if date_format:
39
+ return date_object.strftime(date_format)
39
40
 
40
- return date_object.isoformat()
41
+ return date_object.isoformat()
42
+ except Exception:
43
+ return ""
41
44
 
42
45
 
43
46
  def datetime_str(
@@ -52,14 +55,11 @@ def datetime_str(
52
55
  """
53
56
  if not date_format:
54
57
  date_format = default_date_format
55
-
56
58
  if isinstance(date_object, str):
57
59
  date_object = datetime_obj(date_object)
58
-
59
- if not date_object:
60
- return ""
61
-
62
- return date_object.strftime(date_format)
60
+ if isinstance(date_object, datetime.date):
61
+ return date_object.strftime(date_format)
62
+ return ""
63
63
 
64
64
 
65
65
  def date_obj(date_str: Union[str, datetime.datetime, datetime.date, int, None]) -> Optional[datetime.date]:
@@ -80,7 +80,7 @@ def import_aqua_scan(
80
80
  import_name="Aqua",
81
81
  file_types=[".csv", ".xlsx"],
82
82
  folder_path=folder_path,
83
- regscale_ssp_id=regscale_ssp_id,
83
+ object_id=regscale_ssp_id,
84
84
  scan_date=scan_date,
85
85
  mappings_path=mappings_path,
86
86
  disable_mapping=disable_mapping,
@@ -249,7 +249,7 @@ def import_aws_scans(
249
249
  import_name="AWS Inspector",
250
250
  file_types=[".csv", ".json"],
251
251
  folder_path=folder_path,
252
- regscale_ssp_id=regscale_ssp_id,
252
+ object_id=regscale_ssp_id,
253
253
  scan_date=scan_date,
254
254
  mappings_path=mappings_path,
255
255
  disable_mapping=disable_mapping,
@@ -251,7 +251,7 @@ def import_defender_alerts(
251
251
  import_name="Defender",
252
252
  file_types=".csv",
253
253
  folder_path=folder_path,
254
- regscale_ssp_id=regscale_ssp_id,
254
+ object_id=regscale_ssp_id,
255
255
  scan_date=scan_date,
256
256
  mappings_path=mappings_path,
257
257
  disable_mapping=disable_mapping,
@@ -79,7 +79,7 @@ def import_ecr_scans(
79
79
  import_name="ECR",
80
80
  file_types=[".csv", ".json"],
81
81
  folder_path=folder_path,
82
- regscale_ssp_id=regscale_ssp_id,
82
+ object_id=regscale_ssp_id,
83
83
  scan_date=scan_date,
84
84
  mappings_path=mappings_path,
85
85
  disable_mapping=disable_mapping,
@@ -79,7 +79,7 @@ def import_appscan_files(
79
79
  import_name="IBM AppScan",
80
80
  file_types=".csv",
81
81
  folder_path=folder_path,
82
- regscale_ssp_id=regscale_ssp_id,
82
+ object_id=regscale_ssp_id,
83
83
  scan_date=scan_date,
84
84
  mappings_path=mappings_path,
85
85
  disable_mapping=disable_mapping,
@@ -79,7 +79,7 @@ def import_nexpose_files(
79
79
  import_name="Nexpose",
80
80
  file_types=".csv",
81
81
  folder_path=folder_path,
82
- regscale_ssp_id=regscale_ssp_id,
82
+ object_id=regscale_ssp_id,
83
83
  scan_date=scan_date,
84
84
  mappings_path=mappings_path,
85
85
  disable_mapping=disable_mapping,
@@ -80,7 +80,7 @@ def import_prisma_data(
80
80
  import_name="Prisma",
81
81
  file_types=".csv",
82
82
  folder_path=folder_path,
83
- regscale_ssp_id=regscale_ssp_id,
83
+ object_id=regscale_ssp_id,
84
84
  scan_date=scan_date,
85
85
  mappings_path=mappings_path,
86
86
  disable_mapping=disable_mapping,