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,125 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for Leveraged Authorizations in the application"""
4
+ from enum import Enum
5
+ from typing import Optional, Union
6
+ from urllib.parse import urljoin
7
+
8
+ from pydantic import field_validator, Field, ConfigDict
9
+
10
+ from regscale.core.app.api import Api
11
+ from regscale.core.app.application import Application
12
+ from regscale.core.app.utils.app_utils import get_current_datetime
13
+ from .regscale_model import RegScaleModel
14
+
15
+
16
+ class NatureOfAgreement(str, Enum):
17
+ """Asset Status Enum"""
18
+
19
+ EULA = "End User Licensing Agreement (EULA)"
20
+ SLA = "Service Level Agreement (SLA)"
21
+ LicenseAgreement = "License Agreement"
22
+ Contract = "Contract"
23
+ Other = "Other"
24
+
25
+ def __str__(self):
26
+ return self.value
27
+
28
+
29
+ class ImpactLevel(str, Enum):
30
+ """Asset Status Enum"""
31
+
32
+ LowSaaS = "Low Impact SaaS"
33
+ Low = "Low"
34
+ Moderate = "Moderate"
35
+ High = "High"
36
+ NonAuthorized = "Non-Authorized Cloud Service Provider (CSP)"
37
+
38
+ def __str__(self):
39
+ return self.value
40
+
41
+
42
+ class LeveragedAuthorization(RegScaleModel):
43
+ """LeveragedAuthorizations model."""
44
+
45
+ _module_slug = "leveraged-authorization"
46
+ _get_objects_for_list = True
47
+
48
+ id: Optional[int] = 0
49
+ isPublic: Optional[bool] = True
50
+ uuid: Optional[str] = None
51
+ title: str
52
+ fedrampId: Optional[str] = None
53
+ ownerId: str
54
+ securityPlanId: int
55
+ natureOfAgreement: Union[NatureOfAgreement, str] = NatureOfAgreement.Other
56
+ impactLevel: Union[ImpactLevel, str] = ImpactLevel.Low
57
+ dateAuthorized: Optional[str] = None
58
+ description: Optional[str] = None
59
+ dataTypes: Optional[str] = None
60
+ servicesUsed: Optional[str] = None
61
+ authenticationType: Optional[str] = None
62
+ authorizedUserTypes: Optional[str] = None
63
+ authorizationType: Optional[str] = None # not to be confused with authenticationType
64
+ securityPlanLink: Optional[str] = ""
65
+ crmLink: Optional[str] = ""
66
+ responsibilityAndInheritanceLink: Optional[str] = ""
67
+ createdById: str = Field(default_factory=RegScaleModel.get_user_id)
68
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
69
+ lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
70
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
71
+ tenantsId: Optional[int] = 1
72
+
73
+ @staticmethod
74
+ def _get_additional_endpoints() -> ConfigDict:
75
+ """
76
+ Get additional endpoints for the PortsProtocols model.
77
+
78
+ :return: A dictionary of additional endpoints
79
+ :rtype: ConfigDict
80
+ """
81
+ return ConfigDict( # type: ignore
82
+ get_all_by_parent="/api/{model_slug}/getAllByParent/{intParentID}",
83
+ )
84
+
85
+ @classmethod
86
+ @field_validator(
87
+ "crmLink",
88
+ "responsibilityAndInheritanceLink",
89
+ "securityPlanLink",
90
+ mode="before",
91
+ check_fields=True,
92
+ )
93
+ def validate_fields(cls, value: Optional[str]) -> str:
94
+ """
95
+ Validate the CRM link, responsibility and inheritance link, and security plan link.
96
+
97
+ :param Optional[str] value: The field value.
98
+ :return: The validated field value or empty string.
99
+ :rtype: str
100
+ """
101
+ if not value:
102
+ value = ""
103
+ return value
104
+
105
+ @staticmethod
106
+ def insert_leveraged_authorizations(app: Application, leveraged_auth: "LeveragedAuthorization") -> dict:
107
+ """
108
+ Insert a leveraged authorization into the database.
109
+
110
+ :param Application app: The application instance.
111
+ :param LeveragedAuthorization leveraged_auth: The leveraged authorization to insert.
112
+ :return: The response from the API or raise an exception
113
+ :rtype: dict
114
+ """
115
+ api = Api()
116
+
117
+ # Construct the URL by joining the domain and endpoint
118
+ url = urljoin(app.config.get("domain"), "/api/leveraged-authorization")
119
+ # Convert the Pydantic model to a dictionary
120
+ data = leveraged_auth.dict()
121
+ # Make the POST request to insert the data
122
+ response = api.post(url, json=data)
123
+
124
+ # Check for success and handle the response as needed
125
+ return response.json() if response.ok else response.raise_for_status()
@@ -0,0 +1,52 @@
1
+ from enum import Enum
2
+ from typing import Optional, Union
3
+
4
+ from pydantic import Field, ConfigDict
5
+
6
+ from regscale.core.app.utils.app_utils import get_current_datetime
7
+ from regscale.models.regscale_models import RegScaleModel
8
+
9
+
10
+ class LoIType(str, Enum):
11
+ """Lines of Inquiry Type Enum"""
12
+
13
+ Audit = "Audit Question"
14
+ Data = "Data Collection"
15
+
16
+
17
+ class LinesOfInquiry(RegScaleModel):
18
+ """Lines of Inquiry Model"""
19
+
20
+ _module_slug = "lines-of-inquiry"
21
+ _unique_fields = ["id"]
22
+ _parent_id_field = "assessmentPlanId"
23
+
24
+ id: int = 0
25
+ isPublic: bool = True
26
+ uuid: Optional[str] = None
27
+ inquiry: Optional[str] = None
28
+ requirement: Optional[str] = None
29
+ assessmentPlanId: int = 0
30
+ weight: Optional[int] = 1
31
+ lineType: Union[LoIType, str] = LoIType.Audit
32
+ dataType: Optional[str] = Field(default_factory=get_current_datetime)
33
+ choiceList: Optional[str] = None
34
+ requiresScoring: bool = True
35
+ createdBy: Optional[str] = None
36
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
37
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
38
+ lastUpdatedBy: Optional[str] = None
39
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
40
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
41
+
42
+ @staticmethod
43
+ def _get_additional_endpoints() -> ConfigDict:
44
+ """
45
+ Get additional endpoints for the Components model.
46
+
47
+ :return: A dictionary of additional endpoints
48
+ :rtype: ConfigDict
49
+ """
50
+ return ConfigDict( # type: ignore
51
+ get_all_by_parent="/api/{model_slug}/getAllByParent/{intAssessmentID}",
52
+ )
@@ -0,0 +1,205 @@
1
+ """Model for a RegScale Link"""
2
+
3
+ import warnings
4
+ from concurrent.futures import ThreadPoolExecutor, as_completed
5
+ from typing import List, Optional
6
+
7
+ from pydantic import ConfigDict, Field
8
+ from requests import JSONDecodeError, Response
9
+
10
+ from regscale.core.app.api import Api
11
+ from regscale.core.app.application import Application
12
+ from regscale.core.app.logz import create_logger
13
+ from regscale.core.app.utils.app_utils import get_current_datetime
14
+ from .regscale_model import RegScaleModel
15
+
16
+
17
+ class Link(RegScaleModel):
18
+ _module_slug = "links"
19
+ _unique_fields = [
20
+ ["title", "parentID", "parentModule"],
21
+ ]
22
+ _parent_id_field = "parentID"
23
+
24
+ id: Optional[int] = 0
25
+ url: str
26
+ title: str
27
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
28
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
29
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
30
+ isPublic: bool = True
31
+ parentID: Optional[int] = None
32
+ parentModule: Optional[str] = None
33
+ tenantsId: Optional[int] = None
34
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
35
+ otherAttributes: Optional[str] = None
36
+ externalId: Optional[str] = None
37
+
38
+ @staticmethod
39
+ def _get_additional_endpoints() -> ConfigDict:
40
+ """
41
+ Get additional endpoints for the Links model.
42
+
43
+ :return: A dictionary of additional endpoints
44
+ :rtype: ConfigDict
45
+ """
46
+ return ConfigDict(
47
+ get_all_by_part="/api/{model_slug}/getAllByPart/{intParentID}/{strModule}/{strType}/{strPart}",
48
+ get_all_from_list="/api/{model_slug}/getAllFromList",
49
+ batch_create="/api/{model_slug}/batchCreate",
50
+ batch_update="/api/{model_slug}/batchUpdate",
51
+ )
52
+
53
+ def __hash__(self) -> hash:
54
+ """
55
+ Enable object to be hashable
56
+
57
+ :return: Hashed Link
58
+ :rtype: hash
59
+ """
60
+ return hash(
61
+ (
62
+ self.title,
63
+ self.parentID,
64
+ self.parentModule,
65
+ self.url,
66
+ )
67
+ )
68
+
69
+ def __eq__(self, other: "Link") -> bool:
70
+ """
71
+ Determine if two Links are equal
72
+
73
+ :param Link other: Link Object to compare to
74
+ :return: True if equal
75
+ :rtype: bool
76
+ """
77
+ return (
78
+ self.title == other.title
79
+ and self.parentID == other.parentID
80
+ and self.parentModule == other.parentModule
81
+ and self.url == other.url
82
+ )
83
+
84
+ @staticmethod
85
+ def update_link(app: Application, link: "Link") -> Optional["Link"]:
86
+ """
87
+ Update a Link in RegScale via API
88
+
89
+ :param Application app: Application
90
+ :param Link link: Link to update
91
+ :return: Updated Link
92
+ :rtype: Optional[Link]
93
+ """
94
+ warnings.warn(
95
+ "This function is deprecated and will be removed in the future. Use Link.save() instead.",
96
+ DeprecationWarning,
97
+ stacklevel=2,
98
+ )
99
+ api = Api()
100
+ link_id = link.id
101
+
102
+ response = api.put(app.config["domain"] + f"/api/links/{link_id}", json=link.dict())
103
+ if response.status_code == 200:
104
+ try:
105
+ link = Link(**response.json())
106
+ except JSONDecodeError:
107
+ link = None
108
+ return link
109
+
110
+ @staticmethod
111
+ def bulk_insert(api: Api, links: List["Link"], thread_count: Optional[int] = 10) -> List[Response]:
112
+ """
113
+ Bulk insert Links to the RegScale API
114
+
115
+ :param Api api: RegScale API
116
+ :param List[Link] links: List of links to insert
117
+ :param Optional[int] thread_count: Number of threads to use, defaults to 10
118
+ :return: List of Responses from RegScale API
119
+ :rtype: List[Response]
120
+ """
121
+ warnings.warn(
122
+ "This function is deprecated and will be removed in the future. Use Link.batch_create() instead.",
123
+ DeprecationWarning,
124
+ stacklevel=2,
125
+ )
126
+
127
+ app = api.app
128
+ results = []
129
+
130
+ # use threadpoolexecutor to speed up inserts
131
+ with ThreadPoolExecutor(max_workers=thread_count) as executor:
132
+ futures = [
133
+ executor.submit(
134
+ Link.insert_link,
135
+ app,
136
+ link,
137
+ )
138
+ for link in links
139
+ ]
140
+ for future in as_completed(futures):
141
+ results.append(future.result())
142
+ return results
143
+
144
+ @staticmethod
145
+ def insert_link(app: Application, link: "Link") -> "Link":
146
+ """
147
+ Insert a Link into RegScale
148
+
149
+ :param Application app: Application
150
+ :param Link link: Link to insert
151
+ :return: Inserted Link
152
+ :rtype: Link
153
+ """
154
+ warnings.warn(
155
+ "This function is deprecated and will be removed in the future. Use Link.create() instead.",
156
+ DeprecationWarning,
157
+ stacklevel=2,
158
+ )
159
+ api = Api()
160
+ logger = create_logger()
161
+ response = api.post(app.config["domain"] + "/api/links", json=link.dict())
162
+ if response.status_code == 200:
163
+ try:
164
+ link = Link(**response.json())
165
+ except JSONDecodeError as jex:
166
+ logger.error("Unable to read link:\n%s", jex)
167
+ link = None
168
+ else:
169
+ logger.warning("Unable to insert link: %s", link.title)
170
+ return link
171
+
172
+ @staticmethod
173
+ def fetch_links_by_parent(
174
+ app: Application,
175
+ regscale_id: int,
176
+ regscale_module: str,
177
+ ) -> List["Link"]:
178
+ """
179
+ Fetch Links by Parent ID and Module
180
+
181
+ :param Application app: Application
182
+ :param int regscale_id: RegScale ID
183
+ :param str regscale_module: RegScale Module
184
+ :return: List of Links
185
+ :rtype: List[Link]
186
+ """
187
+ api = Api()
188
+ body = f"""
189
+ query {{
190
+ links(take: 50, skip: 0, where: {{ parentModule: {{eq: "{regscale_module}"}} parentID: {{eq: {regscale_id}}}
191
+ }}) {{
192
+ items {{
193
+ {Link.build_graphql_fields()}
194
+ }},
195
+ pageInfo {{
196
+ hasNextPage
197
+ }}
198
+ ,totalCount}}
199
+ }}
200
+ """
201
+ try:
202
+ existing_regscale_links = api.graph(query=body)["links"]["items"]
203
+ except (JSONDecodeError, KeyError):
204
+ existing_regscale_links = []
205
+ return [Link(**link) for link in existing_regscale_links]
@@ -0,0 +1,64 @@
1
+ """Metadata model for RegScale"""
2
+
3
+ from typing import List, Optional
4
+
5
+ from pydantic import Field, ConfigDict
6
+
7
+ from regscale.core.app.utils.app_utils import get_current_datetime
8
+ from .regscale_model import RegScaleModel
9
+
10
+
11
+ class Metadata(RegScaleModel):
12
+ """RegScale Metadata class"""
13
+
14
+ _module_slug = "metadata"
15
+
16
+ id: Optional[int] = None
17
+ isPublic: bool = True # Required as boolean
18
+ active: bool = True # Required as boolean
19
+ readOnly: bool = False # Required as boolean
20
+ field: Optional[str] = None
21
+ value: Optional[str] = None
22
+ type: Optional[str] = None
23
+ module: Optional[str] = None
24
+ tenantsId: int = 1
25
+ lastUpdatedById: Optional[str] = None
26
+ createdById: Optional[str] = None
27
+ dateCreated: str = Field(default_factory=get_current_datetime) # Required as string
28
+ dateLastUpdated: str = Field(default_factory=get_current_datetime) # Required as string
29
+ dateLastUpdated: str = Field(default_factory=get_current_datetime) # Required as string
30
+ mappedValue: Optional[str] = None
31
+ externalKey: Optional[str] = None
32
+
33
+ @staticmethod
34
+ def _get_additional_endpoints() -> ConfigDict:
35
+ """
36
+ Get additional endpoints for the Metadata model.
37
+
38
+ :return: A dictionary of additional endpoints
39
+ :rtype: ConfigDict
40
+ """
41
+ return ConfigDict(
42
+ get_all_grouped="/api/{model_slug}/getAllGrouped",
43
+ filter_metadata="/api/{model_slug}/filterMetadata/{strModule}/{strField}/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
44
+ get_metadata_by_module_field="/api/{model_slug}/getMetadata/{strModule}/{strField}",
45
+ get_metadata_by_module="/api/{model_slug}/getMetadata/{strModule}",
46
+ get_seeding_options="/api/{model_slug}/getSeedingOptions",
47
+ reseed="/api/{model_slug}/reseed/{strModule}",
48
+ toggle_metadata="/api/{model_slug}/toggleMetadata/{intId}/{bToggle}",
49
+ )
50
+
51
+ @classmethod
52
+ def get_metadata_by_module_field(cls, module: str, field: str) -> List["Metadata"]:
53
+ """
54
+ Retrieves metadata by module and field.
55
+
56
+ :param str module: The module
57
+ :param str field: The field
58
+ :return: A list of metadata or None
59
+ :rtype: List[Metadata]
60
+ """
61
+ response = cls._get_api_handler().get(
62
+ endpoint=cls.get_endpoint("get_metadata_by_module_field").format(strModule=module, strField=field)
63
+ )
64
+ return cls._handle_list_response(response)
File without changes
@@ -0,0 +1,124 @@
1
+ """
2
+ This module contains the PlanCacheMixin class, which provides caching functionality for objects associated with security plans.
3
+
4
+ The PlanCacheMixin is a generic class that can be used with any model that has a security plan ID. It offers methods to populate a cache of objects by plan ID and retrieve all objects for a given plan ID.
5
+
6
+ Classes that inherit from PlanCacheMixin should define two class variables:
7
+ - _graph_query_name: A string representing the name of the GraphQL query for the objects.
8
+ - _graph_plan_id_path: A dot notation string representing the path to the security plan ID in the GraphQL response.
9
+
10
+ Example usage:
11
+ class AssetMapping(PlanCacheMixin["AssetMapping"]):
12
+ _graph_query_name = "assetMappings"
13
+ _graph_plan_id_path = "component.securityPlanId"
14
+
15
+ This mixin is designed to work with the RegScale API and assumes the existence of certain methods like cache_object.
16
+ """
17
+
18
+ import logging
19
+ from typing import Dict, List, TypeVar, Generic, cast, Type, ClassVar
20
+
21
+ logger = logging.getLogger("regscale")
22
+
23
+
24
+ T = TypeVar("T", bound="PlanCacheMixin")
25
+
26
+
27
+ class PlanCacheMixin(Generic[T]):
28
+ """
29
+ Mixin for caching objects by plan ID.
30
+
31
+ This mixin is designed to be used with classes that have a security plan ID.
32
+ It provides a method to populate a cache of objects by plan ID and a method to get all objects for a given plan ID.
33
+
34
+ Example:
35
+ class AssetMapping(PlanCacheMixin["AssetMapping"]):
36
+ _graph_query_name = "assetMappings"
37
+ _graph_plan_id_path = "component.securityPlanId"
38
+ """
39
+
40
+ _graph_query_name: ClassVar[str] # Example: "assetMappings"
41
+ _graph_plan_id_path: ClassVar[str] # Example: "component.securityPlanId"
42
+
43
+ @classmethod
44
+ def populate_cache_by_plan(cls: Type[T], plan_id: int) -> None:
45
+ """
46
+ Populate the parent cache using the get_plan_objects method.
47
+
48
+ :param int plan_id: Security Plan ID
49
+ :rtype: None
50
+ """
51
+ objects = cls.get_plan_objects(plan_id)
52
+ for obj in objects:
53
+ cls.cache_object(obj)
54
+ logger.info("Cached %s %s objects", len(objects), cls.__name__)
55
+
56
+ @classmethod
57
+ def get_plan_objects(cls: Type[T], plan_id: int) -> List[T]:
58
+ """
59
+ Get all objects for a given plan ID.
60
+
61
+ :param int plan_id: Security Plan ID
62
+ :return: Objects for a given plan ID
63
+ :rtype: List[T]
64
+ """
65
+ plan_id_field = cls._graph_plan_id_path
66
+
67
+ # Parse the dot notation to build the where statement
68
+ where_parts = plan_id_field.split(".")
69
+ where_statement = ": {".join(where_parts) + f": {{eq: {plan_id}}}" + "}" * (len(where_parts) - 1)
70
+
71
+ search_query = f"""query {{
72
+ {cls._graph_query_name}(skip: 0, take: 50, where: {{{where_statement}}}) {{
73
+ items {{
74
+ {cls.build_graphql_fields()}
75
+ }}
76
+ totalCount
77
+ pageInfo {{
78
+ hasNextPage
79
+ }}
80
+ }}
81
+ }}"""
82
+ response = cls._get_api_handler().graph(query=search_query)
83
+ objects = cast(List[T], cls._handle_graph_response(response))
84
+ return objects
85
+
86
+ @classmethod
87
+ def build_graphql_fields(cls) -> str:
88
+ """
89
+ Build GraphQL fields for the query.
90
+
91
+ :return: GraphQL fields
92
+ :rtype: str
93
+ """
94
+ raise NotImplementedError("Subclasses must implement build_graphql_fields")
95
+
96
+ @classmethod
97
+ def cache_object(cls, obj: T) -> None:
98
+ """
99
+ Cache an object.
100
+
101
+ :param T obj: Object to cache
102
+ :rtype: None
103
+ """
104
+ raise NotImplementedError("Subclasses must implement cache_object")
105
+
106
+ @classmethod
107
+ def _handle_graph_response(cls, response: Dict) -> List[T]:
108
+ """
109
+ Handle GraphQL response.
110
+
111
+ :param Dict response: GraphQL response
112
+ :return: List of objects
113
+ :rtype: List[T]
114
+ """
115
+ raise NotImplementedError("Subclasses must implement _handle_graph_response")
116
+
117
+ @property
118
+ def _api_handler(self):
119
+ """
120
+ Get API handler.
121
+
122
+ :return: API handler
123
+ """
124
+ raise NotImplementedError("Subclasses must implement _api_handler")