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,570 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for a RegScale Assessment"""
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from enum import Enum
6
+ from typing import Any, List, Optional, Union
7
+
8
+ from requests import JSONDecodeError
9
+
10
+ from regscale.core.app.api import Api
11
+ from regscale.core.app.application import Application
12
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
13
+
14
+
15
+ class AssessmentStatus(Enum):
16
+ """
17
+ Enum for acceptable Assessment Statuses
18
+ """
19
+
20
+ SCHEDULED = "Scheduled"
21
+ IN_PROGRESS = "In Progress"
22
+ COMPLETE = "Complete"
23
+ CANCELLED = "Cancelled"
24
+
25
+
26
+ class AssessmentType(Enum):
27
+ """
28
+ Enum for acceptable Assessment Types in RegScale
29
+ """
30
+
31
+ SELF = "Self"
32
+ INDEPENDENT = "Independent"
33
+ EFFECTIVENESS_REVIEW = "Effectiveness Review"
34
+ IMPLEMENTATION_VERIFICATION_REVIEW = "Implementation Verification Review"
35
+ MANAGEMENT = "Management"
36
+ READINESS_REVIEW = "Readiness Review"
37
+ SUPPLIER_QUALITY_EVALUATION = "Supplier Quality Evaluation"
38
+ QA_SURVEILLANCE = "QA Surveillance"
39
+ RP_SURVEILLANCE = "RP Surveillance"
40
+ SH_SURVEILLANCE = "SH Surveillance"
41
+
42
+
43
+ class AssessmentResultsStatus(str, Enum):
44
+ """
45
+ Enum for acceptable Assessment Result Statuses in RegScale
46
+ """
47
+
48
+ NOT_YET_ASSESSED = "Not Yet Assessed"
49
+ PASS = "Pass"
50
+ FAIL = "Fail"
51
+ PARTIAL = "Partial Pass"
52
+ NOT_APPLICABLE = "Not Applicable"
53
+
54
+
55
+ class Assessment(RegScaleModel):
56
+ """
57
+ Model for a RegScale Assessment
58
+ """
59
+
60
+ _module_slug = "assessments"
61
+
62
+ id: int = 0
63
+ leadAssessorId: str = ""
64
+ title: Optional[str] = None
65
+ assessmentType: Optional[Union[AssessmentType, str]] = None
66
+ plannedStart: Optional[str] = None
67
+ plannedFinish: Optional[str] = None
68
+ status: Union[AssessmentStatus, str] = AssessmentStatus.SCHEDULED
69
+ facilityId: Optional[int] = None
70
+ orgId: Optional[int] = None
71
+ assessmentResult: Optional[Union[str, AssessmentResultsStatus]] = ""
72
+ actualFinish: Optional[str] = None
73
+ assessmentReport: Optional[str] = None
74
+ masterId: Optional[int] = None
75
+ complianceScore: Optional[float] = None
76
+ targets: Optional[str] = None
77
+ automationInfo: Optional[str] = None
78
+ automationId: Optional[str] = None
79
+ metadata: Optional[str] = None
80
+ assessmentPlan: Optional[str] = None
81
+ methodology: Optional[str] = None
82
+ rulesOfEngagement: Optional[str] = None
83
+ disclosures: Optional[str] = None
84
+ scopeIncludes: Optional[str] = None
85
+ scopeExcludes: Optional[str] = None
86
+ limitationsOfLiability: Optional[str] = None
87
+ documentsReviewed: Optional[str] = None
88
+ activitiesObserved: Optional[str] = None
89
+ fixedDuringAssessment: Optional[str] = None
90
+ summaryOfResults: Optional[str] = None
91
+ oscalsspId: Optional[int] = None
92
+ oscalComponentId: Optional[int] = None
93
+ controlId: Optional[int] = None
94
+ requirementId: Optional[int] = None
95
+ securityPlanId: Optional[int] = None
96
+ projectId: Optional[int] = None
97
+ supplyChainId: Optional[int] = None
98
+ policyId: Optional[int] = None
99
+ componentId: Optional[int] = None
100
+ incidentId: Optional[int] = None
101
+ parentId: Optional[int] = None
102
+ parentModule: Optional[str] = None
103
+ createdById: Optional[str] = None
104
+ dateCreated: Optional[str] = None
105
+ lastUpdatedById: Optional[str] = None
106
+ dateLastUpdated: Optional[str] = None
107
+ isPublic: bool = True
108
+ verificationStatus: Optional[str] = None
109
+ otherIdentifier: Optional[str] = None
110
+
111
+ @staticmethod
112
+ def _get_additional_endpoints() -> dict[str, str]:
113
+ """
114
+ Get additional endpoints for the Assessments model.
115
+
116
+ :return: A dictionary of additional endpoints
117
+ :rtype: dict[str, str]
118
+ """
119
+ return { # type: ignore
120
+ "user_open_items_days": "/api/{model_slug}/userOpenItemsDays/{strUserId}/{intDays}",
121
+ "get_existing_lightning_by_parent": "/api/{model_slug}/getExistingLightningByParent/{intParentID}/{strModule}",
122
+ "get_all_by_grandparent": "/api/{model_slug}/getAllByGrandParent/{intParentID}/{strModule}",
123
+ "get_all_by_master": "/api/{model_slug}/getAllByMaster/{intMaster}",
124
+ "get_count": "/api/{model_slug}/getCount",
125
+ "batch_recurring": "/api/{model_slug}/batchRecurring/{intID}/{dtStart}/{dtEnd}/{repeatUntil}/{strFrequency}",
126
+ "process_lineage": "/api/{model_slug}/processLineage/{intAssessmentID}",
127
+ "assessment_first_and_last": "/api/{model_slug}/assessmentFirstAndLast/{intId}/{strModule}",
128
+ "assessment_timeline": "/api/{model_slug}/assessmentTimeline/{intId}/{strModule}/{strType}",
129
+ "calendar_assessments": "/api/{model_slug}/calendarAssessments/{dtDate}/{fId}/{orgId}/{userId}",
130
+ "graph": "/api/{model_slug}/graph",
131
+ "graph_by_date": "/api/{model_slug}/graphByDate/{strGroupBy}/{year}",
132
+ "schedule": "/api/{model_slug}/schedule/{year}/{strField}",
133
+ "get_by_date_range_all": "/api/{model_slug}/GetByDateRangeAll/{dtStart}/{dtEnd}",
134
+ "get_by_date_range_open": "/api/{model_slug}/getByDateRangeOpen/{dtStart}/{dtEnd}",
135
+ "get_by_date_range_closed": "/api/{model_slug}/getByDateRangeClosed/{dtStart}/{dtEnd}",
136
+ "graph_by_owner_then_status": "/api/{model_slug}/graphByOwnerThenStatus/{dateField}/{dtStart}/{dtEnd}",
137
+ "graph_by_type_then_status": "/api/{model_slug}/graphByTypeThenStatus/{dateField}/{dtStart}/{dtEnd}",
138
+ "group_by_owner_then_status": "/api/{model_slug}/groupByOwnerThenStatus/{dateField}/{dtStart}/{dtEnd}",
139
+ "main_dashboard_chart": "/api/{model_slug}/mainDashboardChart/{year}",
140
+ "main_dashboard": "/api/{model_slug}/mainDashboard/{intYear}",
141
+ "main_dashboard_overdue": "/api/{model_slug}/mainDashboardOverdue",
142
+ "main_dashboard_upcoming": "/api/{model_slug}/mainDashboardUpcoming",
143
+ "graph_due_date": "/api/{model_slug}/graphDueDate/{year}",
144
+ "graph_due_date_by_status": "/api/{model_slug}/graphDueDateByStatus/{year}",
145
+ "report": "/api/{model_slug}/report/{strReport}",
146
+ "query_by_custom_field": "/api/{model_slug}/queryByCustomField/{strFieldName}/{strValue}",
147
+ "filter_assessments": "/api/{model_slug}/filterAssessments",
148
+ "batch_create": "/api/{model_slug}/batchCreate",
149
+ "heimdall": "/api/{model_slug}/heimdall/{intID}",
150
+ "find_by_other_identifier": "/api/{model_slug}/findByOtherIdentifier/{strID}",
151
+ "other_identifier_starts_with": "/api/{model_slug}/otherIdentifierStartsWith/{strID}",
152
+ "get_completed_on_schedule": "/api/{model_slug}/getCompletedOnSchedule/{intYear}",
153
+ }
154
+
155
+ def __getitem__(self, key: Any) -> Any:
156
+ """
157
+ Get attribute from Pipeline
158
+
159
+ :param Any key: Key to get value from
160
+ :return: value of provided key
161
+ :rtype: Any
162
+ """
163
+ return getattr(self, key)
164
+
165
+ def __setitem__(self, key: Any, value: Any) -> None:
166
+ """
167
+ Set attribute in Pipeline with provided key
168
+
169
+ :param Any key: Key to change to provided value
170
+ :param Any value: New value for provided Key
171
+ :rtype: None
172
+ """
173
+ return setattr(self, key, value)
174
+
175
+ def insert_assessment(self, app: Application) -> Optional["Assessment"]:
176
+ """
177
+ Function to create a new assessment in RegScale and returns the new assessment's ID
178
+
179
+ :param Application app: Application object
180
+ :return: New Assessment object created in RegScale
181
+ :rtype: Optional[Assessment]
182
+ """
183
+ api = Api()
184
+ url = f"{app.config['domain']}/api/assessments"
185
+ response = api.post(url=url, json=self.dict())
186
+ if not response.ok:
187
+ app.logger.debug(response.status_code)
188
+ app.logger.error(f"Failed to insert Assessment.\n{response.text}")
189
+ return Assessment(**response.json()) if response.ok else None
190
+
191
+ @classmethod
192
+ def bulk_insert(
193
+ cls,
194
+ app: Application,
195
+ assessments: list["Assessment"],
196
+ max_workers: int = 5,
197
+ ) -> list["Assessment"]:
198
+ """
199
+ Bulk insert assets using the RegScale API and ThreadPoolExecutor
200
+
201
+ :param Application app: Application Instance
202
+ :param list[Assessment] assessments: Assessment List
203
+ :param int max_workers: Max Workers, defaults to 5
204
+ :return: List of Assessments created in RegScale
205
+ :rtype: list["Assessment"]
206
+ """
207
+
208
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
209
+ workers = [
210
+ executor.submit(
211
+ assessment.create,
212
+ )
213
+ for assessment in assessments
214
+ ]
215
+ return list(filter(None, [worker.result() for worker in workers]))
216
+
217
+ @staticmethod
218
+ def fetch_all_assessments(app: Application) -> list["Assessment"]:
219
+ """
220
+ Function to retrieve all assessments from RegScale
221
+
222
+ :param Application app: Application Object
223
+ :return: List of assessments from RegScale
224
+ :rtype: list[Assessment]
225
+ """
226
+ query = f"""
227
+ query {{
228
+ assessments (take: 50, skip: 0) {{
229
+ items {{
230
+ {Assessment.build_graphql_fields()}
231
+ }}
232
+ pageInfo {{
233
+ hasNextPage
234
+ }}
235
+ totalCount
236
+ }}
237
+ }}
238
+ """
239
+ api = Api()
240
+ try:
241
+ app.logger.info("Retrieving all assessments in RegScale...")
242
+ existing_assessments = api.graph(query=query)["assessments"]["items"]
243
+ app.logger.info("%i assessment(s) retrieved from RegScale.", len(existing_assessments))
244
+ except (JSONDecodeError, KeyError):
245
+ existing_assessments = []
246
+ return [Assessment(**assessment) for assessment in existing_assessments]
247
+
248
+ @classmethod
249
+ def get_all_by_master(cls, master_id: int) -> List["Assessment"]:
250
+ """
251
+ Get a list of objects by master assessment.
252
+
253
+ :param int master_id: The ID of the Master Assessment/ConMon
254
+ :return: A list Assessment objects
255
+ :rtype: List[Assessment]
256
+ """
257
+ endpoint = cls.get_endpoint("get_all_by_master").format(intMaster=master_id)
258
+ return cls._handle_list_response(cls._get_api_handler().get(endpoint=endpoint))
259
+
260
+ @staticmethod
261
+ def fetch_all_assessments_by_parent(
262
+ app: Application,
263
+ parent_id: int,
264
+ parent_module: str,
265
+ org_and_facil: Optional[bool] = False,
266
+ ) -> dict:
267
+ """
268
+ Function to retrieve all assessments from RegScale by parent
269
+
270
+ :param Application app: RegScale Application object
271
+ :param int parent_id: RegScale ID of parent
272
+ :param str parent_module: Module of parent
273
+ :param Optional[bool] org_and_facil: If True, return org and facility names, defaults to False
274
+ :return: GraphQL response from RegScale
275
+ :rtype: dict
276
+ """
277
+ api = Api()
278
+ # The indentation is important here
279
+ org_and_facil_query = """
280
+ facility {
281
+ name
282
+ }
283
+ org {
284
+ name
285
+ }
286
+ """
287
+ body = f"""
288
+ query {{
289
+ assessments (skip: 0, take: 50, where: {{parentId: {{eq: {parent_id}}} parentModule: {{eq: "{parent_module}"}}}}) {{
290
+ items {{
291
+ id
292
+ title
293
+ leadAssessor {{
294
+ firstName
295
+ lastName
296
+ userName
297
+ }}
298
+ {org_and_facil_query if org_and_facil else ""}
299
+ assessmentType
300
+ plannedStart
301
+ plannedFinish
302
+ status
303
+ actualFinish
304
+ assessmentResult
305
+ parentId
306
+ parentModule
307
+ }}
308
+ totalCount
309
+ pageInfo {{
310
+ hasNextPage
311
+ }}
312
+ }}
313
+ }}
314
+ """
315
+ assessments = api.graph(query=body)
316
+ if parent_module not in [
317
+ "securityplans",
318
+ "incidents",
319
+ "policies",
320
+ "components",
321
+ "requirements",
322
+ "supplychain",
323
+ ]:
324
+ return assessments
325
+
326
+ replacements = {
327
+ "securityplans": "securityPlanId",
328
+ "incidents": "incidentId",
329
+ "policies": "policyId",
330
+ "components": "componentId",
331
+ "requirements": "requirementId",
332
+ "supplychain": "supplyChainId",
333
+ }
334
+ if replacement_key := replacements.get(parent_module):
335
+ body = body.replace(
336
+ f'parentId: {{eq: {parent_id}}} parentModule: {{eq: "{parent_module}"}}',
337
+ f"{replacement_key}: {{eq: {parent_id}}}",
338
+ )
339
+ return {**assessments, **api.graph(query=body)}
340
+
341
+ @classmethod
342
+ def get_sort_position_dict(cls) -> dict:
343
+ """
344
+ Overrides the base method.
345
+
346
+ :return: dict The sort position in the list of properties
347
+ :rtype: dict
348
+ """
349
+ return {
350
+ "id": 1,
351
+ "leadAssessorId": 2,
352
+ "title": 3,
353
+ "assessmentType": 4,
354
+ "plannedStart": 5,
355
+ "plannedFinish": 6,
356
+ "status": 7,
357
+ "facilityId": 8,
358
+ "orgId": 9,
359
+ "assessmentResult": 10,
360
+ "actualFinish": 11,
361
+ "assessmentReport": 12,
362
+ "masterId": 13,
363
+ "complianceScore": 14,
364
+ "targets": 15,
365
+ "automationInfo": 16,
366
+ "automationId": 17,
367
+ "metadata": 18,
368
+ "assessmentPlan": 19,
369
+ "methodology": 20,
370
+ "rulesOfEngagement": 21,
371
+ "disclosures": 22,
372
+ "scopeIncludes": 23,
373
+ "scopeExcludes": 24,
374
+ "limitationsOfLiability": 25,
375
+ "documentsReviewed": 26,
376
+ "activitiesObserved": 27,
377
+ "fixedDuringAssessment": 28,
378
+ "summaryOfResults": 29,
379
+ "oscalsspId": 30,
380
+ "oscalComponentId": 31,
381
+ "controlId": 32,
382
+ "requirementId": 33,
383
+ "securityPlanId": 34,
384
+ "projectId": 35,
385
+ "supplyChainId": 36,
386
+ "policyId": 37,
387
+ "componentId": 38,
388
+ "incidentId": 39,
389
+ "parentId": 40,
390
+ "parentModule": 41,
391
+ "isPublic": 42,
392
+ "verificationStatus": 43,
393
+ "otherIdentifier": 44,
394
+ }
395
+
396
+ @classmethod
397
+ def get_enum_values(cls, field_name: str) -> list:
398
+ """
399
+ Overrides the base method.
400
+
401
+ :param str field_name: The property name to provide enum values for
402
+ :return: list of strings
403
+ :rtype: list
404
+ """
405
+ if field_name == "assessmentType":
406
+ return [assessment_type.value for assessment_type in AssessmentType]
407
+ if field_name == "status":
408
+ return [status.value for status in AssessmentStatus]
409
+ if field_name == "assessmentResult":
410
+ return [result for result in AssessmentResultsStatus]
411
+ return cls.get_bool_enums(field_name)
412
+
413
+ @classmethod
414
+ def get_lookup_field(cls, field_name: str) -> str:
415
+ """
416
+ Overrides the base method.
417
+
418
+ :param str field_name: The property name to provide enum values for
419
+ :return: str the field name to look up
420
+ :rtype: str
421
+ """
422
+ lookup_fields = {
423
+ "leadAssessorId": "user",
424
+ "leadAssessor": "user",
425
+ "facilityId": "facilities",
426
+ "facility": "facilities",
427
+ "orgId": "organizations",
428
+ "org": "organizations",
429
+ "parentModule": "module",
430
+ "controlId": "",
431
+ "requirementId": "",
432
+ "securityPlanId": "",
433
+ "projectId": "",
434
+ "supplyChainId": "",
435
+ "policyId": "",
436
+ "componentId": "",
437
+ "incidentId": "",
438
+ }
439
+ if field_name in lookup_fields.keys():
440
+ return lookup_fields[field_name]
441
+ return ""
442
+
443
+ @classmethod
444
+ def is_date_field(cls, field_name: str) -> bool:
445
+ """
446
+ Overrides the base method.
447
+
448
+ :param str field_name: The property name to provide enum values for
449
+ :return: bool if the field should be formatted as a date
450
+ :rtype: bool
451
+ """
452
+ return field_name in ["plannedStart", "plannedFinish", "actualFinish"]
453
+
454
+ @classmethod
455
+ def get_export_query(cls, app: Application, parent_id: int, parent_module: str) -> list:
456
+ """
457
+ Overrides the base method.
458
+
459
+ :param Application app: RegScale Application object
460
+ :param int parent_id: RegScale ID of parent
461
+ :param str parent_module: Module of parent
462
+ :return: list GraphQL response from RegScale
463
+ :rtype: list
464
+ """
465
+ existing_assessment_data = cls.fetch_all_assessments_by_parent_for_export(app, parent_id, parent_module, True)
466
+ if (
467
+ existing_assessment_data["assessments"]["totalCount"] > 0
468
+ ): # Checking to see if assessment exists for selected RegScale Id and RegScale Module.
469
+ return existing_assessment_data["assessments"]["items"]
470
+ return []
471
+
472
+ @classmethod
473
+ def use_query(cls) -> bool:
474
+ """
475
+ Overrides the base method.
476
+
477
+ :return: bool
478
+ :rtype: bool
479
+ """
480
+ return True
481
+
482
+ @classmethod
483
+ def get_extra_fields(cls) -> list:
484
+ """
485
+ Overrides the base method.
486
+
487
+ :return: list of extra field names
488
+ :rtype: list
489
+ """
490
+ return ["leadAssessor", "facility", "org"]
491
+
492
+ @staticmethod
493
+ def fetch_all_assessments_by_parent_for_export(
494
+ app: Application,
495
+ parent_id: int,
496
+ parent_module: str,
497
+ org_and_facil: Optional[bool] = False,
498
+ ) -> dict:
499
+ """
500
+ Function to retrieve all assessments from RegScale by parent
501
+
502
+ :param Application app: RegScale Application object
503
+ :param int parent_id: RegScale ID of parent
504
+ :param str parent_module: Module of parent
505
+ :param Optional[bool] org_and_facil: If True, return org and facility names, defaults to False
506
+ :return: GraphQL response from RegScale
507
+ :rtype: dict
508
+ """
509
+ api = Api()
510
+ body = f"""
511
+ query {{
512
+ assessments (skip: 0, take: 50, where: {{parentId: {{eq: {parent_id}}} parentModule: {{eq: "{parent_module}"}}}}) {{
513
+ items {{
514
+ id
515
+ title
516
+ leadAssessorId
517
+ facilityId
518
+ orgId
519
+ assessmentType
520
+ plannedStart
521
+ plannedFinish
522
+ status
523
+ actualFinish
524
+ assessmentResult
525
+ parentId
526
+ parentModule
527
+ }}
528
+ totalCount
529
+ pageInfo {{
530
+ hasNextPage
531
+ }}
532
+ }}
533
+ }}
534
+ """
535
+ assessments = api.graph(query=body)
536
+ if parent_module not in [
537
+ "securityplans",
538
+ "incidents",
539
+ "policies",
540
+ "components",
541
+ "requirements",
542
+ "supplychain",
543
+ ]:
544
+ return assessments
545
+
546
+ replacements = {
547
+ "securityplans": "securityPlanId",
548
+ "incidents": "incidentId",
549
+ "policies": "policyId",
550
+ "components": "componentId",
551
+ "requirements": "requirementId",
552
+ "supplychain": "supplyChainId",
553
+ }
554
+ if replacement_key := replacements.get(parent_module):
555
+ body = body.replace(
556
+ f'parentId: {{eq: {parent_id}}} parentModule: {{eq: "{parent_module}"}}',
557
+ f"{replacement_key}: {{eq: {parent_id}}}",
558
+ )
559
+ return {**assessments, **api.graph(query=body)}
560
+
561
+ @classmethod
562
+ def is_required_field(cls, field_name: str) -> bool:
563
+ """
564
+ Overrides the base method.
565
+
566
+ :param str field_name: field name to check
567
+ :return: bool indicating if the field is required
568
+ :rtype: bool
569
+ """
570
+ return field_name in ["plannedStart", "plannedFinish"]
@@ -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 AssesmentPlanArea(str, Enum):
11
+ """Assessment Plan Functional Area Type Enum"""
12
+
13
+ Safety = "Safety"
14
+ Security = "Security"
15
+ Quality = "Quality"
16
+ Financial = "Financial"
17
+ Maintenance = "Maintenance"
18
+ Operational = "Operational"
19
+ Environmental = "Environmental"
20
+
21
+
22
+ class AssessmentPlan(RegScaleModel):
23
+ """Lines of Inquiry Model"""
24
+
25
+ _module_slug = "assessmentplans"
26
+ _unique_fields = ["id"]
27
+
28
+ id: int = 0
29
+ isPublic: bool = True
30
+ uuid: Optional[str] = None
31
+ planOwnerId: str = Field(default_factory=RegScaleModel.get_user_id)
32
+ title: str
33
+ functionalArea: Union[AssesmentPlanArea, str] = AssesmentPlanArea.Financial
34
+ description: Optional[str] = None
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/{intParentID}",
52
+ )