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,162 @@
1
+ """Module for defining the VulnerabilityMapping model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional, List, Dict, Any
6
+
7
+ from pydantic import Field, ConfigDict
8
+
9
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
10
+ from regscale.models.regscale_models.search import Search
11
+
12
+
13
+ class VulnerabilityMapping(RegScaleModel):
14
+ """Represents a mapping between vulnerabilities and assets."""
15
+
16
+ _module_slug = "vulnerabilityMappings"
17
+ _unique_fields = [
18
+ ["vulnerabilityId", "assetId", "scanId"],
19
+ ]
20
+ _parent_id_field = "scanId"
21
+
22
+ uuid: Optional[str] = None
23
+ vulnerabilityId: int
24
+ assetId: int
25
+ scanId: Optional[int] = None
26
+ securityPlansId: Optional[int] = None
27
+ status: Optional[str] = Field(max_length=450)
28
+ firstSeen: str
29
+ lastSeen: str
30
+ dateClosed: Optional[str] = None
31
+ isPublic: bool = Field(default=False)
32
+ createdById: str = Field(default_factory=RegScaleModel.get_user_id)
33
+ lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
34
+ dateCreated: str
35
+ dateLastUpdated: Optional[str] = None
36
+ tenantsId: int = Field(default=0)
37
+
38
+ @staticmethod
39
+ def _get_additional_endpoints() -> ConfigDict:
40
+ """
41
+ Get additional endpoints for the API.
42
+
43
+ :return: A dictionary of additional endpoints
44
+ :rtype: ConfigDict
45
+ """
46
+ return ConfigDict(
47
+ find_by_vulnerability="/api/{model_slug}/findByVulnerability/{vulnerability_id}",
48
+ find_by_asset="/api/{model_slug}/findByAsset/{asset_id}",
49
+ find_by_issue="/api/{model_slug}/findByIssue/{issue_id}",
50
+ find_by_scan="/api/{model_slug}/findByScan/{scan_id}",
51
+ )
52
+
53
+ @classmethod
54
+ def find_by_vulnerability(cls, vulnerability_id: int, status: str = "all") -> List["VulnerabilityMapping"]:
55
+ """
56
+ Get vulnerability mappings by vulnerability ID.
57
+
58
+ :param int vulnerability_id: The vulnerability ID
59
+ :param str status: The status filter (default is "all")
60
+ :return: A list of vulnerability mappings with the given vulnerability ID
61
+ :rtype: List[VulnerabilityMapping]
62
+ """
63
+ endpoint = cls.get_endpoint("find_by_vulnerability").format(vulnerability_id=vulnerability_id)
64
+ params = {"status": status}
65
+ response = cls._get_api_handler().get(endpoint, params=params)
66
+ results = cls._handle_list_response(response)
67
+ for result in results:
68
+ cls.cache_object(result)
69
+ return results
70
+
71
+ @classmethod
72
+ def find_by_asset(cls, asset_id: int, status: str = "all") -> List["VulnerabilityMapping"]:
73
+ """
74
+ Get vulnerability mappings by asset ID.
75
+
76
+ :param int asset_id: The asset ID
77
+ :param str status: The status filter (default is "all")
78
+ :return: A list of vulnerability mappings with the given asset ID
79
+ :rtype: List[VulnerabilityMapping]
80
+ """
81
+ endpoint = cls.get_endpoint("find_by_asset").format(asset_id=asset_id)
82
+ params = {"status": status}
83
+ response = cls._get_api_handler().get(endpoint, params=params)
84
+ results = cls._handle_list_response(response)
85
+ for result in results:
86
+ cls.cache_object(result)
87
+ return results
88
+
89
+ @classmethod
90
+ def find_by_issue(cls, issue_id: int, status: str = "all") -> List["VulnerabilityMapping"]:
91
+ """
92
+ Get vulnerability mappings by issue ID.
93
+
94
+ :param int issue_id: The issue ID
95
+ :param str status: The status filter (default is "all")
96
+ :return: A list of vulnerability mappings with the given issue ID
97
+ :rtype: List[VulnerabilityMapping]
98
+ """
99
+ endpoint = cls.get_endpoint("find_by_issue").format(issue_id=issue_id)
100
+ params = {"status": status}
101
+ response = cls._get_api_handler().get(endpoint, params=params)
102
+ results = cls._handle_list_response(response)
103
+ for result in results:
104
+ cls.cache_object(result)
105
+ return results
106
+
107
+ @classmethod
108
+ def find_by_scan(cls, scan_id: int, status: str = "all") -> List["VulnerabilityMapping"]:
109
+ """
110
+ Get vulnerability mappings by scan ID.
111
+
112
+ :param int scan_id: The scan ID
113
+ :param str status: The status filter (default is "all")
114
+ :return: A list of vulnerability mappings with the given scan ID
115
+ :rtype: List[VulnerabilityMapping]
116
+ """
117
+ endpoint = cls.get_endpoint("find_by_scan").format(scan_id=scan_id)
118
+ params = {"status": status}
119
+ response = cls._get_api_handler().get(endpoint, params=params)
120
+ results = cls._handle_list_response(response)
121
+ for result in results:
122
+ cls.cache_object(result)
123
+ return results
124
+
125
+ def create_unique(self) -> "VulnerabilityMapping":
126
+ """
127
+ Create a VulnerabilityMapping object, using cache to check for existing records.
128
+
129
+ :return: The created or existing VulnerabilityMapping object
130
+ :rtype: VulnerabilityMapping
131
+ """
132
+ # Check if the object already exists in the cache
133
+ cache_key = self._get_cache_key(self)
134
+ with self._get_lock(cache_key):
135
+ cached_object = self.get_cached_object(cache_key)
136
+ if cached_object:
137
+ return cached_object
138
+
139
+ # If not found, create a new object
140
+ new_object = super().create()
141
+ self.cache_object(new_object)
142
+ return new_object
143
+
144
+ @classmethod
145
+ def get_all_by_parent(
146
+ cls,
147
+ parent_id: int,
148
+ parent_module: Optional[str] = None,
149
+ search: Optional[Search] = None,
150
+ **kwargs: Dict[str, Any],
151
+ ) -> List["VulnerabilityMapping"]:
152
+ """
153
+ Get all vulnerability mappings for a given parent.
154
+
155
+ :param int parent_id: The ID of the parent (scan ID in this case)
156
+ :param Optional[str] parent_module: The module of the parent (not used for VulnerabilityMapping)
157
+ :param Optional[Search] search: Search string (not used for VulnerabilityMapping)
158
+ :return: A list of vulnerability mappings for the given parent
159
+ :rtype: List[VulnerabilityMapping]
160
+ """
161
+ status = kwargs.get("status", "all")
162
+ return cls.find_by_scan(scan_id=parent_id, status=status)
@@ -0,0 +1,55 @@
1
+ """RegScale Workflow model"""
2
+
3
+ from typing import List, Optional
4
+
5
+ from pydantic import BaseModel, Field
6
+ from requests import JSONDecodeError
7
+
8
+ from regscale.core.app.api import Api
9
+ from regscale.core.app.application import Application
10
+ from regscale.core.app.utils.app_utils import create_logger
11
+
12
+
13
+ class Workflow(BaseModel):
14
+ id: int = 0
15
+ name: Optional[str] = None
16
+ status: Optional[str] = None
17
+ startDate: Optional[str] = None
18
+ endDate: Optional[str] = None
19
+ currentStep: int = 0
20
+ comments: Optional[str] = None
21
+ createdById: Optional[str] = None
22
+ dateCreated: Optional[str] = None
23
+ lastUpdatedById: Optional[str] = None
24
+ isPublic: bool = True
25
+ dateLastUpdated: Optional[str] = None
26
+ ownerId: Optional[str] = None
27
+ atlasModule: Optional[str] = None
28
+ parentId: Optional[int] = None
29
+ workflowInstanceSteps: List[str] = Field(default_factory=list)
30
+
31
+ def insert_workflow(self, app: Application, template_id: int) -> Optional["Workflow"]:
32
+ """
33
+ Insert a workflow into the database
34
+
35
+ :param Application app: Application instance
36
+ :param int template_id: Workflow template ID in RegScale
37
+ :return: Newly created Workflow object, or None if unsuccessful
38
+ :rtype: Optional[Workflow]
39
+ """
40
+ api = Api()
41
+ # Convert the model to a dictionary
42
+ data = self.dict()
43
+ url = f"{app.config['domain']}/api/workflowInstances/createFromTemplate/{template_id}"
44
+ # Make the API call
45
+ response = api.post(url=url, json=data)
46
+
47
+ # Check the response
48
+ if not response.ok:
49
+ response.raise_for_status()
50
+ try:
51
+ workflow = Workflow(**response.json())
52
+ except JSONDecodeError as jex:
53
+ logger = create_logger()
54
+ logger.error("Unable to read workflow:\n%s", jex)
55
+ return workflow or None
@@ -0,0 +1,34 @@
1
+ """
2
+ This module contains the WorkflowAction model.
3
+ """
4
+
5
+ from typing import Optional
6
+
7
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
8
+ from pydantic import ConfigDict
9
+
10
+
11
+ class WorkflowAction(RegScaleModel):
12
+ _module_slug = "workflowActions"
13
+
14
+ id: Optional[int] = None
15
+ value: Optional[str] = None
16
+ recordId: Optional[int] = None
17
+ recordModule: Optional[str] = None
18
+ days: Optional[int] = None
19
+ recordTitle: Optional[str] = None
20
+ workflowTemplateId: Optional[int] = None
21
+ workflowInstanceId: Optional[int] = None
22
+ isPublic = True
23
+
24
+ @staticmethod
25
+ def _get_additional_endpoints() -> ConfigDict:
26
+ """
27
+ Get additional endpoints for the WorkflowAction model.
28
+
29
+ :return: A dictionary of additional endpoints
30
+ :rtype: ConfigDict
31
+ """
32
+ return ConfigDict(
33
+ get_actions="/api/{model_slug}/getActions/{strModule}",
34
+ )
@@ -0,0 +1,269 @@
1
+ import logging
2
+ from enum import Enum
3
+ from typing import Optional, List
4
+
5
+ from pydantic import ConfigDict, Field
6
+
7
+ from regscale.core.app.utils.app_utils import get_current_datetime
8
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
9
+ from workflow_instance_step import WorkflowInstanceStep
10
+ from workflow_template import WorkflowTemplate
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class WorkflowInstanceStatus(Enum):
16
+ """
17
+ Enum for workflow instance status.
18
+ """
19
+
20
+ PENDING = "Pending"
21
+ APPROVED = "Approved"
22
+ REJECTED = "Rejected"
23
+ COMPLETE = "Complete"
24
+
25
+
26
+ class WorkflowInstance(RegScaleModel):
27
+ _module_slug = "workflowInstances"
28
+
29
+ id: Optional[int] = None
30
+ name: Optional[str] = None
31
+ status: Optional[str] = Field(default=WorkflowInstanceStatus.PENDING.value)
32
+ startDate: Optional[str] = None
33
+ endDate: Optional[str] = None
34
+ currentStep: Optional[int] = None
35
+ comments: 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
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
39
+ isPublic: Optional[bool] = True
40
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
41
+ ownerId: Optional[str] = None
42
+ parentId: Optional[int] = None
43
+ atlasModule: Optional[str] = None
44
+ workflowInstanceSteps: Optional[List[WorkflowInstanceStep]] = None
45
+ tenantsId: Optional[int] = 1
46
+
47
+ @staticmethod
48
+ def _get_additional_endpoints() -> ConfigDict:
49
+ """
50
+ Get additional endpoints for the WorkflowInstance model.
51
+
52
+ :return: A dictionary of additional endpoints
53
+ :rtype: ConfigDict
54
+ """
55
+ return ConfigDict(
56
+ get_by_parent="/api/{model_slug}/filterWorkflowInstanceByParentId/{intParentID}/{strModule}/id/descending/1/100",
57
+ get_count="/api/{model_slug}/getCount",
58
+ get_open="/api/{model_slug}/getOpen",
59
+ get_by_status="/api/{model_slug}/getByStatus",
60
+ user_open_items_days="/api/{model_slug}/userOpenItemsDays/{strOwner}/{intDays}",
61
+ filter_workflow_instances="/api/{model_slug}/filterWorkflowInstances/{strSearch}/{strStatus}/{strOwner}/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
62
+ filter_workflow_instances_by_user="/api/{model_slug}/filterWorkflowInstancesByUser/{strUser}/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
63
+ approve_step_put="/api/{model_slug}/approveStep/{strUserId}",
64
+ submit_put="/api/{model_slug}/submit/{userId}",
65
+ create_from_module_post="/api/{model_slug}/createFromModule/{intTemplateId}/{strUserId}",
66
+ create_custom_workflow_post="/api/{model_slug}/createCustomWorkflow/{strModule}/{intParentId}",
67
+ reject_step_put="/api/{model_slug}/rejectStep/{strUserId}",
68
+ create_from_template_post="/api/{model_slug}/createFromTemplate/{intTemplateId}",
69
+ )
70
+
71
+ @classmethod
72
+ def get_workflows_by_parent(cls, parent_id: int, parent_module: str) -> List["WorkflowInstance"]:
73
+ """
74
+ Get all workflows by parent.
75
+
76
+ :param int parent_id: The ID of the parent
77
+ :param str parent_module: The module of the parent
78
+ :return: A list of workflows
79
+ :rtype: List[WorkflowInstance]
80
+ """
81
+ response = cls._get_api_handler().get(
82
+ endpoint=cls.get_endpoint("get_by_parent").format(intParentID=parent_id, strModule=parent_module)
83
+ )
84
+ if response and response.ok:
85
+ json_data = response.json()
86
+ items = json_data.get("items", [])
87
+ return [WorkflowInstance(**workflow) for workflow in items]
88
+ return []
89
+
90
+ @classmethod
91
+ def find_by_unique(cls, parent_id: int, parent_module: str, name: str) -> Optional["WorkflowInstance"]:
92
+ """
93
+ Find a object by unique query.
94
+ :param int parent_id: The ID of the parent
95
+ :param str parent_module: The module of the parent
96
+ :param str name: The name of the object
97
+ :return: The functional role
98
+ :rtype: FunctionalRole
99
+ """
100
+ for instance in cls.get_all_by_parent(parent_id=parent_id, parent_module=parent_module):
101
+ if instance.name == name:
102
+ return instance
103
+ return None
104
+
105
+ @classmethod
106
+ def create_from_template(cls, template_id: int) -> Optional[int]:
107
+ """
108
+ Create a workflow instance from a template.
109
+
110
+ :param int template_id: The ID of the template
111
+ :return: The created workflow instance id
112
+ :rtype: Optional[int]
113
+ """
114
+ workflow_template = WorkflowTemplate.get_object(object_id=template_id)
115
+ if not workflow_template:
116
+ logger.error(f"Failed to find workflow template {template_id}")
117
+ return None
118
+ response = cls._get_api_handler().post(
119
+ endpoint=cls.get_endpoint("create_from_template_post").format(
120
+ model_slug=cls._module_slug, intTemplateId=template_id
121
+ ),
122
+ data=workflow_template.model_dump(),
123
+ )
124
+ if response and response.ok:
125
+ return int(response.text)
126
+ else:
127
+ logger.error(f"Failed to create workflow instance from template {template_id}")
128
+ return None
129
+
130
+ @classmethod
131
+ def create_custom_workflow_from_template(
132
+ cls, template_id: int, parent_id: int, parent_module: str
133
+ ) -> Optional["WorkflowInstance"]:
134
+ """
135
+ Create a workflow instance from a template.
136
+
137
+ :param int template_id: The ID of the template
138
+ :param int parent_id: The ID of the parent
139
+ :param str parent_module: The module of the parent
140
+ :return: The created workflow instance id
141
+ :rtype: Optional[int]
142
+ """
143
+ workflow_template = WorkflowTemplate.get_object(object_id=template_id)
144
+ steps = workflow_template.workflowTemplateSteps
145
+ if not workflow_template:
146
+ logger.error(f"Failed to find workflow template {template_id}")
147
+ return None
148
+ response = cls._get_api_handler().post(
149
+ endpoint=cls.get_endpoint("create_custom_workflow_post").format(
150
+ model_slug=cls._module_slug, strModule=parent_module, intParentId=parent_id
151
+ ),
152
+ data=[step.model_dump() for step in steps],
153
+ )
154
+ if response and response.ok:
155
+ return WorkflowInstance(**response.json())
156
+ else:
157
+ logger.error(f"Failed to create workflow instance from template {template_id}")
158
+ return None
159
+
160
+ @classmethod
161
+ def create_custom_workflow_from_template_with_group(
162
+ cls, template_id: int, parent_id: int, parent_module: str, group_id: int, group_name: str
163
+ ) -> Optional["WorkflowInstance"]:
164
+ """
165
+ Create a workflow instance from a template.
166
+
167
+ :param int template_id: The ID of the template
168
+ :param int parent_id: The ID of the parent
169
+ :param str parent_module: The module of the parent
170
+ :param int group_id: The ID of the group
171
+ :param str group_name: The name of the group
172
+ :return: The created workflow instance id
173
+ :rtype: Optional[int]
174
+ """
175
+ workflow_template = WorkflowTemplate.get_object(object_id=template_id)
176
+ steps = workflow_template.workflowTemplateSteps
177
+ for step in steps:
178
+ if step.name == "Automated Conflict of Interest Check":
179
+ continue
180
+ step.name = f"{step.name} - {group_name}" if group_name else step.name
181
+ step.groupsId = group_id
182
+
183
+ if not workflow_template:
184
+ logger.error(f"Failed to find workflow template {template_id}")
185
+ return None
186
+ response = cls._get_api_handler().post(
187
+ endpoint=cls.get_endpoint("create_custom_workflow_post").format(
188
+ model_slug=cls._module_slug, strModule=parent_module, intParentId=parent_id
189
+ ),
190
+ data=[step.model_dump() for step in steps],
191
+ )
192
+ if response and response.ok:
193
+ return WorkflowInstance(**response.json())
194
+ else:
195
+ logger.error(f"Failed to create workflow instance from template {template_id}")
196
+ return None
197
+
198
+ def create_custom_workflow(self, module: str, parent_id: int) -> Optional[int]:
199
+ """
200
+ Create a custom workflow instance.
201
+
202
+ :param str module: The module of the parent
203
+ :param int parent_id: The ID of the parent
204
+ :return: The created workflow instance id
205
+ :rtype: Optional[int]
206
+ """
207
+ response = selfcls._get_api_handler().post(
208
+ endpoint=self.get_endpoint("create_custom_workflow_post").format(
209
+ model_slug=self._module_slug, strModule=module, intParentId=parent_id
210
+ ),
211
+ data=self.dict(),
212
+ )
213
+ if response and response.ok:
214
+ return int(response.text)
215
+ else:
216
+ logger.error(f"Failed to create custom workflow instance from module {module}. Error: {response.text}")
217
+ return None
218
+
219
+ def approve_step(self, user_id: str) -> bool:
220
+ """
221
+ Approve a step in a workflow instance.
222
+
223
+ :param str user_id: The ID of the user
224
+ :return: True if successful
225
+ :rtype: bool
226
+ """
227
+ response = selfcls._get_api_handler().put(
228
+ endpoint=self.get_endpoint("approve_step_put").format(model_slug=self._module_slug, strUserId=user_id),
229
+ data=self.dict(),
230
+ )
231
+ if getattr(response, "ok", False):
232
+ return True
233
+ else:
234
+ logger.error(f"Failed to approve step for {self.name}")
235
+ return False
236
+
237
+ def reject_step(self, user_id: str) -> bool:
238
+ """
239
+ Reject a step in a workflow instance.
240
+
241
+ :param str user_id: The ID of the user
242
+ :return: True if successful
243
+ :rtype: bool
244
+ """
245
+ response = selfcls._get_api_handler().put(
246
+ endpoint=self.get_endpoint("reject_step_put").format(model_slug=self._module_slug, strUserId=user_id),
247
+ data=self.dict(),
248
+ )
249
+ if getattr(response, "ok", False):
250
+ return True
251
+ else:
252
+ logger.error(f"Failed to reject step for {self.name}")
253
+ return False
254
+
255
+ def approve_all_steps(self, user_id: str) -> None:
256
+ """
257
+ Approve all steps in a workflow instance.
258
+
259
+ :param str user_id: The ID of the user
260
+ :rtype: None
261
+ """
262
+ for step in WorkflowInstanceStep.get_all_by_parent(
263
+ parent_id=self.id,
264
+ parent_module=self.get_module_slug(),
265
+ ):
266
+ if step.order not in [0, 1000]:
267
+ self.currentStep = step.order
268
+ self.comments = "<p>I Approve</p>"
269
+ self.approve_step(user_id=user_id)
@@ -0,0 +1,114 @@
1
+ """
2
+ This module contains the WorkflowInstanceStep model class that represents a workflow instance step in the RegScale application.
3
+ """
4
+
5
+ from typing import Optional, Union
6
+
7
+ from pydantic import ConfigDict, Field
8
+
9
+ from regscale.core.app.utils.app_utils import get_current_datetime
10
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
11
+ from enum import Enum
12
+
13
+
14
+ class WorkflowInstanceStepType(str, Enum):
15
+ """
16
+ Enum for workflow instance step type.
17
+ """
18
+
19
+ MANAGER = "Manager"
20
+ GROUP = "Group"
21
+
22
+
23
+ class WorkflowInstanceStepExecutionType(str, Enum):
24
+ """
25
+ Enum for workflow instance step execution type.
26
+ """
27
+
28
+ SEQUENTIAL = "Sequential"
29
+ PARALLEL = "Parallel"
30
+
31
+
32
+ class WorkflowInstanceStepStatus(str, Enum):
33
+ """
34
+ Enum for workflow instance step status.
35
+ """
36
+
37
+ PENDING = "Pending"
38
+ APPROVED = "Approved"
39
+ REJECTED = "Rejected"
40
+ COMPLETE = "Complete"
41
+ SUBMITTED = "Submitted"
42
+
43
+
44
+ class WorkflowInstanceStep(RegScaleModel):
45
+ _module_slug = "workflowInstanceSteps"
46
+
47
+ id: Optional[int] = None
48
+ workflowInstanceId: Optional[int] = None
49
+ name: Optional[str] = None
50
+ comments: Optional[str] = None
51
+ order: Optional[int] = 1
52
+ status: Optional[str] = None
53
+ startDate: Optional[str] = None
54
+ endDate: Optional[str] = None
55
+ actionType: Optional[str] = None
56
+ executionType: Optional[str] = None
57
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
58
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
59
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
60
+ isPublic: Optional[bool] = True
61
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
62
+ groupsId: Optional[int] = None
63
+ tenantsId: Optional[int] = 1
64
+ stepType: Optional[str] = None
65
+ assignedToId: Optional[str] = None
66
+ functionalRoleId: Optional[int] = None
67
+ parentId: Optional[int] = None
68
+ parentModule: Optional[str] = None
69
+
70
+ @staticmethod
71
+ def _get_additional_endpoints() -> ConfigDict:
72
+ """
73
+ Get additional endpoints for the WorkflowInstanceStep model.
74
+
75
+ :return: A dictionary of additional endpoints
76
+ :rtype: ConfigDict
77
+ """
78
+ return ConfigDict(
79
+ get_by_parent="/api/{model_slug}/getByParent/{intParentID}",
80
+ filter_workflow_instance_steps_by_parent="/api/{model_slug}/filterWorkflowInstanceStepsByParent/{intWorkflowInstanceID}/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
81
+ update_workflow_instance_step_put="/api/{model_slug}/{id}",
82
+ get_workflow_instance_step="/api/{model_slug}/{id}",
83
+ )
84
+
85
+ @classmethod
86
+ def find_by_unique(cls, workflow_instance_id: int, field_name: str, field_value: Union[str, int]):
87
+ """
88
+ Find a object by unique query.
89
+ :param workflow_instance_id: The workflow instance ID
90
+ :param field_name: The field name
91
+ :param field_value: The field value
92
+ :return: The functional role
93
+ :rtype: FunctionalRole
94
+ """
95
+ for instance in cls.get_all_by_parent(parent_id=workflow_instance_id, parent_module=None):
96
+ if getattr(instance, field_name) == field_value:
97
+ return instance
98
+ return None
99
+
100
+ @classmethod
101
+ def get_by_parent(cls, parent_id: int):
102
+ """
103
+ Get workflow instance steps by parent ID.
104
+
105
+ :param parent_id: The parent ID
106
+ :return: A list of workflow instance steps
107
+ :rtype: List[WorkflowInstanceStep]
108
+ """
109
+ response = cls._get_api_handler().get(
110
+ endpoint=cls.get_endpoint("get_by_parent").format(model_slug=cls._module_slug, intParentID=parent_id)
111
+ )
112
+ if response and response.ok:
113
+ return [WorkflowInstanceStep(**step) for step in response.json()]
114
+ return []
@@ -0,0 +1,58 @@
1
+ """
2
+ This module contains the WorkflowTemplate model.
3
+ """
4
+
5
+ from typing import Optional, List
6
+
7
+ from pydantic import ConfigDict, Field
8
+
9
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
10
+ from workflow_template_step import WorkflowTemplateStep
11
+
12
+
13
+ class WorkflowTemplate(RegScaleModel):
14
+ _module_slug = "workflowTemplates"
15
+
16
+ id: Optional[int] = None
17
+ name: Optional[str] = None
18
+ status: Optional[str] = None
19
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
20
+ dateCreated: Optional[str] = None
21
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
22
+ isPublic: Optional[bool] = None
23
+ dateLastUpdated: Optional[str] = None
24
+ atlasModule: Optional[str] = None
25
+ workflowTemplateSteps: Optional[List[WorkflowTemplateStep]] = None
26
+ tenantsId: int = 1
27
+
28
+ @staticmethod
29
+ def _get_additional_endpoints() -> ConfigDict:
30
+ """
31
+ Get additional endpoints for the WorkflowTemplate model.
32
+
33
+ :return: A dictionary of additional endpoints
34
+ :rtype: ConfigDict
35
+ """
36
+ return ConfigDict(
37
+ get_count="/api/{model_slug}/getCount",
38
+ get_by_atlas_module="/api/{model_slug}/getByAtlasModule/{strModule}",
39
+ filter_workflow_templates="/api/{model_slug}/filterWorkflowTemplates/{strSearch}/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
40
+ )
41
+
42
+ @classmethod
43
+ def get_by_module_slug(cls, module: str) -> List["WorkflowTemplate"]:
44
+ """
45
+ Get all workflow templates by atlas module.
46
+
47
+ :param str module: The module of the parent
48
+ :return: A list of workflow templates
49
+ :rtype: List["WorkflowTemplate"]
50
+ """
51
+ response = cls._get_api_handler().get(
52
+ endpoint=cls.get_endpoint("get_by_atlas_module").format(model_slug=cls._module_slug, strModule=module)
53
+ )
54
+ if response and response.ok:
55
+ return [cls(**o) for o in response.json()]
56
+ else:
57
+ cls.log_response_error(response=response)
58
+ return []