regscale-cli 6.19.0.1__py3-none-any.whl → 6.19.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 (28) hide show
  1. regscale/__init__.py +1 -1
  2. regscale/core/app/utils/app_utils.py +1 -1
  3. regscale/integrations/commercial/amazon/common.py +5 -4
  4. regscale/integrations/commercial/aws/scanner.py +3 -2
  5. regscale/integrations/commercial/synqly/assets.py +10 -0
  6. regscale/integrations/commercial/synqly/ticketing.py +25 -0
  7. regscale/integrations/commercial/tenablev2/commands.py +34 -4
  8. regscale/integrations/commercial/tenablev2/sync_compliance.py +550 -0
  9. regscale/integrations/commercial/wizv2/click.py +3 -3
  10. regscale/integrations/scanner_integration.py +3 -2
  11. regscale/models/app_models/import_validater.py +2 -0
  12. regscale/models/integration_models/cisa_kev_data.json +188 -10
  13. regscale/models/integration_models/flat_file_importer/__init__.py +26 -9
  14. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  15. regscale/models/regscale_models/assessment_plan.py +1 -1
  16. regscale/models/regscale_models/assessment_result.py +39 -0
  17. regscale/models/regscale_models/line_of_inquiry.py +2 -2
  18. regscale/models/regscale_models/regscale_model.py +16 -15
  19. regscale/models/regscale_models/software_inventory.py +1 -1
  20. regscale/models/regscale_models/supply_chain.py +4 -4
  21. regscale/models/regscale_models/user.py +11 -0
  22. regscale/utils/graphql_client.py +2 -1
  23. {regscale_cli-6.19.0.1.dist-info → regscale_cli-6.19.2.0.dist-info}/METADATA +45 -45
  24. {regscale_cli-6.19.0.1.dist-info → regscale_cli-6.19.2.0.dist-info}/RECORD +28 -26
  25. {regscale_cli-6.19.0.1.dist-info → regscale_cli-6.19.2.0.dist-info}/LICENSE +0 -0
  26. {regscale_cli-6.19.0.1.dist-info → regscale_cli-6.19.2.0.dist-info}/WHEEL +0 -0
  27. {regscale_cli-6.19.0.1.dist-info → regscale_cli-6.19.2.0.dist-info}/entry_points.txt +0 -0
  28. {regscale_cli-6.19.0.1.dist-info → regscale_cli-6.19.2.0.dist-info}/top_level.txt +0 -0
regscale/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "6.19.0.1"
1
+ __version__ = "6.19.2.0"
@@ -642,7 +642,7 @@ def save_to_json(file: Path, data: Any, output_log: bool) -> None:
642
642
  with open(file, "w", encoding="utf-8") as outfile:
643
643
  outfile.write(str(data))
644
644
  if output_log:
645
- logger.info("Data successfully saved to %s", file.absolute())
645
+ logger.info("Data successfully saved to %s", file.name)
646
646
 
647
647
 
648
648
  def save_data_to(file: Path, data: Any, output_log: bool = True, transpose_data: bool = True) -> None:
@@ -56,17 +56,18 @@ def determine_status_and_results(finding: Any) -> Tuple[str, Optional[str]]:
56
56
  results = None
57
57
  if "Compliance" in finding.keys():
58
58
  status = "Fail" if finding["Compliance"]["Status"] == "FAILED" else "Pass"
59
- results = ", ".join(finding["Compliance"]["RelatedRequirements"])
59
+ results = ", ".join(finding.get("Compliance", {}).get("RelatedRequirements", [])) or "N/A"
60
60
  if "FindingProviderFields" in finding.keys():
61
61
  status = (
62
62
  "Fail"
63
- if finding["FindingProviderFields"]["Severity"]["Label"] in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
63
+ if finding.get("FindingProviderFields", {}).get("Severity", {}).get("Label", "")
64
+ in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
64
65
  else "Pass"
65
66
  )
66
67
  if "PatchSummary" in finding.keys() and not results:
67
68
  results = (
68
- f"{finding['PatchSummary']['MissingCount']} Missing Patch(s) of "
69
- "{finding['PatchSummary']['InstalledCount']}"
69
+ f"{finding.get('PatchSummary', {}).get('MissingCount', 0)} Missing Patch(s) of "
70
+ "{finding.get('PatchSummary', {}).get('InstalledCount', 0)}"
70
71
  )
71
72
  return status, results
72
73
 
@@ -711,12 +711,13 @@ Description: {description if isinstance(description, str) else ''}"""
711
711
  )
712
712
  if not region:
713
713
  logger.warning("AWS region not provided. Defaulting to 'us-east-1'.")
714
- client = boto3.client(
715
- "securityhub",
714
+ session = boto3.Session(
716
715
  region_name=kwargs.get(region, "us-east-1"),
717
716
  aws_access_key_id=aws_secret_key_id,
718
717
  aws_secret_access_key=aws_secret_access_key,
718
+ aws_session_token=kwargs.get("aws_session_token"),
719
719
  )
720
+ client = session.client("securityhub")
720
721
  aws_findings = fetch_aws_findings(aws_client=client)
721
722
  self.num_findings_to_process = len(aws_findings)
722
723
  for finding in aws_findings:
@@ -33,6 +33,16 @@ def sync_nozomi_vantage(regscale_ssp_id: int) -> None:
33
33
  assets_nozomi_vantage.run_sync(regscale_ssp_id=regscale_ssp_id)
34
34
 
35
35
 
36
+ @assets.command(name="sync_qualys_cloud")
37
+ @regscale_ssp_id()
38
+ def sync_qualys_cloud(regscale_ssp_id: int) -> None:
39
+ """Sync Assets from Qualys Cloud to RegScale."""
40
+ from regscale.models.integration_models.synqly_models.connectors import Assets
41
+
42
+ assets_qualys_cloud = Assets("qualys_cloud")
43
+ assets_qualys_cloud.run_sync(regscale_ssp_id=regscale_ssp_id)
44
+
45
+
36
46
  @assets.command(name="sync_servicenow")
37
47
  @regscale_ssp_id()
38
48
  def sync_servicenow(regscale_ssp_id: int) -> None:
@@ -158,4 +158,29 @@ def sync_torq(regscale_id: int, regscale_module: str, name: str) -> None:
158
158
  ticketing_torq.run_sync(regscale_id=regscale_id, regscale_module=regscale_module, name=name)
159
159
 
160
160
 
161
+ @ticketing.command(name="sync_zendesk")
162
+ @regscale_id()
163
+ @regscale_module()
164
+ @click.option(
165
+ "--name",
166
+ type=click.STRING,
167
+ help="zendesk name",
168
+ required=True,
169
+ prompt="zendesk name",
170
+ )
171
+ @click.option(
172
+ "--subject",
173
+ type=click.STRING,
174
+ help="zendesk subject",
175
+ required=True,
176
+ prompt="zendesk subject",
177
+ )
178
+ def sync_zendesk(regscale_id: int, regscale_module: str, name: str, subject: str) -> None:
179
+ """Sync Ticketing data between Zendesk and RegScale."""
180
+ from regscale.models.integration_models.synqly_models.connectors import Ticketing
181
+
182
+ ticketing_zendesk = Ticketing("zendesk")
183
+ ticketing_zendesk.run_sync(regscale_id=regscale_id, regscale_module=regscale_module, name=name, subject=subject)
184
+
185
+
161
186
  # pylint: enable=line-too-long
@@ -30,12 +30,17 @@ from regscale.integrations.commercial.tenablev2.jsonl_scanner import TenableSCJs
30
30
  from regscale.integrations.commercial.tenablev2.sc_scanner import SCIntegration
31
31
  from regscale.integrations.commercial.tenablev2.variables import TenableVariables
32
32
  from regscale.models import regscale_id, regscale_ssp_id
33
- from regscale.models.app_models.click import save_output_to, file_types
34
- from regscale.models.regscale_models.security_plan import SecurityPlan
33
+ from regscale.models.app_models.click import file_types, hidden_file_path, save_output_to
34
+ from regscale.models.regscale_models import SecurityPlan
35
35
 
36
36
  logger = logging.getLogger("regscale")
37
37
  console = Console()
38
38
  artifacts_dir = "./artifacts"
39
+ REGSCALE_INC = "RegScale, Inc."
40
+ REGSCALE_CLI = "RegScale CLI"
41
+ FULLY_IMPLEMENTED = "Fully Implemented"
42
+ NOT_IMPLEMENTED = "Not Implemented"
43
+ IN_REMEDIATION = "In Remediation"
39
44
 
40
45
 
41
46
  # Define a helper function for gen_client to replace the original one
@@ -146,7 +151,7 @@ def io_sync_assets(regscale_ssp_id: int, tags: List[Tuple[str, str]] = None):
146
151
  from regscale.integrations.commercial.tenablev2.scanner import TenableIntegration
147
152
 
148
153
  integration = TenableIntegration(plan_id=regscale_ssp_id, tags=tags)
149
- integration.sync_assets()
154
+ integration.sync_assets(plan_id=regscale_ssp_id)
150
155
 
151
156
  console.print("[bold green]Tenable.io asset synchronization complete.[/bold green]")
152
157
  except Exception as e:
@@ -185,7 +190,7 @@ def io_sync_findings(
185
190
  from regscale.integrations.commercial.tenablev2.scanner import TenableIntegration
186
191
 
187
192
  integration = TenableIntegration(plan_id=regscale_ssp_id, tags=tags, scan_date=scan_date)
188
- integration.sync_findings(severity=severity)
193
+ integration.sync_findings(plan_id=regscale_ssp_id, severity=severity)
189
194
 
190
195
  console.print("[bold green]Tenable.io finding synchronization complete.[/bold green]")
191
196
  except Exception as e:
@@ -768,6 +773,31 @@ def sync_jsonl(
768
773
  logger.error(f"Error in Tenable SC JSONL sync: {str(e)}", exc_info=True)
769
774
 
770
775
 
776
+ @io.command(name="sync_compliance_controls")
777
+ @regscale_ssp_id()
778
+ @click.option(
779
+ "--catalog_id",
780
+ type=click.INT,
781
+ help="The ID number from RegScale Catalog that the System Security Plan's controls belong to",
782
+ prompt="Enter RegScale Catalog ID",
783
+ required=True,
784
+ )
785
+ @click.option(
786
+ "--framework",
787
+ required=True,
788
+ type=click.Choice(["800-53", "800-53r5", "CSF", "800-171"], case_sensitive=True),
789
+ help="The framework to use. from Tenable.io frameworks MUST be the same RegScale Catalog of controls",
790
+ )
791
+ @hidden_file_path(help="The file path to load control data instead of fetching from Tenable.io")
792
+ def sync_compliance_data(regscale_ssp_id: int, catalog_id: int, framework: str, offline: Optional[Path] = None):
793
+ """
794
+ Sync the compliance data from Tenable.io to create control implementations for controls in frameworks.
795
+ """
796
+ from regscale.integrations.commercial.tenablev2.sync_compliance import sync_compliance_data
797
+
798
+ sync_compliance_data(ssp_id=regscale_ssp_id, catalog_id=catalog_id, framework=framework, offline=offline)
799
+
800
+
771
801
  # Add import_nessus to __all__ exports at the end of the file
772
802
  __all__ = [
773
803
  "tenable",