regscale-cli 6.16.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 (481) hide show
  1. regscale/__init__.py +1 -0
  2. regscale/airflow/__init__.py +9 -0
  3. regscale/airflow/azure/__init__.py +9 -0
  4. regscale/airflow/azure/cli.py +89 -0
  5. regscale/airflow/azure/upload_dags.py +116 -0
  6. regscale/airflow/click_dags.py +127 -0
  7. regscale/airflow/click_mixins.py +82 -0
  8. regscale/airflow/config.py +25 -0
  9. regscale/airflow/factories/__init__.py +0 -0
  10. regscale/airflow/factories/connections.py +58 -0
  11. regscale/airflow/factories/workflows.py +78 -0
  12. regscale/airflow/hierarchy.py +88 -0
  13. regscale/airflow/operators/__init__.py +0 -0
  14. regscale/airflow/operators/click.py +36 -0
  15. regscale/airflow/sensors/__init__.py +0 -0
  16. regscale/airflow/sensors/sql.py +107 -0
  17. regscale/airflow/sessions/__init__.py +0 -0
  18. regscale/airflow/sessions/sql/__init__.py +3 -0
  19. regscale/airflow/sessions/sql/queries.py +64 -0
  20. regscale/airflow/sessions/sql/sql_server_queries.py +248 -0
  21. regscale/airflow/tasks/__init__.py +0 -0
  22. regscale/airflow/tasks/branches.py +22 -0
  23. regscale/airflow/tasks/cli.py +116 -0
  24. regscale/airflow/tasks/click.py +73 -0
  25. regscale/airflow/tasks/debugging.py +9 -0
  26. regscale/airflow/tasks/groups.py +116 -0
  27. regscale/airflow/tasks/init.py +60 -0
  28. regscale/airflow/tasks/states.py +47 -0
  29. regscale/airflow/tasks/workflows.py +36 -0
  30. regscale/ansible/__init__.py +9 -0
  31. regscale/core/__init__.py +0 -0
  32. regscale/core/app/__init__.py +3 -0
  33. regscale/core/app/api.py +571 -0
  34. regscale/core/app/application.py +665 -0
  35. regscale/core/app/internal/__init__.py +136 -0
  36. regscale/core/app/internal/admin_actions.py +230 -0
  37. regscale/core/app/internal/assessments_editor.py +873 -0
  38. regscale/core/app/internal/catalog.py +316 -0
  39. regscale/core/app/internal/comparison.py +459 -0
  40. regscale/core/app/internal/control_editor.py +571 -0
  41. regscale/core/app/internal/encrypt.py +79 -0
  42. regscale/core/app/internal/evidence.py +1240 -0
  43. regscale/core/app/internal/file_uploads.py +151 -0
  44. regscale/core/app/internal/healthcheck.py +66 -0
  45. regscale/core/app/internal/login.py +305 -0
  46. regscale/core/app/internal/migrations.py +240 -0
  47. regscale/core/app/internal/model_editor.py +1701 -0
  48. regscale/core/app/internal/poam_editor.py +632 -0
  49. regscale/core/app/internal/workflow.py +105 -0
  50. regscale/core/app/logz.py +74 -0
  51. regscale/core/app/utils/XMLIR.py +258 -0
  52. regscale/core/app/utils/__init__.py +0 -0
  53. regscale/core/app/utils/api_handler.py +358 -0
  54. regscale/core/app/utils/app_utils.py +1110 -0
  55. regscale/core/app/utils/catalog_utils/__init__.py +0 -0
  56. regscale/core/app/utils/catalog_utils/common.py +91 -0
  57. regscale/core/app/utils/catalog_utils/compare_catalog.py +193 -0
  58. regscale/core/app/utils/catalog_utils/diagnostic_catalog.py +97 -0
  59. regscale/core/app/utils/catalog_utils/download_catalog.py +103 -0
  60. regscale/core/app/utils/catalog_utils/update_catalog.py +718 -0
  61. regscale/core/app/utils/catalog_utils/update_catalog_v2.py +1378 -0
  62. regscale/core/app/utils/catalog_utils/update_catalog_v3.py +1272 -0
  63. regscale/core/app/utils/catalog_utils/update_plans.py +334 -0
  64. regscale/core/app/utils/file_utils.py +238 -0
  65. regscale/core/app/utils/parser_utils.py +81 -0
  66. regscale/core/app/utils/pickle_file_handler.py +57 -0
  67. regscale/core/app/utils/regscale_utils.py +319 -0
  68. regscale/core/app/utils/report_utils.py +119 -0
  69. regscale/core/app/utils/variables.py +226 -0
  70. regscale/core/decorators.py +31 -0
  71. regscale/core/lazy_group.py +65 -0
  72. regscale/core/login.py +63 -0
  73. regscale/core/server/__init__.py +0 -0
  74. regscale/core/server/flask_api.py +473 -0
  75. regscale/core/server/helpers.py +373 -0
  76. regscale/core/server/rest.py +64 -0
  77. regscale/core/server/static/css/bootstrap.css +6030 -0
  78. regscale/core/server/static/css/bootstrap.min.css +6 -0
  79. regscale/core/server/static/css/main.css +176 -0
  80. regscale/core/server/static/images/regscale-cli.svg +49 -0
  81. regscale/core/server/static/images/regscale.svg +38 -0
  82. regscale/core/server/templates/base.html +74 -0
  83. regscale/core/server/templates/index.html +43 -0
  84. regscale/core/server/templates/login.html +28 -0
  85. regscale/core/server/templates/make_base64.html +22 -0
  86. regscale/core/server/templates/upload_STIG.html +109 -0
  87. regscale/core/server/templates/upload_STIG_result.html +26 -0
  88. regscale/core/server/templates/upload_ssp.html +144 -0
  89. regscale/core/server/templates/upload_ssp_result.html +128 -0
  90. regscale/core/static/__init__.py +0 -0
  91. regscale/core/static/regex.py +14 -0
  92. regscale/core/utils/__init__.py +117 -0
  93. regscale/core/utils/click_utils.py +13 -0
  94. regscale/core/utils/date.py +238 -0
  95. regscale/core/utils/graphql.py +254 -0
  96. regscale/core/utils/urls.py +23 -0
  97. regscale/dev/__init__.py +6 -0
  98. regscale/dev/analysis.py +454 -0
  99. regscale/dev/cli.py +235 -0
  100. regscale/dev/code_gen.py +492 -0
  101. regscale/dev/dirs.py +69 -0
  102. regscale/dev/docs.py +384 -0
  103. regscale/dev/monitoring.py +26 -0
  104. regscale/dev/profiling.py +216 -0
  105. regscale/exceptions/__init__.py +4 -0
  106. regscale/exceptions/license_exception.py +7 -0
  107. regscale/exceptions/validation_exception.py +9 -0
  108. regscale/integrations/__init__.py +1 -0
  109. regscale/integrations/commercial/__init__.py +486 -0
  110. regscale/integrations/commercial/ad.py +433 -0
  111. regscale/integrations/commercial/amazon/__init__.py +0 -0
  112. regscale/integrations/commercial/amazon/common.py +106 -0
  113. regscale/integrations/commercial/aqua/__init__.py +0 -0
  114. regscale/integrations/commercial/aqua/aqua.py +91 -0
  115. regscale/integrations/commercial/aws/__init__.py +6 -0
  116. regscale/integrations/commercial/aws/cli.py +322 -0
  117. regscale/integrations/commercial/aws/inventory/__init__.py +110 -0
  118. regscale/integrations/commercial/aws/inventory/base.py +64 -0
  119. regscale/integrations/commercial/aws/inventory/resources/__init__.py +19 -0
  120. regscale/integrations/commercial/aws/inventory/resources/compute.py +234 -0
  121. regscale/integrations/commercial/aws/inventory/resources/containers.py +113 -0
  122. regscale/integrations/commercial/aws/inventory/resources/database.py +101 -0
  123. regscale/integrations/commercial/aws/inventory/resources/integration.py +237 -0
  124. regscale/integrations/commercial/aws/inventory/resources/networking.py +253 -0
  125. regscale/integrations/commercial/aws/inventory/resources/security.py +240 -0
  126. regscale/integrations/commercial/aws/inventory/resources/storage.py +91 -0
  127. regscale/integrations/commercial/aws/scanner.py +823 -0
  128. regscale/integrations/commercial/azure/__init__.py +0 -0
  129. regscale/integrations/commercial/azure/common.py +32 -0
  130. regscale/integrations/commercial/azure/intune.py +488 -0
  131. regscale/integrations/commercial/azure/scanner.py +49 -0
  132. regscale/integrations/commercial/burp.py +78 -0
  133. regscale/integrations/commercial/cpe.py +144 -0
  134. regscale/integrations/commercial/crowdstrike.py +1117 -0
  135. regscale/integrations/commercial/defender.py +1511 -0
  136. regscale/integrations/commercial/dependabot.py +210 -0
  137. regscale/integrations/commercial/durosuite/__init__.py +0 -0
  138. regscale/integrations/commercial/durosuite/api.py +1546 -0
  139. regscale/integrations/commercial/durosuite/process_devices.py +101 -0
  140. regscale/integrations/commercial/durosuite/scanner.py +637 -0
  141. regscale/integrations/commercial/durosuite/variables.py +21 -0
  142. regscale/integrations/commercial/ecr.py +90 -0
  143. regscale/integrations/commercial/gcp/__init__.py +237 -0
  144. regscale/integrations/commercial/gcp/auth.py +96 -0
  145. regscale/integrations/commercial/gcp/control_tests.py +238 -0
  146. regscale/integrations/commercial/gcp/variables.py +18 -0
  147. regscale/integrations/commercial/gitlab.py +332 -0
  148. regscale/integrations/commercial/grype.py +165 -0
  149. regscale/integrations/commercial/ibm.py +90 -0
  150. regscale/integrations/commercial/import_all/__init__.py +0 -0
  151. regscale/integrations/commercial/import_all/import_all_cmd.py +467 -0
  152. regscale/integrations/commercial/import_all/scan_file_fingerprints.json +27 -0
  153. regscale/integrations/commercial/jira.py +1046 -0
  154. regscale/integrations/commercial/mappings/__init__.py +0 -0
  155. regscale/integrations/commercial/mappings/csf_controls.json +713 -0
  156. regscale/integrations/commercial/mappings/nist_800_53_r5_controls.json +1516 -0
  157. regscale/integrations/commercial/nessus/__init__.py +0 -0
  158. regscale/integrations/commercial/nessus/nessus_utils.py +429 -0
  159. regscale/integrations/commercial/nessus/scanner.py +416 -0
  160. regscale/integrations/commercial/nexpose.py +90 -0
  161. regscale/integrations/commercial/okta.py +798 -0
  162. regscale/integrations/commercial/opentext/__init__.py +0 -0
  163. regscale/integrations/commercial/opentext/click.py +99 -0
  164. regscale/integrations/commercial/opentext/scanner.py +143 -0
  165. regscale/integrations/commercial/prisma.py +91 -0
  166. regscale/integrations/commercial/qualys.py +1462 -0
  167. regscale/integrations/commercial/salesforce.py +980 -0
  168. regscale/integrations/commercial/sap/__init__.py +0 -0
  169. regscale/integrations/commercial/sap/click.py +31 -0
  170. regscale/integrations/commercial/sap/sysdig/__init__.py +0 -0
  171. regscale/integrations/commercial/sap/sysdig/click.py +57 -0
  172. regscale/integrations/commercial/sap/sysdig/sysdig_scanner.py +190 -0
  173. regscale/integrations/commercial/sap/tenable/__init__.py +0 -0
  174. regscale/integrations/commercial/sap/tenable/click.py +49 -0
  175. regscale/integrations/commercial/sap/tenable/scanner.py +196 -0
  176. regscale/integrations/commercial/servicenow.py +1756 -0
  177. regscale/integrations/commercial/sicura/__init__.py +0 -0
  178. regscale/integrations/commercial/sicura/api.py +855 -0
  179. regscale/integrations/commercial/sicura/commands.py +73 -0
  180. regscale/integrations/commercial/sicura/scanner.py +481 -0
  181. regscale/integrations/commercial/sicura/variables.py +16 -0
  182. regscale/integrations/commercial/snyk.py +90 -0
  183. regscale/integrations/commercial/sonarcloud.py +260 -0
  184. regscale/integrations/commercial/sqlserver.py +369 -0
  185. regscale/integrations/commercial/stig_mapper_integration/__init__.py +0 -0
  186. regscale/integrations/commercial/stig_mapper_integration/click_commands.py +38 -0
  187. regscale/integrations/commercial/stig_mapper_integration/mapping_engine.py +353 -0
  188. regscale/integrations/commercial/stigv2/__init__.py +0 -0
  189. regscale/integrations/commercial/stigv2/ckl_parser.py +349 -0
  190. regscale/integrations/commercial/stigv2/click_commands.py +95 -0
  191. regscale/integrations/commercial/stigv2/stig_integration.py +202 -0
  192. regscale/integrations/commercial/synqly/__init__.py +0 -0
  193. regscale/integrations/commercial/synqly/assets.py +46 -0
  194. regscale/integrations/commercial/synqly/ticketing.py +132 -0
  195. regscale/integrations/commercial/synqly/vulnerabilities.py +223 -0
  196. regscale/integrations/commercial/synqly_jira.py +840 -0
  197. regscale/integrations/commercial/tenablev2/__init__.py +0 -0
  198. regscale/integrations/commercial/tenablev2/authenticate.py +31 -0
  199. regscale/integrations/commercial/tenablev2/click.py +1584 -0
  200. regscale/integrations/commercial/tenablev2/scanner.py +504 -0
  201. regscale/integrations/commercial/tenablev2/stig_parsers.py +140 -0
  202. regscale/integrations/commercial/tenablev2/utils.py +78 -0
  203. regscale/integrations/commercial/tenablev2/variables.py +17 -0
  204. regscale/integrations/commercial/trivy.py +162 -0
  205. regscale/integrations/commercial/veracode.py +96 -0
  206. regscale/integrations/commercial/wizv2/WizDataMixin.py +97 -0
  207. regscale/integrations/commercial/wizv2/__init__.py +0 -0
  208. regscale/integrations/commercial/wizv2/click.py +429 -0
  209. regscale/integrations/commercial/wizv2/constants.py +1001 -0
  210. regscale/integrations/commercial/wizv2/issue.py +361 -0
  211. regscale/integrations/commercial/wizv2/models.py +112 -0
  212. regscale/integrations/commercial/wizv2/parsers.py +339 -0
  213. regscale/integrations/commercial/wizv2/sbom.py +115 -0
  214. regscale/integrations/commercial/wizv2/scanner.py +416 -0
  215. regscale/integrations/commercial/wizv2/utils.py +796 -0
  216. regscale/integrations/commercial/wizv2/variables.py +39 -0
  217. regscale/integrations/commercial/wizv2/wiz_auth.py +159 -0
  218. regscale/integrations/commercial/xray.py +91 -0
  219. regscale/integrations/integration/__init__.py +2 -0
  220. regscale/integrations/integration/integration.py +26 -0
  221. regscale/integrations/integration/inventory.py +17 -0
  222. regscale/integrations/integration/issue.py +100 -0
  223. regscale/integrations/integration_override.py +149 -0
  224. regscale/integrations/public/__init__.py +103 -0
  225. regscale/integrations/public/cisa.py +641 -0
  226. regscale/integrations/public/criticality_updater.py +70 -0
  227. regscale/integrations/public/emass.py +411 -0
  228. regscale/integrations/public/emass_slcm_import.py +697 -0
  229. regscale/integrations/public/fedramp/__init__.py +0 -0
  230. regscale/integrations/public/fedramp/appendix_parser.py +548 -0
  231. regscale/integrations/public/fedramp/click.py +479 -0
  232. regscale/integrations/public/fedramp/components.py +714 -0
  233. regscale/integrations/public/fedramp/docx_parser.py +259 -0
  234. regscale/integrations/public/fedramp/fedramp_cis_crm.py +1124 -0
  235. regscale/integrations/public/fedramp/fedramp_common.py +3181 -0
  236. regscale/integrations/public/fedramp/fedramp_docx.py +388 -0
  237. regscale/integrations/public/fedramp/fedramp_five.py +2343 -0
  238. regscale/integrations/public/fedramp/fedramp_traversal.py +138 -0
  239. regscale/integrations/public/fedramp/import_fedramp_r4_ssp.py +279 -0
  240. regscale/integrations/public/fedramp/import_workbook.py +495 -0
  241. regscale/integrations/public/fedramp/inventory_items.py +244 -0
  242. regscale/integrations/public/fedramp/mappings/__init__.py +0 -0
  243. regscale/integrations/public/fedramp/mappings/fedramp_r4_parts.json +7388 -0
  244. regscale/integrations/public/fedramp/mappings/fedramp_r5_params.json +8636 -0
  245. regscale/integrations/public/fedramp/mappings/fedramp_r5_parts.json +9605 -0
  246. regscale/integrations/public/fedramp/mappings/system_roles.py +34 -0
  247. regscale/integrations/public/fedramp/mappings/user.py +175 -0
  248. regscale/integrations/public/fedramp/mappings/values.py +141 -0
  249. regscale/integrations/public/fedramp/markdown_parser.py +150 -0
  250. regscale/integrations/public/fedramp/metadata.py +689 -0
  251. regscale/integrations/public/fedramp/models/__init__.py +59 -0
  252. regscale/integrations/public/fedramp/models/leveraged_auth_new.py +168 -0
  253. regscale/integrations/public/fedramp/models/poam_importer.py +522 -0
  254. regscale/integrations/public/fedramp/parts_mapper.py +107 -0
  255. regscale/integrations/public/fedramp/poam/__init__.py +0 -0
  256. regscale/integrations/public/fedramp/poam/scanner.py +851 -0
  257. regscale/integrations/public/fedramp/properties.py +201 -0
  258. regscale/integrations/public/fedramp/reporting.py +84 -0
  259. regscale/integrations/public/fedramp/resources.py +496 -0
  260. regscale/integrations/public/fedramp/rosetta.py +110 -0
  261. regscale/integrations/public/fedramp/ssp_logger.py +87 -0
  262. regscale/integrations/public/fedramp/system_characteristics.py +922 -0
  263. regscale/integrations/public/fedramp/system_control_implementations.py +582 -0
  264. regscale/integrations/public/fedramp/system_implementation.py +190 -0
  265. regscale/integrations/public/fedramp/xml_utils.py +87 -0
  266. regscale/integrations/public/nist_catalog.py +275 -0
  267. regscale/integrations/public/oscal.py +1946 -0
  268. regscale/integrations/public/otx.py +169 -0
  269. regscale/integrations/scanner_integration.py +2692 -0
  270. regscale/integrations/variables.py +25 -0
  271. regscale/models/__init__.py +7 -0
  272. regscale/models/app_models/__init__.py +5 -0
  273. regscale/models/app_models/catalog_compare.py +213 -0
  274. regscale/models/app_models/click.py +252 -0
  275. regscale/models/app_models/datetime_encoder.py +21 -0
  276. regscale/models/app_models/import_validater.py +321 -0
  277. regscale/models/app_models/mapping.py +260 -0
  278. regscale/models/app_models/pipeline.py +37 -0
  279. regscale/models/click_models.py +413 -0
  280. regscale/models/config.py +154 -0
  281. regscale/models/email_style.css +67 -0
  282. regscale/models/hierarchy.py +8 -0
  283. regscale/models/inspect_models.py +79 -0
  284. regscale/models/integration_models/__init__.py +0 -0
  285. regscale/models/integration_models/amazon_models/__init__.py +0 -0
  286. regscale/models/integration_models/amazon_models/inspector.py +262 -0
  287. regscale/models/integration_models/amazon_models/inspector_scan.py +206 -0
  288. regscale/models/integration_models/aqua.py +247 -0
  289. regscale/models/integration_models/azure_alerts.py +255 -0
  290. regscale/models/integration_models/base64.py +23 -0
  291. regscale/models/integration_models/burp.py +433 -0
  292. regscale/models/integration_models/burp_models.py +128 -0
  293. regscale/models/integration_models/cisa_kev_data.json +19333 -0
  294. regscale/models/integration_models/defender_data.py +93 -0
  295. regscale/models/integration_models/defenderimport.py +143 -0
  296. regscale/models/integration_models/drf.py +443 -0
  297. regscale/models/integration_models/ecr_models/__init__.py +0 -0
  298. regscale/models/integration_models/ecr_models/data.py +69 -0
  299. regscale/models/integration_models/ecr_models/ecr.py +239 -0
  300. regscale/models/integration_models/flat_file_importer.py +1079 -0
  301. regscale/models/integration_models/grype_import.py +247 -0
  302. regscale/models/integration_models/ibm.py +126 -0
  303. regscale/models/integration_models/implementation_results.py +85 -0
  304. regscale/models/integration_models/nexpose.py +140 -0
  305. regscale/models/integration_models/prisma.py +202 -0
  306. regscale/models/integration_models/qualys.py +720 -0
  307. regscale/models/integration_models/qualys_scanner.py +160 -0
  308. regscale/models/integration_models/sbom/__init__.py +0 -0
  309. regscale/models/integration_models/sbom/cyclone_dx.py +139 -0
  310. regscale/models/integration_models/send_reminders.py +620 -0
  311. regscale/models/integration_models/snyk.py +155 -0
  312. regscale/models/integration_models/synqly_models/__init__.py +0 -0
  313. regscale/models/integration_models/synqly_models/capabilities.json +1 -0
  314. regscale/models/integration_models/synqly_models/connector_types.py +22 -0
  315. regscale/models/integration_models/synqly_models/connectors/__init__.py +7 -0
  316. regscale/models/integration_models/synqly_models/connectors/assets.py +97 -0
  317. regscale/models/integration_models/synqly_models/connectors/ticketing.py +583 -0
  318. regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +169 -0
  319. regscale/models/integration_models/synqly_models/ocsf_mapper.py +331 -0
  320. regscale/models/integration_models/synqly_models/param.py +72 -0
  321. regscale/models/integration_models/synqly_models/synqly_model.py +733 -0
  322. regscale/models/integration_models/synqly_models/tenants.py +39 -0
  323. regscale/models/integration_models/tenable_models/__init__.py +0 -0
  324. regscale/models/integration_models/tenable_models/integration.py +187 -0
  325. regscale/models/integration_models/tenable_models/models.py +513 -0
  326. regscale/models/integration_models/trivy_import.py +231 -0
  327. regscale/models/integration_models/veracode.py +217 -0
  328. regscale/models/integration_models/xray.py +135 -0
  329. regscale/models/locking.py +100 -0
  330. regscale/models/platform.py +110 -0
  331. regscale/models/regscale_models/__init__.py +67 -0
  332. regscale/models/regscale_models/assessment.py +570 -0
  333. regscale/models/regscale_models/assessment_plan.py +52 -0
  334. regscale/models/regscale_models/asset.py +567 -0
  335. regscale/models/regscale_models/asset_mapping.py +190 -0
  336. regscale/models/regscale_models/case.py +42 -0
  337. regscale/models/regscale_models/catalog.py +261 -0
  338. regscale/models/regscale_models/cci.py +46 -0
  339. regscale/models/regscale_models/change.py +167 -0
  340. regscale/models/regscale_models/checklist.py +372 -0
  341. regscale/models/regscale_models/comment.py +49 -0
  342. regscale/models/regscale_models/compliance_settings.py +112 -0
  343. regscale/models/regscale_models/component.py +412 -0
  344. regscale/models/regscale_models/component_mapping.py +65 -0
  345. regscale/models/regscale_models/control.py +38 -0
  346. regscale/models/regscale_models/control_implementation.py +1128 -0
  347. regscale/models/regscale_models/control_objective.py +261 -0
  348. regscale/models/regscale_models/control_parameter.py +100 -0
  349. regscale/models/regscale_models/control_test.py +34 -0
  350. regscale/models/regscale_models/control_test_plan.py +75 -0
  351. regscale/models/regscale_models/control_test_result.py +52 -0
  352. regscale/models/regscale_models/custom_field.py +245 -0
  353. regscale/models/regscale_models/data.py +109 -0
  354. regscale/models/regscale_models/data_center.py +40 -0
  355. regscale/models/regscale_models/deviation.py +203 -0
  356. regscale/models/regscale_models/email.py +97 -0
  357. regscale/models/regscale_models/evidence.py +47 -0
  358. regscale/models/regscale_models/evidence_mapping.py +40 -0
  359. regscale/models/regscale_models/facility.py +59 -0
  360. regscale/models/regscale_models/file.py +382 -0
  361. regscale/models/regscale_models/filetag.py +37 -0
  362. regscale/models/regscale_models/form_field_value.py +94 -0
  363. regscale/models/regscale_models/group.py +169 -0
  364. regscale/models/regscale_models/implementation_objective.py +335 -0
  365. regscale/models/regscale_models/implementation_option.py +275 -0
  366. regscale/models/regscale_models/implementation_role.py +33 -0
  367. regscale/models/regscale_models/incident.py +177 -0
  368. regscale/models/regscale_models/interconnection.py +43 -0
  369. regscale/models/regscale_models/issue.py +1176 -0
  370. regscale/models/regscale_models/leveraged_authorization.py +125 -0
  371. regscale/models/regscale_models/line_of_inquiry.py +52 -0
  372. regscale/models/regscale_models/link.py +205 -0
  373. regscale/models/regscale_models/meta_data.py +64 -0
  374. regscale/models/regscale_models/mixins/__init__.py +0 -0
  375. regscale/models/regscale_models/mixins/parent_cache.py +124 -0
  376. regscale/models/regscale_models/module.py +224 -0
  377. regscale/models/regscale_models/modules.py +191 -0
  378. regscale/models/regscale_models/objective.py +14 -0
  379. regscale/models/regscale_models/parameter.py +87 -0
  380. regscale/models/regscale_models/ports_protocol.py +81 -0
  381. regscale/models/regscale_models/privacy.py +89 -0
  382. regscale/models/regscale_models/profile.py +50 -0
  383. regscale/models/regscale_models/profile_link.py +68 -0
  384. regscale/models/regscale_models/profile_mapping.py +124 -0
  385. regscale/models/regscale_models/project.py +63 -0
  386. regscale/models/regscale_models/property.py +278 -0
  387. regscale/models/regscale_models/question.py +85 -0
  388. regscale/models/regscale_models/questionnaire.py +87 -0
  389. regscale/models/regscale_models/questionnaire_instance.py +177 -0
  390. regscale/models/regscale_models/rbac.py +132 -0
  391. regscale/models/regscale_models/reference.py +86 -0
  392. regscale/models/regscale_models/regscale_model.py +1643 -0
  393. regscale/models/regscale_models/requirement.py +29 -0
  394. regscale/models/regscale_models/risk.py +274 -0
  395. regscale/models/regscale_models/sbom.py +54 -0
  396. regscale/models/regscale_models/scan_history.py +436 -0
  397. regscale/models/regscale_models/search.py +53 -0
  398. regscale/models/regscale_models/security_control.py +132 -0
  399. regscale/models/regscale_models/security_plan.py +204 -0
  400. regscale/models/regscale_models/software_inventory.py +159 -0
  401. regscale/models/regscale_models/stake_holder.py +64 -0
  402. regscale/models/regscale_models/stig.py +647 -0
  403. regscale/models/regscale_models/supply_chain.py +152 -0
  404. regscale/models/regscale_models/system_role.py +188 -0
  405. regscale/models/regscale_models/system_role_external_assignment.py +40 -0
  406. regscale/models/regscale_models/tag.py +37 -0
  407. regscale/models/regscale_models/tag_mapping.py +19 -0
  408. regscale/models/regscale_models/task.py +133 -0
  409. regscale/models/regscale_models/threat.py +196 -0
  410. regscale/models/regscale_models/user.py +175 -0
  411. regscale/models/regscale_models/user_group.py +55 -0
  412. regscale/models/regscale_models/vulnerability.py +242 -0
  413. regscale/models/regscale_models/vulnerability_mapping.py +162 -0
  414. regscale/models/regscale_models/workflow.py +55 -0
  415. regscale/models/regscale_models/workflow_action.py +34 -0
  416. regscale/models/regscale_models/workflow_instance.py +269 -0
  417. regscale/models/regscale_models/workflow_instance_step.py +114 -0
  418. regscale/models/regscale_models/workflow_template.py +58 -0
  419. regscale/models/regscale_models/workflow_template_step.py +45 -0
  420. regscale/regscale.py +815 -0
  421. regscale/utils/__init__.py +7 -0
  422. regscale/utils/b64conversion.py +14 -0
  423. regscale/utils/click_utils.py +118 -0
  424. regscale/utils/decorators.py +48 -0
  425. regscale/utils/dict_utils.py +59 -0
  426. regscale/utils/files.py +79 -0
  427. regscale/utils/fxns.py +30 -0
  428. regscale/utils/graphql_client.py +113 -0
  429. regscale/utils/lists.py +16 -0
  430. regscale/utils/numbers.py +12 -0
  431. regscale/utils/shell.py +148 -0
  432. regscale/utils/string.py +121 -0
  433. regscale/utils/synqly_utils.py +165 -0
  434. regscale/utils/threading/__init__.py +8 -0
  435. regscale/utils/threading/threadhandler.py +131 -0
  436. regscale/utils/threading/threadsafe_counter.py +47 -0
  437. regscale/utils/threading/threadsafe_dict.py +242 -0
  438. regscale/utils/threading/threadsafe_list.py +83 -0
  439. regscale/utils/version.py +104 -0
  440. regscale/validation/__init__.py +0 -0
  441. regscale/validation/address.py +37 -0
  442. regscale/validation/record.py +48 -0
  443. regscale/visualization/__init__.py +5 -0
  444. regscale/visualization/click.py +34 -0
  445. regscale_cli-6.16.0.0.dist-info/LICENSE +21 -0
  446. regscale_cli-6.16.0.0.dist-info/METADATA +659 -0
  447. regscale_cli-6.16.0.0.dist-info/RECORD +481 -0
  448. regscale_cli-6.16.0.0.dist-info/WHEEL +5 -0
  449. regscale_cli-6.16.0.0.dist-info/entry_points.txt +6 -0
  450. regscale_cli-6.16.0.0.dist-info/top_level.txt +2 -0
  451. tests/fixtures/__init__.py +2 -0
  452. tests/fixtures/api.py +87 -0
  453. tests/fixtures/models.py +91 -0
  454. tests/fixtures/test_fixture.py +144 -0
  455. tests/mocks/__init__.py +0 -0
  456. tests/mocks/objects.py +3 -0
  457. tests/mocks/response.py +32 -0
  458. tests/mocks/xml.py +13 -0
  459. tests/regscale/__init__.py +0 -0
  460. tests/regscale/core/__init__.py +0 -0
  461. tests/regscale/core/test_api.py +232 -0
  462. tests/regscale/core/test_app.py +406 -0
  463. tests/regscale/core/test_login.py +37 -0
  464. tests/regscale/core/test_logz.py +66 -0
  465. tests/regscale/core/test_sbom_generator.py +87 -0
  466. tests/regscale/core/test_validation_utils.py +163 -0
  467. tests/regscale/core/test_version.py +78 -0
  468. tests/regscale/models/__init__.py +0 -0
  469. tests/regscale/models/test_asset.py +71 -0
  470. tests/regscale/models/test_config.py +26 -0
  471. tests/regscale/models/test_control_implementation.py +27 -0
  472. tests/regscale/models/test_import.py +97 -0
  473. tests/regscale/models/test_issue.py +36 -0
  474. tests/regscale/models/test_mapping.py +52 -0
  475. tests/regscale/models/test_platform.py +31 -0
  476. tests/regscale/models/test_regscale_model.py +346 -0
  477. tests/regscale/models/test_report.py +32 -0
  478. tests/regscale/models/test_tenable_integrations.py +118 -0
  479. tests/regscale/models/test_user_model.py +121 -0
  480. tests/regscale/test_about.py +19 -0
  481. tests/regscale/test_authorization.py +65 -0
@@ -0,0 +1,416 @@
1
+ """Module for Wiz vulnerability scanning integration."""
2
+
3
+ import datetime
4
+ import json
5
+ import logging
6
+ import os
7
+ import re
8
+ from typing import Any, Dict, Iterator, List, Optional
9
+
10
+ from regscale.core.app.utils.app_utils import check_file_path, get_current_datetime
11
+ from regscale.core.utils import get_base_protocol_from_port
12
+ from regscale.integrations.commercial.wizv2.constants import (
13
+ INVENTORY_FILE_PATH,
14
+ INVENTORY_QUERY,
15
+ WizVulnerabilityType,
16
+ get_wiz_vulnerability_queries,
17
+ )
18
+ from regscale.integrations.commercial.wizv2.parsers import (
19
+ collect_components_to_create,
20
+ fetch_wiz_data,
21
+ get_disk_storage,
22
+ get_ip_address_from_props,
23
+ get_latest_version,
24
+ get_network_info,
25
+ get_product_ids,
26
+ get_software_name_from_cpe,
27
+ handle_container_image_version,
28
+ handle_provider,
29
+ handle_software_version,
30
+ pull_resource_info_from_props,
31
+ )
32
+ from regscale.integrations.commercial.wizv2.utils import (
33
+ create_asset_type,
34
+ get_notes_from_wiz_props,
35
+ handle_management_type,
36
+ map_category,
37
+ )
38
+ from regscale.integrations.commercial.wizv2.variables import WizVariables
39
+ from regscale.integrations.commercial.wizv2.wiz_auth import wiz_authenticate
40
+ from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding, ScannerIntegration
41
+ from regscale.integrations.variables import ScannerVariables
42
+ from regscale.models import IssueStatus, regscale_models
43
+
44
+ logger = logging.getLogger("regscale")
45
+
46
+
47
+ class WizVulnerabilityIntegration(ScannerIntegration):
48
+ """Integration class for Wiz vulnerability scanning."""
49
+
50
+ title = "Wiz"
51
+ asset_identifier_field = "wizId"
52
+ issue_identifier_field = "wizId"
53
+ finding_severity_map = {
54
+ "Critical": regscale_models.IssueSeverity.Critical,
55
+ "High": regscale_models.IssueSeverity.High,
56
+ "Medium": regscale_models.IssueSeverity.Moderate,
57
+ "Low": regscale_models.IssueSeverity.Low,
58
+ }
59
+ asset_lookup = "vulnerableAsset"
60
+ wiz_token = None
61
+
62
+ @staticmethod
63
+ def get_variables():
64
+ return {
65
+ "first": 100,
66
+ "filterBy": {},
67
+ }
68
+
69
+ def authenticate(self, client_id: Optional[str] = None, client_secret: Optional[str] = None) -> None:
70
+ """
71
+ Authenticates to Wiz using the client ID and client secret
72
+
73
+ :param Optional[str] client_id: Wiz client ID
74
+ :param Optional[str] client_secret: WiZ client secret
75
+ :rtype: None
76
+ """
77
+ client_id = client_id or WizVariables.wizClientId
78
+ client_secret = client_secret or WizVariables.wizClientSecret
79
+ logger.info("Authenticating to Wiz...")
80
+ self.wiz_token = wiz_authenticate(client_id, client_secret)
81
+
82
+ def get_query_types(self, project_id: str) -> List[Dict[str, Any]]:
83
+ """Get the query types for vulnerability scanning.
84
+
85
+ :param str project_id: The project ID to get queries for
86
+ :return: List of query types
87
+ :rtype: List[Dict[str, Any]]
88
+ """
89
+ return get_wiz_vulnerability_queries(project_id=project_id)
90
+
91
+ def fetch_findings(self, *args, **kwargs) -> Iterator[IntegrationFinding]:
92
+ """
93
+ Fetches Wiz findings using the GraphQL API
94
+
95
+ :yield: IntegrationFinding objects
96
+ :rtype: Iterator[IntegrationFinding]
97
+ """
98
+ self.authenticate(kwargs.get("client_id"), kwargs.get("client_secret"))
99
+ project_id = kwargs.get("wiz_project_id")
100
+ if not project_id:
101
+ raise ValueError("Wiz project ID is required")
102
+
103
+ logger.info("Fetching Wiz findings...")
104
+
105
+ for wiz_vulnerability_type in self.get_query_types(project_id=project_id):
106
+ logger.info("Fetching Wiz findings for %s...", wiz_vulnerability_type["type"])
107
+
108
+ # Use the variables from the query type configuration
109
+ variables = wiz_vulnerability_type.get("variables", self.get_variables())
110
+
111
+ nodes = self.fetch_wiz_data_if_needed(
112
+ query=wiz_vulnerability_type["query"],
113
+ variables=variables,
114
+ topic_key=wiz_vulnerability_type["topic_key"],
115
+ file_path=wiz_vulnerability_type["file_path"],
116
+ )
117
+ yield from self.parse_findings(nodes, wiz_vulnerability_type["type"])
118
+
119
+ logger.info("Finished fetching Wiz findings.")
120
+
121
+ def parse_findings(
122
+ self, nodes: List[Dict[str, Any]], vulnerability_type: WizVulnerabilityType
123
+ ) -> Iterator[IntegrationFinding]:
124
+ """
125
+ Parses a list of Wiz finding nodes into IntegrationFinding objects.
126
+
127
+ :param List[Dict[str, Any]] nodes: List of Wiz finding nodes
128
+ :param WizVulnerabilityType vulnerability_type: The type of vulnerability
129
+ :yield: IntegrationFinding objects
130
+ :rtype: Iterator[IntegrationFinding]
131
+ """
132
+ for node in nodes:
133
+ finding = self.parse_finding(node, vulnerability_type)
134
+ if finding:
135
+ yield finding
136
+
137
+ @classmethod
138
+ def get_issue_severity(cls, severity: str) -> regscale_models.IssueSeverity:
139
+ """
140
+ Get the issue severity from the Wiz severity
141
+
142
+ :param str severity: The severity of the vulnerability
143
+ :return: The issue severity
144
+ :rtype: regscale_models.IssueSeverity
145
+ """
146
+ return cls.finding_severity_map.get(severity.capitalize(), regscale_models.IssueSeverity.Low)
147
+
148
+ def parse_finding(
149
+ self, node: Dict[str, Any], vulnerability_type: WizVulnerabilityType
150
+ ) -> Optional[IntegrationFinding]:
151
+ """
152
+ Parses a Wiz finding node into an IntegrationFinding object
153
+
154
+ :param Dict[str, Any] node: The Wiz finding node to parse
155
+ :param WizVulnerabilityType vulnerability_type: The type of vulnerability
156
+ :return: The parsed IntegrationFinding or None if parsing fails
157
+ :rtype: Optional[IntegrationFinding]
158
+ """
159
+ try:
160
+ asset_id = node.get(self.asset_lookup, {}).get("id")
161
+ if not asset_id:
162
+ return None
163
+
164
+ severity = self.get_issue_severity(node.get("severity", "Low"))
165
+
166
+ status = self.map_status_to_issue_status(node.get("status", "Open"))
167
+ name: str = node.get("name", "")
168
+ cve = (
169
+ name
170
+ if name and (name.startswith("CVE") or name.startswith("GHSA")) and not node.get("cve")
171
+ else node.get("cve", name)
172
+ )
173
+
174
+ return IntegrationFinding(
175
+ control_labels=[],
176
+ category="Wiz Vulnerability",
177
+ title=node.get("name", "Unknown vulnerability"),
178
+ description=node.get("description", ""),
179
+ severity=severity,
180
+ status=status,
181
+ asset_identifier=asset_id,
182
+ external_id=f"{node.get('sourceRule', {'id': cve}).get('id')}",
183
+ first_seen=node.get("firstDetectedAt") or node.get("firstSeenAt") or get_current_datetime(),
184
+ last_seen=node.get("lastDetectedAt") or node.get("analyzedAt") or get_current_datetime(),
185
+ remediation=node.get("description", ""),
186
+ cvss_score=node.get("score"),
187
+ cve=cve,
188
+ plugin_name=cve,
189
+ cvss_v3_base_score=node.get("score"),
190
+ source_rule_id=node.get("sourceRule", {}).get("id"),
191
+ vulnerability_type=vulnerability_type.value,
192
+ )
193
+ except (KeyError, TypeError, ValueError) as e:
194
+ logger.error("Error parsing Wiz finding: %s", str(e), exc_info=True)
195
+ return None
196
+
197
+ @staticmethod
198
+ def map_status_to_issue_status(status: str) -> IssueStatus:
199
+ """
200
+ Maps the Wiz status to issue status
201
+ :param str status: Status of the vulnerability
202
+ :returns: Issue status
203
+ :rtype: str
204
+ """
205
+ status_lower = status.lower()
206
+ if status_lower == "open":
207
+ return IssueStatus.Open
208
+ elif status_lower in ["resolved", "rejected"]:
209
+ return IssueStatus.Closed
210
+ return IssueStatus.Open
211
+
212
+ def fetch_assets(self, *args, **kwargs) -> Iterator[IntegrationAsset]:
213
+ """
214
+ Fetches Wiz assets using the GraphQL API
215
+
216
+ :yields: Iterator[IntegrationAsset]
217
+ """
218
+ self.authenticate(kwargs.get("client_id"), kwargs.get("client_secret"))
219
+ wiz_project_id = kwargs.get("wiz_project_id")
220
+ logger.info("Fetching Wiz assets...")
221
+ filter_by_override = kwargs.get("filter_by_override") or WizVariables.wizInventoryFilterBy
222
+ filter_by = self.get_filter_by(filter_by_override, wiz_project_id)
223
+
224
+ variables = self.get_variables()
225
+ variables["filterBy"].update(filter_by)
226
+
227
+ nodes = self.fetch_wiz_data_if_needed(
228
+ query=INVENTORY_QUERY, variables=variables, topic_key="cloudResources", file_path=INVENTORY_FILE_PATH
229
+ )
230
+ logger.info("Fetched %d Wiz assets.", len(nodes))
231
+ self.num_assets_to_process = len(nodes)
232
+
233
+ for node in nodes:
234
+ asset = self.parse_asset(node)
235
+ if asset:
236
+ yield asset
237
+
238
+ @staticmethod
239
+ def get_filter_by(filter_by_override, wiz_project_id):
240
+ if filter_by_override:
241
+ return json.loads(filter_by_override) if isinstance(filter_by_override, str) else filter_by_override
242
+ filter_by = {"project": wiz_project_id}
243
+ if WizVariables.wizLastInventoryPull and not WizVariables.wizFullPullLimitHours:
244
+ filter_by["updatedAt"] = {"after": WizVariables.wizLastInventoryPull}
245
+ return filter_by
246
+
247
+ def parse_asset(self, node: Dict[str, Any]) -> Optional[IntegrationAsset]:
248
+ """
249
+ Parses Wiz assets
250
+
251
+ :param Dict[str, Any] node: The Wiz asset to parse
252
+ :return: The parsed IntegrationAsset
253
+ :rtype: Optional[IntegrationAsset]
254
+ """
255
+ name = node.get("name", "")
256
+ wiz_entity = node.get("graphEntity", {})
257
+ if not wiz_entity:
258
+ logger.warning("No graph entity found for asset %s", name)
259
+ return None
260
+
261
+ wiz_entity_properties = wiz_entity.get("properties", {})
262
+ network_dict = get_network_info(wiz_entity_properties)
263
+ handle_provider_dict = handle_provider(wiz_entity_properties)
264
+ software_name_dict = get_software_name_from_cpe(wiz_entity_properties, name)
265
+ software_list = self.create_name_version_dict(wiz_entity_properties.get("installedPackages", []))
266
+
267
+ ports_and_protocols = self.get_ports_and_protocols(wiz_entity_properties)
268
+
269
+ if node.get("type", "") == "CONTAINER_IMAGE":
270
+ software_version = handle_container_image_version(
271
+ image_tags=wiz_entity_properties.get("imageTags", []), name=name
272
+ )
273
+ software_name = name.split(":")[0].split("/")[-1] if name else ""
274
+ software_vendor = name.split(":")[0].split("/")[1] if len(name.split(":")[0].split("/")) > 1 else None
275
+ else:
276
+ software_version = self.get_software_version(wiz_entity_properties, node)
277
+ software_name = self.get_software_name(software_name_dict, wiz_entity_properties, node)
278
+ software_vendor = self.get_software_vendor(software_name_dict, wiz_entity_properties, node)
279
+
280
+ return IntegrationAsset(
281
+ name=name,
282
+ external_id=node.get("name"),
283
+ asset_tag_number=node.get("id", ""),
284
+ other_tracking_number=node.get("id", ""),
285
+ identifier=node.get("id", ""),
286
+ asset_type=create_asset_type(node.get("type", "")),
287
+ asset_owner_id=ScannerVariables.userId,
288
+ parent_id=self.plan_id,
289
+ parent_module=regscale_models.SecurityPlan.get_module_slug(),
290
+ asset_category=map_category(node.get("type", "")),
291
+ date_last_updated=wiz_entity.get("lastSeen", ""),
292
+ management_type=handle_management_type(wiz_entity_properties),
293
+ status=self.map_wiz_status(wiz_entity_properties.get("status")),
294
+ ip_address=get_ip_address_from_props(wiz_entity_properties),
295
+ software_vendor=software_vendor,
296
+ software_version=software_version,
297
+ software_name=software_name,
298
+ location=wiz_entity_properties.get("region"),
299
+ notes=get_notes_from_wiz_props(wiz_entity_properties, node.get("id", "")),
300
+ model=wiz_entity_properties.get("nativeType"),
301
+ manufacturer=wiz_entity_properties.get("cloudPlatform"),
302
+ serial_number=get_product_ids(wiz_entity_properties),
303
+ is_public_facing=wiz_entity_properties.get("directlyInternetFacing", False),
304
+ azure_identifier=handle_provider_dict.get("azureIdentifier"),
305
+ mac_address=wiz_entity_properties.get("macAddress"),
306
+ fqdn=wiz_entity_properties.get("dnsName") or network_dict.get("dns"),
307
+ disk_storage=get_disk_storage(wiz_entity_properties) or 0,
308
+ cpu=pull_resource_info_from_props(wiz_entity_properties)[1] or 0,
309
+ ram=pull_resource_info_from_props(wiz_entity_properties)[0] or 0,
310
+ operating_system=wiz_entity_properties.get("operatingSystem"),
311
+ os_version=wiz_entity_properties.get("version"),
312
+ end_of_life_date=wiz_entity_properties.get("versionEndOfLifeDate"),
313
+ vlan_id=wiz_entity_properties.get("zone"),
314
+ uri=network_dict.get("url"),
315
+ aws_identifier=handle_provider_dict.get("awsIdentifier"),
316
+ google_identifier=handle_provider_dict.get("googleIdentifier"),
317
+ other_cloud_identifier=handle_provider_dict.get("otherCloudIdentifier"),
318
+ patch_level=get_latest_version(wiz_entity_properties),
319
+ cpe=wiz_entity_properties.get("cpe"),
320
+ component_names=collect_components_to_create([node], []),
321
+ source_data=node,
322
+ url=wiz_entity_properties.get("cloudProviderURL"),
323
+ ports_and_protocols=ports_and_protocols,
324
+ software_inventory=software_list,
325
+ )
326
+
327
+ @staticmethod
328
+ def get_ports_and_protocols(wiz_entity_properties):
329
+ start_port = wiz_entity_properties.get("portStart")
330
+ if start_port:
331
+ end_port = wiz_entity_properties.get("portEnd") or start_port
332
+ protocol = wiz_entity_properties.get("protocols", wiz_entity_properties.get("protocol"))
333
+ if protocol in ["other", None]:
334
+ protocol = get_base_protocol_from_port(start_port)
335
+ return [{"start_port": start_port, "end_port": end_port, "protocol": protocol}]
336
+ return []
337
+
338
+ @staticmethod
339
+ def get_software_vendor(software_name_dict, wiz_entity_properties, node):
340
+ if map_category(node.get("type")) == regscale_models.AssetCategory.Software:
341
+ return software_name_dict.get("software_vendor") or wiz_entity_properties.get("cloudPlatform")
342
+ return None
343
+
344
+ @staticmethod
345
+ def get_software_version(wiz_entity_properties, node):
346
+ if map_category(node.get("type")) == regscale_models.AssetCategory.Software:
347
+ return handle_software_version(wiz_entity_properties, map_category(node.get("type"))) or "1.0"
348
+ return None
349
+
350
+ @staticmethod
351
+ def get_software_name(software_name_dict, wiz_entity_properties, node):
352
+ if map_category(node.get("type")) == regscale_models.AssetCategory.Software:
353
+ return software_name_dict.get("software_name") or wiz_entity_properties.get("nativeType")
354
+ return None
355
+
356
+ @staticmethod
357
+ def create_name_version_dict(package_list: List[str]) -> List[Dict[str, str]]:
358
+ """
359
+ Creates a dictionary of package names and their versions from a list of strings in the format "name (version)".
360
+
361
+ :param List[str] package_list: A list of strings containing package names and versions.
362
+ :return Dict[str, str]: A dictionary with package names as keys and versions as values.
363
+ """
364
+ software_inventory = []
365
+ for package in package_list:
366
+ match = re.match(r"(.+?) \((.+?)\)", package)
367
+ if match:
368
+ name, version = match.groups()
369
+ software_inventory.append({"name": name, "version": version})
370
+ return software_inventory
371
+
372
+ @staticmethod
373
+ def map_wiz_status(wiz_status: Optional[str]) -> regscale_models.AssetStatus:
374
+ """Map Wiz status to RegScale status."""
375
+ return regscale_models.AssetStatus.Active if wiz_status != "Inactive" else regscale_models.AssetStatus.Inactive
376
+
377
+ def fetch_wiz_data_if_needed(self, query: str, variables: Dict, topic_key: str, file_path: str) -> List[Dict]:
378
+ """
379
+ Fetch Wiz data if needed and save to file if not already fetched within the last 8 hours and return the data
380
+
381
+ :param str query: GraphQL query string
382
+ :param Dict variables: Query variables
383
+ :param str topic_key: The key for the data in the response
384
+ :param str file_path: Path to save the fetched data
385
+ :return: List of nodes as dictionaries
386
+ :rtype: List[Dict]
387
+ """
388
+ fetch_interval = datetime.timedelta(hours=WizVariables.wizFullPullLimitHours or 8) # Interval to fetch new data
389
+ current_time = datetime.datetime.now()
390
+ check_file_path(os.path.dirname(file_path))
391
+
392
+ if os.path.exists(file_path):
393
+ file_mod_time = datetime.datetime.fromtimestamp(os.path.getmtime(file_path))
394
+ if current_time - file_mod_time < fetch_interval:
395
+ logger.info("File %s is newer than %s hours. Using cached data...", file_path, fetch_interval)
396
+ with open(file_path, "r", encoding="utf-8") as file:
397
+ return json.load(file)
398
+ else:
399
+ logger.info("File %s is older than %s hours. Fetching new data...", file_path, fetch_interval)
400
+ else:
401
+ logger.info("File %s does not exist. Fetching new data...", file_path)
402
+
403
+ if not self.wiz_token:
404
+ raise ValueError("Wiz token is not set. Please authenticate first.")
405
+
406
+ nodes = fetch_wiz_data(
407
+ query=query,
408
+ variables=variables,
409
+ api_endpoint_url=WizVariables.wizUrl,
410
+ token=self.wiz_token,
411
+ topic_key=topic_key,
412
+ )
413
+ with open(file_path, "w", encoding="utf-8") as file:
414
+ json.dump(nodes, file)
415
+
416
+ return nodes