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,245 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for Custom Fields in the application"""
4
+
5
+ import logging
6
+ from typing import Any, List, Optional
7
+
8
+ from pydantic import ConfigDict
9
+
10
+ from regscale.core.app.utils.app_utils import update_keys_to_lowercase_first_letter
11
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
12
+
13
+ logger = logging.getLogger("regscale")
14
+
15
+
16
+ class CustomField(RegScaleModel):
17
+ _module_slug = "customFields"
18
+
19
+ id: Optional[int] = None
20
+ createdById: Optional[str] = None
21
+ dateCreated: Optional[str] = None
22
+ lastUpdatedById: Optional[str] = None
23
+ isPublic: Optional[bool] = None
24
+ moduleId: Optional[int] = None
25
+ fieldName: Optional[str] = None
26
+ fieldDataType: Optional[str] = None
27
+ active: Optional[bool] = None
28
+ fieldRequired: Optional[bool] = None
29
+ disabled: Optional[bool] = None
30
+ order: Optional[int] = None
31
+ tenantId: int = 1
32
+ dateLastUpdated: Optional[str] = None
33
+ data: Optional[List[Any]] = None
34
+
35
+ @staticmethod
36
+ def _get_additional_endpoints() -> ConfigDict:
37
+ """
38
+ Get additional endpoints for the CustomField model.
39
+
40
+ :return: A dictionary of additional endpoints
41
+ :rtype: ConfigDict
42
+ """
43
+ return ConfigDict(
44
+ insert="/api/{model_slug}/1",
45
+ get_module_with_tenant="/api/{model_slug}/module/{tenantId}/{moduleId}",
46
+ get_module="/api/{model_slug}/module/{moduleId}",
47
+ get_module_required="/api/{model_slug}/moduleRequired/{moduleId}",
48
+ get_custom_field="/api/{model_slug}/{customFieldId}",
49
+ filter_custom_fields="/api/{model_slug}/{tenantId}/{moduleId}/{strSort}/{strDirection}/{intPage}/{intPageSize}",
50
+ update_batch_post="/api/{model_slug}/update/{tenantId}",
51
+ create_custom_field_post="/api/{model_slug}/{tenantId}",
52
+ update_custom_field_put="/api/{model_slug}/{tenantId}",
53
+ update_sort_order_post="/api/{model_slug}/sortOrder/{moduleId}",
54
+ enable_custom_field_put="/api/{model_slug}/enable/{tenantId}/{customFieldId}/{enabled}",
55
+ require_custom_field_put="/api/{model_slug}/require/{tenantId}/{customFieldId}/{required}",
56
+ get_by_parent="/api/{model_slug}/module/{strModule}",
57
+ )
58
+
59
+ @classmethod
60
+ def get_list_by_module_id(cls, module_id: int) -> List["CustomField"]:
61
+ """
62
+ Get a list of custom fields by module ID
63
+
64
+ :param int module_id: The ID of the module
65
+ :return: A list of custom fields
66
+ :rtype: List[CustomField]
67
+ """
68
+ response = cls._get_api_handler().get(
69
+ endpoint=cls.get_endpoint("get_module").format(model_slug=cls._module_slug, moduleId=module_id)
70
+ )
71
+ custom_fields = []
72
+ if response and response.ok:
73
+ for custom_field in response.json():
74
+ custom_fields.append(CustomField(**custom_field))
75
+ return custom_fields
76
+
77
+ @classmethod
78
+ def get_custom_fields_by_module_id(cls, parent_module_id: int) -> List["CustomField"]:
79
+ """
80
+ Get a list of custom fields by module ID
81
+
82
+ :param int parent_module_id: The ID of the module
83
+ :return: List of CustomField objects
84
+ :rtype: List[CustomField]
85
+ """
86
+ custom_fields = CustomField.get_list_by_module_id(module_id=cls.get_module_id())
87
+ for field in custom_fields:
88
+ data_field_list = CustomFieldsData.get_list_by_parent_id_and_module_id(
89
+ parent_id=parent_module_id, module_id=field.moduleId
90
+ )
91
+ for data in data_field_list:
92
+ if data.fieldId == field.id:
93
+ field.data = data
94
+ if field.data:
95
+ field.data = update_keys_to_lowercase_first_letter(field.data)
96
+ return custom_fields
97
+
98
+
99
+ class CustomFieldsData(RegScaleModel):
100
+ _module_slug = "customFieldsData"
101
+ id: Optional[int] = None
102
+ createdById: Optional[str] = None
103
+ dateCreated: Optional[str] = None
104
+ lastUpdatedById: Optional[str] = None
105
+ isPublic: Optional[bool] = None
106
+ moduleId: Optional[int] = None
107
+ parentId: Optional[int] = None
108
+ field: Optional[CustomField] = None
109
+ fieldId: Optional[int] = None
110
+ fieldName: Optional[str] = None
111
+ fieldValue: Optional[str] = None
112
+ fieldDataType: Optional[str] = None
113
+ fieldRequired: Optional[bool] = None
114
+ disabled: Optional[bool] = None
115
+ tenantsId: Optional[int] = None
116
+ dateLastUpdated: Optional[str] = None
117
+
118
+ @classmethod
119
+ def get_by_module_id(cls, parent_id: int, module_id: int) -> Optional[List["CustomFieldsData"]]:
120
+ """
121
+ Get a list of custom fields by module ID.
122
+
123
+ :param int parent_id: The ID of the module parent id field
124
+ :param int module_id: The ID of the module
125
+ :return: A list of custom fields, None if no custom fields are found
126
+ :rtype: Optional[List[CustomFieldsData]]
127
+ """
128
+ response = cls._get_api_handler().get(
129
+ endpoint=cls.get_endpoint("get_custom_fields_data_get").format(
130
+ model_slug=cls._module_slug, parentId=parent_id, moduleId=module_id
131
+ )
132
+ )
133
+ if response and response.ok:
134
+ return [CustomFieldsData(**data) for data in response.json()]
135
+ return None
136
+
137
+ @classmethod
138
+ def get_by_id(cls, cid: int, module_id: int) -> Optional["CustomFieldsData"]:
139
+ """
140
+ Get a list of custom fields by module ID.
141
+
142
+ :param int cid: The ID of the custom field
143
+ :param int module_id: The ID of the module
144
+ :return: A list of custom fields, None if no custom fields are found
145
+ :rtype: Optional[CustomFieldsData]
146
+ """
147
+ response = cls._get_api_handler().get(
148
+ endpoint=cls.get_endpoint("get_custom_fields_data").format(
149
+ model_slug=cls._module_slug, id=cid, moduleId=module_id
150
+ )
151
+ )
152
+ if response and response.ok:
153
+ # print(response.json())
154
+ return CustomFieldsData(**response.json())
155
+ return None
156
+
157
+ @staticmethod
158
+ def _get_additional_endpoints() -> ConfigDict:
159
+ """
160
+ Get additional endpoints for the CustomFieldData model.
161
+
162
+ :return: A dictionary of additional endpoints
163
+ :rtype: ConfigDict
164
+ """
165
+ return ConfigDict(
166
+ get_custom_fields_data="/api/{model_slug}/{id}/{moduleId}",
167
+ update_batch_post="/api/{model_slug}/update",
168
+ create_custom_field_data_post="/api/{model_slug}",
169
+ get_custom_fields_data_get="/api/{model_slug}/createCustomFieldsData/{parentId}/{moduleId}",
170
+ get_by_parent="/api/{model_slug}/{intParentID}/{strModule}",
171
+ )
172
+
173
+ @classmethod
174
+ def get_list_by_parent_id_and_module_id(cls, parent_id: int, module_id: int) -> List["CustomFieldsData"]:
175
+ """
176
+ Get a list of custom fields by module ID.
177
+
178
+ :param int parent_id: The ID of the parent
179
+ :param int module_id: The ID of the module
180
+ :return: A list of custom field datas
181
+ :rtype: List["CustomFieldsData"]
182
+ """
183
+ response = cls._get_api_handler().get(
184
+ endpoint=cls.get_endpoint("get_custom_fields_data_get").format(
185
+ model_slug=cls._module_slug, parentID=parent_id, moduleID=module_id
186
+ )
187
+ )
188
+ custom_fields = []
189
+ if response and response.ok:
190
+ for custom_field_data in response.json():
191
+ custom_fields.append(CustomFieldsData(**custom_field_data))
192
+ return custom_fields
193
+
194
+ @classmethod
195
+ def batch_update(cls, custom_data_fields: List["CustomFieldsData"]) -> bool:
196
+ """
197
+ Batch update custom fields data.
198
+
199
+ :param List[CustomFieldsData] custom_data_fields: The list of custom fields data
200
+ :return: Whether the batch update was successful
201
+ :rtype: bool
202
+ """
203
+ response = cls._get_api_handler().post(
204
+ endpoint=cls.get_endpoint("update_batch_post").format(model_slug=cls._module_slug),
205
+ data=[custom_data_field.dict() for custom_data_field in custom_data_fields],
206
+ )
207
+ if response and response.ok:
208
+ return True
209
+ else:
210
+ logger.error("Failed to batch update custom fields data")
211
+ return False
212
+
213
+
214
+ class CustomFieldsSelectItem(RegScaleModel):
215
+ _module_slug = "customFieldsSelectItems"
216
+
217
+ @staticmethod
218
+ def _get_additional_endpoints() -> ConfigDict:
219
+ """
220
+ Get additional endpoints for the CustomFieldSelectItem model.
221
+
222
+ :return: A dictionary of additional endpoints
223
+ :rtype: ConfigDict
224
+ """
225
+ return ConfigDict(
226
+ create_items_post="/api/{model_slug}/items/{tenantId}",
227
+ update_items_put="/api/{model_slug}/items/{tenantId}",
228
+ get_items="/api/{model_slug}/items/{parentId}",
229
+ get_items_for_request="/api/{model_slug}/items/{parentId}/{moduleId}/{requestId}",
230
+ enable_item_put="/api/{model_slug}/enable/{tenantId}/{customFieldSelectItemId}/{enabled}",
231
+ )
232
+
233
+ id: Optional[int] = None
234
+ createdById: Optional[str] = None
235
+ dateCreated: Optional[str] = None
236
+ lastUpdatedById: Optional[str] = None
237
+ isPublic: Optional[bool] = None
238
+ moduleId: Optional[int] = None
239
+ parentId: Optional[int] = None
240
+ fieldKey: Optional[str] = None
241
+ fieldValue: Optional[str] = None
242
+ tenantsId: Optional[int] = None
243
+ dateLastUpdated: Optional[str] = None
244
+ disabled: Optional[bool] = None
245
+ itemOrder: Optional[int] = None
@@ -0,0 +1,109 @@
1
+ """Data model class"""
2
+
3
+ from enum import Enum
4
+ from typing import List, Optional, cast
5
+
6
+ from pydantic import Field, ConfigDict
7
+ from requests import Response
8
+
9
+ from regscale.core.app.utils.app_utils import (
10
+ get_current_datetime,
11
+ create_progress_object,
12
+ )
13
+ from .regscale_model import RegScaleModel, T
14
+ from ...core.app.internal.model_editor import get_all_by_parent
15
+
16
+
17
+ class DataListItem(RegScaleModel):
18
+ """
19
+ Data list item model class
20
+ """
21
+
22
+ id: int
23
+ dateCreated: str
24
+ dataType: str
25
+ dataSource: str
26
+
27
+
28
+ class DataDataType(str, Enum):
29
+ """
30
+ Data data type enum
31
+ """
32
+
33
+ JSON = "JSON"
34
+ XML = "XML"
35
+ YAML = "YAML"
36
+
37
+ def __str__(self):
38
+ return self.value
39
+
40
+
41
+ class Data(RegScaleModel):
42
+ """
43
+ Data model class
44
+ """
45
+
46
+ _module_slug = "data"
47
+ _unique_fields = [
48
+ ["parentId", "parentModule", "dataSource", "dataType"],
49
+ ]
50
+
51
+ id: Optional[int] = 0
52
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
53
+ dateCreated: str = Field(default_factory=get_current_datetime)
54
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
55
+ isPublic: bool = True
56
+ dataSource: str
57
+ dataType: Optional[str] = None
58
+ rawData: Optional[str] = None
59
+ parentId: int
60
+ parentModule: str
61
+ tenantsId: int = 1
62
+ dateLastUpdated: str = Field(default_factory=get_current_datetime)
63
+
64
+ @staticmethod
65
+ def _get_additional_endpoints() -> ConfigDict:
66
+ """
67
+ Get additional endpoints for the Data model.
68
+
69
+ :return: A dictionary of additional endpoints
70
+ :rtype: ConfigDict
71
+ """
72
+ return ConfigDict(
73
+ batch_create="/api/{model_slug}/batchCreate",
74
+ batch_update="/api/{model_slug}/batchUpdate",
75
+ get_all_by_parent="/api/{model_slug}/getAllByParent/{intParentID}/{strModule}",
76
+ )
77
+
78
+ @classmethod
79
+ def get_map(cls, plan_id: int, key_field: str = "parentId") -> dict[str, "Data"]:
80
+ """
81
+ Get the asset map for the asset and cache it in Redis.
82
+
83
+ :param int plan_id: Security Plan ID
84
+ :param str key_field: Key field to use, defaults to "identifier"
85
+ :return: Data Map
86
+ :rtype: dict[str, "Data"]
87
+
88
+ # TODO: Implement filter by plan_id in RegScale API
89
+ """
90
+ search_data = f"""query {{
91
+ data(skip: 0, take: 50) {{
92
+ items {{
93
+ {cls.build_graphql_fields()}
94
+ }}
95
+ totalCount
96
+ pageInfo {{
97
+ hasNextPage
98
+ }}
99
+ }}
100
+ }}"""
101
+ response = cls._get_api_handler().graph(query=search_data)
102
+ objects = cast(List["Data"], cls._handle_graph_response(response))
103
+ return_assets = {}
104
+ for obj in objects:
105
+ identifier = getattr(obj, key_field, None)
106
+ if identifier:
107
+ return_assets[identifier] = obj
108
+
109
+ return {k: v.model_dump_json() for k, v in return_assets.items()}
@@ -0,0 +1,40 @@
1
+ """DataCenter model for RegScale."""
2
+
3
+ import warnings
4
+ from urllib.parse import urljoin
5
+
6
+ from regscale.core.app.api import Api
7
+ from regscale.core.app.application import Application
8
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
9
+
10
+
11
+ class DataCenter(RegScaleModel):
12
+ """DataCenter pydantic BaseModel."""
13
+
14
+ _module_slug = "datacenters"
15
+
16
+ id: int = 0
17
+ uuid: str = ""
18
+ facilityId: int
19
+ parentId: int
20
+ parentModule: str
21
+ isPublic: bool = True
22
+ facility: str = ""
23
+
24
+ def post(self, app: Application) -> dict:
25
+ """
26
+ Post a DataCenter to RegScale
27
+
28
+ :param Application app: The application instance
29
+ :return: The response from the API
30
+ :rtype: dict
31
+ """
32
+ warnings.warn(
33
+ "The 'post' method is deprecated, use 'create' method instead",
34
+ DeprecationWarning,
35
+ )
36
+ api = Api()
37
+ url = urljoin(app.config.get("domain", ""), "/api/datacenters")
38
+ data = self.dict()
39
+ response = api.post(url, json=data)
40
+ return response.json()
@@ -0,0 +1,203 @@
1
+ import concurrent.futures
2
+ import logging
3
+ from typing import List, Optional
4
+
5
+ from pydantic import ConfigDict, Field
6
+
7
+ from regscale.core.app.utils.app_utils import get_current_datetime
8
+
9
+ from .. import Property
10
+ from .regscale_model import RegScaleModel
11
+
12
+ logger = logging.getLogger("regscale")
13
+
14
+
15
+ class Deviation(RegScaleModel):
16
+ """
17
+ Deviation model class
18
+ """
19
+
20
+ _module_slug = "deviations"
21
+ _unique_fields = [
22
+ ["parentIssueId", "deviationType", "rationale", "requestedImpactRating", "vulnerabilityId"],
23
+ ]
24
+ _parent_id_field = "parentIssueId"
25
+
26
+ parentIssueId: int # Required
27
+ requestedImpactRating: str # Required
28
+ deviationType: str # Required
29
+ rationale: str # Required
30
+
31
+ id: int = 0
32
+ otherIdentifier: Optional[str] = None
33
+ isPublic: bool = True
34
+ uuid: Optional[str] = None
35
+ dateSubmitted: Optional[str] = None
36
+ evidenceDescription: Optional[str] = None
37
+ operationalImpacts: Optional[str] = None
38
+ riskJustification: Optional[str] = None
39
+ tmpExploitCodeMaturity: Optional[str] = None
40
+ tmpRemediationLevel: Optional[str] = None
41
+ tmpReportConfidence: Optional[str] = None
42
+ envConfidentiality: Optional[str] = None
43
+ envIntegrity: Optional[str] = None
44
+ envAvailability: Optional[str] = None
45
+ envAttackVector: Optional[str] = None
46
+ envAttackComplexity: Optional[str] = None
47
+ envPrivilegesRequired: Optional[str] = None
48
+ envUserInteraction: Optional[str] = None
49
+ envScope: Optional[str] = None
50
+ envModConfidentiality: Optional[str] = None
51
+ envModIntegrity: Optional[str] = None
52
+ envModAvailability: Optional[str] = None
53
+ vulnerabilityId: Optional[str] = None
54
+ baseScore: Optional[float] = None
55
+ temporalScore: Optional[float] = None
56
+ environmentalScore: Optional[float] = None
57
+ envAttackVectorExplanation: Optional[str] = None
58
+ envAttackComplexityExplanation: Optional[str] = None
59
+ envPrivilegesRequiredExplanation: Optional[str] = None
60
+ envUserInteractionExplanation: Optional[str] = None
61
+ envConfidentialityExplanation: Optional[str] = None
62
+ envIntegrityExplanation: Optional[str] = None
63
+ envAvailabilityExplanation: Optional[str] = None
64
+ tmpExploitCodeMaturityExplanation: Optional[str] = None
65
+ tmpRemediationLevelExplanation: Optional[str] = None
66
+ tmpReportConfidenceExplanation: Optional[str] = None
67
+ baseSeverity: Optional[str] = None
68
+ temporalSeverity: Optional[str] = None
69
+ environmentalSeverity: Optional[str] = None
70
+ finalVectorString: Optional[str] = None
71
+ overallRiskReductionExplanation: Optional[str] = None
72
+ additionalInformation: Optional[str] = None
73
+ drNumber: Optional[str] = None
74
+ createdById: str = Field(default_factory=RegScaleModel.get_user_id)
75
+ dateCreated: str = Field(default_factory=get_current_datetime)
76
+ lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
77
+ dateLastUpdated: str = Field(default_factory=get_current_datetime)
78
+
79
+ @classmethod
80
+ def mapping(cls) -> dict:
81
+ """
82
+ Get the mapping for the Deviation model.
83
+
84
+ :return: A dictionary of mappings
85
+ :rtype: dict
86
+ """
87
+ return {
88
+ "FP": "False Positive (FP)",
89
+ "FP_RA": "False Positive (FP)",
90
+ "OR": "Operational Requirements (OR)",
91
+ "OR_RA": "RA & OR",
92
+ "OR RA": "RA & OR",
93
+ "RA": "Risk Adjustment (RA)",
94
+ }
95
+
96
+ @staticmethod
97
+ def _get_additional_endpoints() -> ConfigDict:
98
+ """
99
+ Get additional endpoints for the Deviations model.
100
+
101
+ :return: A dictionary of additional endpoints
102
+ :rtype: ConfigDict
103
+ """
104
+ return ConfigDict( # type: ignore
105
+ get_by_issue="/api/{model_slug}/getbyIssue/{intParentID}/{includeDrNumber}",
106
+ get_all_by_security_plan="/api/{model_slug}/getAllBySecurityPlan/{sspId}/{includeDrNumber}",
107
+ export_deviation_by_ssp="/api/{model_slug}/getAllByPart/{intParentID}/{strModule}/{strType}/{strPart}",
108
+ )
109
+
110
+ @classmethod
111
+ def get_by_issue(cls, issue_id: int, include_dr_number: bool = True) -> Optional["Deviation"]:
112
+ """
113
+ Get a deviation by issue id
114
+
115
+ :param int issue_id: Ths issue to search for
116
+ :param bool include_dr_number: Include DR number in the response
117
+ :return: A list of deviations
118
+ :rtype: Optional["Deviation"]
119
+ """
120
+ response = cls._get_api_handler().get(
121
+ endpoint=cls.get_endpoint("get_by_issue").format(intParentID=issue_id, includeDrNumber=include_dr_number)
122
+ )
123
+ if response and response.status_code == 200:
124
+ return cls(**response.json())
125
+ return None
126
+
127
+ @classmethod
128
+ def get_by_security_plan(cls, ssp_id: int, include_dr_number: bool = True) -> List["Deviation"]:
129
+ """
130
+ Get a list of deviations by ssp id
131
+
132
+ :param int ssp_id: Ths ssp to search for
133
+ :return: A list of deviations
134
+ :rtype: Optional["Deviation"]
135
+ """
136
+ response = cls._get_api_handler().get(
137
+ endpoint=cls.get_endpoint("get_all_by_security_plan").format(
138
+ sspId=ssp_id, includeDrNumber=include_dr_number
139
+ )
140
+ )
141
+ if response and response.status_code == 200:
142
+ return [cls(**res) for res in response.json()]
143
+ return []
144
+
145
+ @classmethod
146
+ def get_dr_ids(cls, issue_id: int) -> Optional[Property]:
147
+ """
148
+ Get a list of control implementations by plan ID.
149
+
150
+ :param int issue_id: Issue Id
151
+ :return: A single Property object with the DR number if it exists or None
152
+ :rtype: Optional[Property]
153
+ """
154
+ properties = [
155
+ prop
156
+ for prop in Property.get_all_by_parent(parent_id=issue_id, parent_module="issues")
157
+ if prop.key == "dr_number"
158
+ ]
159
+ if properties:
160
+ return properties.pop()
161
+ return None
162
+
163
+ @classmethod
164
+ def get_existing_deviations_by_ssp(
165
+ cls, ssp_id: int, issue_ids: List[int], poam_map: dict = None
166
+ ) -> List["Deviation"]:
167
+ """
168
+ Get existing deviations by SSP
169
+
170
+ :param int ssp_id: Security Plan ID
171
+ :param List[int] issue_ids: List of issue IDs
172
+ :param dict poam_map: POAM map, optional
173
+ :return: list of deviations
174
+ :rtype: List["Deviation"]
175
+ """
176
+ # poam_map description:
177
+ # The main dict key of `id_other_identifier_map` are the `otherIdentifier` of each issue.
178
+ # The values of `id_other_identifier_map` are dictionaries themselves, with the following structure:
179
+ # The values are dictionaries with the following keys
180
+ # - `id`: The ID of the issue in RegScale
181
+ # - `dr_number`: The DR number of the issue
182
+
183
+ # CAUTION: This needs to be moved to platform specific code (see REG-9998)
184
+ logger.info("Looking up existing RegScale deviations for SSP# %i.. ", ssp_id)
185
+ with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
186
+ properties = (
187
+ [prop for prop in list(executor.map(cls.get_dr_ids, issue_ids)) if prop] if not poam_map else []
188
+ )
189
+ deviations = [dev for dev in list(executor.map(cls.get_by_issue, issue_ids)) if dev]
190
+
191
+ for deviation in deviations:
192
+ if not poam_map:
193
+ prop = [prop for prop in properties if prop.parentId == deviation.parentIssueId]
194
+ if prop:
195
+ deviation.extra_data = {"dr_number": prop.pop().value}
196
+ else:
197
+ deviation.extra_data = {"dr_number": None}
198
+ else:
199
+ match = [val for val in poam_map.values() if val.get("id") == deviation.parentIssueId]
200
+ if match:
201
+ deviation.extra_data = {"dr_number": match.pop().get("dr_number")}
202
+
203
+ return deviations
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Class for emails to send emails in RegScale platform"""
4
+
5
+ from typing import Optional
6
+
7
+ from pydantic import ConfigDict, Field
8
+
9
+ from regscale.core.app.utils.app_utils import create_logger
10
+ from regscale.core.app.utils.app_utils import get_current_datetime
11
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
12
+
13
+
14
+ class Email(RegScaleModel):
15
+ """Class for email capabilities via RegScale platform"""
16
+
17
+ _module_slug = "email"
18
+ _exclude_graphql_fields = ["tenantsId"]
19
+
20
+ to: str
21
+ subject: str
22
+ id: Optional[int] = 0
23
+ fromEmail: str = Field(description="Cannot use from since it is a reserved word in Python", alias="from")
24
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
25
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
26
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
27
+ isPublic: Optional[bool] = True
28
+ cc: Optional[str] = ""
29
+ body: Optional[str] = ""
30
+ dateSent: Optional[str] = Field(default_factory=get_current_datetime)
31
+ tenantsId: Optional[int] = 1
32
+ emailSenderId: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
33
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
34
+
35
+ @staticmethod
36
+ def _get_additional_endpoints() -> ConfigDict:
37
+ """
38
+ Get additional endpoints for the Issues model.
39
+
40
+ :return: A dictionary of additional endpoints
41
+ :rtype: ConfigDict
42
+ """
43
+ return ConfigDict(
44
+ get_domain="/api/{model_slug}/getDomain",
45
+ get_admin_email="/api/{model_slug}/getAdminEmail",
46
+ filter_my_email="/api/{model_slug}/filterMyEmail/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
47
+ filter_email="/api/{model_slug}/filterEmail/{strUser}/{strSortBy}/{strDirection}/{intPage}/{intPageSize}",
48
+ find_my_email="/api/{model_slug}/findMyEmail/{intID}",
49
+ )
50
+
51
+ def send(self) -> bool:
52
+ """
53
+ Send the email
54
+
55
+ :return: Whether the email was sent successfully
56
+ :rtype: bool
57
+ """
58
+ logger = create_logger()
59
+ endpoint = self.get_endpoint("insert")
60
+ response = self._get_api_handler().post(endpoint=endpoint, data=self.dict())
61
+ if response and response.ok:
62
+ return True
63
+ import json
64
+
65
+ logger.error(
66
+ f"Failed to create {self.__class__.__name__}\n Endpoint: {endpoint}\n Payload: "
67
+ f"{json.dumps(self.dict(), indent=2)}",
68
+ exc_info=True,
69
+ )
70
+ if response and not response.ok:
71
+ logger.error(f"Response Error: Code #{response.status_code}: {response.reason}\n{response.text}")
72
+ return False
73
+ if response is None:
74
+ error_msg = "Response was None"
75
+ logger.error(error_msg)
76
+ return False
77
+ error_msg = f"Response Code: {response.status_code}:{response.reason} - {response.text}"
78
+ logger.error(error_msg)
79
+ return False
80
+
81
+ def create(self, _=False) -> bool:
82
+ """
83
+ Create the email
84
+
85
+ :return: Email object
86
+ :rtype: Email
87
+ """
88
+ return self.send()
89
+
90
+ def delete(self) -> bool:
91
+ """
92
+ Delete is not supported for emails, returns False
93
+
94
+ :return: False because it is not supported
95
+ :rtype: bool
96
+ """
97
+ return False