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,436 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for Scan in the application"""
4
+ import logging
5
+ import pickle
6
+ import warnings
7
+ from concurrent.futures import ThreadPoolExecutor, as_completed
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+ from typing import Dict, List, Optional, Tuple, Union
11
+
12
+ from pydantic import ConfigDict, Field
13
+ from requests import JSONDecodeError, RequestException, Response
14
+
15
+ from regscale.core.app.api import Api
16
+ from regscale.core.app.application import Application
17
+ from regscale.core.app.utils.app_utils import (
18
+ convert_datetime_to_regscale_string,
19
+ create_progress_object,
20
+ get_current_datetime,
21
+ )
22
+ from regscale.core.utils.date import normalize_date
23
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
24
+
25
+ logger = logging.getLogger("regscale")
26
+
27
+
28
+ class ScanHistory(RegScaleModel):
29
+ """Model for ScanHistory in the application"""
30
+
31
+ _module_slug = "scanhistory"
32
+ _unique_fields = [
33
+ ["scanningTool", "parentId", "parentModule"],
34
+ ]
35
+
36
+ id: int = 0
37
+ scanningTool: str
38
+ dateCreated: str = Field(default_factory=get_current_datetime)
39
+ dateLastUpdated: str = Field(default_factory=get_current_datetime)
40
+ createdById: str = Field(default_factory=RegScaleModel.get_user_id)
41
+ lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
42
+ tenantsId: int = 1
43
+ uuid: Optional[str] = None
44
+ sicuraId: Optional[str] = None
45
+ tenableId: Optional[str] = None
46
+ scanDate: Optional[str] = None
47
+ scannedIPs: Optional[int] = None
48
+ checks: Optional[int] = None
49
+ vInfo: Optional[int] = None
50
+ vLow: int = 0
51
+ vMedium: int = 0
52
+ vHigh: int = 0
53
+ vCritical: int = 0
54
+ parentId: Optional[int] = None
55
+ parentModule: Optional[str] = None
56
+ isPublic: bool = True
57
+
58
+ @staticmethod
59
+ def _get_additional_endpoints() -> ConfigDict:
60
+ """
61
+ Get additional endpoints for the ScanHistory model, using {model_slug} as a placeholder for the model slug.
62
+
63
+ :return: A dictionary of additional endpoints
64
+ :rtype: ConfigDict
65
+ """
66
+
67
+ return ConfigDict( # type: ignore
68
+ get_by_parent_recursive="/api/{model_slug}/getAllByParentRecursive/{intParentID}/{strModule}/{filterDate}",
69
+ get_all_by_parent="/api/{model_slug}/getAllByParent/{intParentID}/{strModule}",
70
+ get_count="/api/{model_slug}/getCount",
71
+ get_scan_dates_by_parent="/api/{model_slug}/getScanDatesByParent/{intID}/{strModule}",
72
+ filter_scans="/api/{model_slug}/filterScans/{intID}/{strModule}/{intPage}/{intPageSize}",
73
+ insert="/api/{model_slug}",
74
+ update="/api/{model_slug}",
75
+ batch_create="/api/{model_slug}/batchCreate",
76
+ get="/api/{model_slug}/find/{id}",
77
+ find_by_guid="/api/{model_slug}/findByGUID/{strGUID}",
78
+ )
79
+
80
+ @classmethod
81
+ def get_by_parent_recursive(cls, parent_id: int, parent_module: str, filter_date: str = "") -> List["ScanHistory"]:
82
+ """
83
+ Get a list of control implementations by plan ID.
84
+
85
+ :param int parent_id: Parent ID
86
+ :param str parent_module: Parent Module
87
+ :param str filter_date: Filter Date
88
+ :return: A list of ScanHistory objects
89
+ :rtype: List[ScanHistory]
90
+ :raises RequestException: If the API request fails
91
+ """
92
+ endpoint = cls.get_endpoint("get_by_parent_recursive").format(
93
+ model_slug=cls._module_slug, intParentID=parent_id, strModule=parent_module, filterDate=filter_date
94
+ )
95
+ logger.debug(f"Endpoint: {endpoint}")
96
+ response = cls._get_api_handler().get(endpoint=endpoint)
97
+ logger.debug(f"Response: {response.status_code}")
98
+ if response and response.ok:
99
+ return [cls(**ci) for ci in response.json()]
100
+ else:
101
+ raise RequestException(f"API request failed with status code {response.status_code}")
102
+
103
+ def __hash__(self) -> int:
104
+ """
105
+ Hash items in Scan class
106
+
107
+ :return: Hashed Scan
108
+ :rtype: int
109
+ """
110
+ fmt = "%Y-%m-%dT%H:%M:%S"
111
+ return hash(
112
+ (
113
+ self.tenableId,
114
+ self.parentId,
115
+ self.parentModule,
116
+ normalize_date(self.scanDate, fmt),
117
+ )
118
+ )
119
+
120
+ def __eq__(self, other: Union["ScanHistory", dict]) -> bool:
121
+ """
122
+ Compare two Scan objects for equality.
123
+
124
+ :param other: Other Scan object or dictionary to compare
125
+ :type other: Union["ScanHistory", dict]
126
+ :return: True if equal, False otherwise
127
+ :rtype: bool
128
+ """
129
+ fmt = "%Y-%m-%dT%H:%M:%S"
130
+ if isinstance(other, ScanHistory):
131
+ return (
132
+ self.tenableId == other.tenableId
133
+ and self.parentId == other.parentId
134
+ and self.parentModule == other.parentModule
135
+ and normalize_date(self.scanDate, fmt) == normalize_date(other.scanDate, fmt)
136
+ )
137
+
138
+ return (
139
+ self.tenableId == other["tenableId"]
140
+ and self.parentId == other["parentId"]
141
+ and self.parentModule == other["parentModule"]
142
+ and normalize_date(self.scanDate, fmt) == normalize_date(other["scanDate"], fmt)
143
+ )
144
+
145
+ @staticmethod
146
+ def post_scan(app: Application, api: Api, scan: "ScanHistory") -> "ScanHistory":
147
+ """
148
+ Post a Scan to RegScale.
149
+
150
+ :param Application app: Application Instance
151
+ :param Api api: Api Instance
152
+ :param ScanHistory scan: Scan Object
153
+ :return: RegScale Scan
154
+ :rtype: ScanHistory
155
+ """
156
+ res = api.post(url=app.config["domain"] + "/api/scanhistory", json=scan.dict())
157
+ if res.status_code != 200:
158
+ api.logger.error(res)
159
+ return ScanHistory(**res.json())
160
+
161
+ @staticmethod
162
+ def group_vulns_by_severity(associated_vulns: List[dict]) -> Dict[str, List[dict]]:
163
+ """
164
+ Groups vulnerabilities by severity
165
+
166
+ :param List[dict] associated_vulns: A list of associated vulnerabilities
167
+ :return: Dictionary of vulnerabilities grouped by severity
168
+ :rtype: Dict[str, List[dict]]
169
+ """
170
+ return {
171
+ vuln["severity"]: [v for v in associated_vulns if v["severity"] == vuln["severity"]]
172
+ for vuln in associated_vulns
173
+ }
174
+
175
+ @staticmethod
176
+ def get_existing_scan_history(app: Application, reg_asset: dict) -> List[dict]:
177
+ """
178
+ Gets existing scan history for a RegScale asset
179
+
180
+ :param Application app: Application Instance
181
+ :param dict reg_asset: RegScale Asset
182
+ :return: List of existing scan history
183
+ :rtype: List[dict]
184
+ """
185
+ api = Api()
186
+ res = api.get(url=app.config["domain"] + f"/api/scanhistory/getAllByParent/{reg_asset.id}/assets")
187
+ if not res.raise_for_status():
188
+ return res.json()
189
+
190
+ @staticmethod
191
+ def create_scan_from_tenable(
192
+ associated_vulns: List[dict], reg_asset: dict, config: dict, tenant_id: int
193
+ ) -> "ScanHistory":
194
+ """
195
+ Creates a Scan object from a Tenable scan
196
+
197
+ :param List[dict] associated_vulns: List of associated vulnerabilities
198
+ :param dict reg_asset: RegScale Asset
199
+ :param dict config: Application Config
200
+ :param int tenant_id: Tenant ID
201
+ :return: Scan object
202
+ :rtype: ScanHistory
203
+ """
204
+ grouped_vulns = ScanHistory.group_vulns_by_severity(associated_vulns)
205
+ return ScanHistory(
206
+ id=0,
207
+ uuid=associated_vulns[0]["scan"]["uuid"],
208
+ scanningTool="NESSUS",
209
+ tenableId=associated_vulns[0]["scan"]["uuid"],
210
+ scanDate=convert_datetime_to_regscale_string(associated_vulns[0]["scan"]["started_at"]),
211
+ scannedIPs=1,
212
+ checks=len(associated_vulns),
213
+ vInfo=len(grouped_vulns["info"]) if "info" in grouped_vulns else 0,
214
+ vLow=len(grouped_vulns["low"]) if "low" in grouped_vulns else 0,
215
+ vMedium=len(grouped_vulns["medium"]) if "medium" in grouped_vulns else 0,
216
+ vHigh=len(grouped_vulns["high"]) if "high" in grouped_vulns else 0,
217
+ vCritical=(len(grouped_vulns["critical"]) if "critical" in grouped_vulns else 0),
218
+ parentId=reg_asset.id,
219
+ parentModule="assets",
220
+ createdById=config["userId"],
221
+ lastUpdatedById=config["userId"],
222
+ dateCreated=convert_datetime_to_regscale_string(datetime.now()),
223
+ tenantsId=tenant_id,
224
+ )
225
+
226
+ @staticmethod
227
+ def prepare_scan_history_for_sync(
228
+ app: Application,
229
+ nessus_list: List[dict],
230
+ existing_assets: List[dict],
231
+ ) -> List["ScanHistory"]:
232
+ """
233
+ Prepares scan history data for synchronization.
234
+
235
+ :param Application app: The Application object to use for database operations.
236
+ :param List[dict] nessus_list: A list of Nessus scan history data.
237
+ :param List[dict] existing_assets: A list of existing Asset objects to compare against.
238
+ :return: List of scan history objects
239
+ :rtype: List["ScanHistory"]
240
+ """
241
+ new_scan_history = []
242
+ assets = {asset["asset"]["uuid"] for asset in nessus_list}
243
+ asset_count = 0
244
+ api = Api()
245
+ config = app.config
246
+ tenant_id = api.get(url=api.config["domain"] + "/api/tenants/config").json()["id"]
247
+
248
+ def process_asset(asset: str) -> None:
249
+ """
250
+ Process an asset from the Nessus scan history data.
251
+
252
+ :param str asset: Asset UUID
253
+ :rtype: None
254
+ """
255
+ nonlocal asset_count
256
+ asset_count += 1
257
+ if asset_count % 100 == 0:
258
+ app.logger.debug(f"Processing asset {asset_count} of {len(assets)}")
259
+ associated_vulns = [ness for ness in nessus_list if ness["asset"]["uuid"] == asset]
260
+ reg_assets = [reg for reg in existing_assets if reg["tenableId"] == asset]
261
+ if reg_assets:
262
+ reg_asset = reg_assets[0] if reg_assets else None
263
+ existing_scans = ScanHistory.get_existing_scan_history(app, reg_asset)
264
+ scan = ScanHistory.create_scan_from_tenable(associated_vulns, reg_asset, config, tenant_id)
265
+ if scan not in existing_scans:
266
+ new_scan_history.append(scan)
267
+
268
+ with ThreadPoolExecutor(max_workers=30) as executor:
269
+ executor.map(process_asset, assets)
270
+
271
+ return new_scan_history
272
+
273
+ @staticmethod
274
+ def sync_scan_history_to_regscale(
275
+ app: Application,
276
+ new_scan_history: List["ScanHistory"],
277
+ ) -> Tuple[List[Response], List["ScanHistory"]]:
278
+ """
279
+ Synchronizes scan history to RegScale
280
+
281
+ :param Application app: Application Instance
282
+ :param List[ScanHistory] new_scan_history: List of new scan history items
283
+ :return: Tuple of Response and Scan
284
+ :rtype: Tuple[List[Response], List[ScanHistory]]
285
+ """
286
+ tup_res = []
287
+ if new_scan_history:
288
+ app.logger.info(f"Inserting {len(new_scan_history)} new scan history item(s)")
289
+ tup_res = ScanHistory.bulk_insert(app, new_scan_history)
290
+ app.logger.info("Done!")
291
+ return tup_res
292
+
293
+ @staticmethod
294
+ def convert_from_tenable(
295
+ str_path: str,
296
+ existing_assets: List[dict],
297
+ ) -> List["ScanHistory"]:
298
+ """
299
+ Converts a TenableScan object to a RegScale Scan object
300
+
301
+ :param str str_path: A path to a temporary directory to store the Nessus scan history data.
302
+ :param List[dict] existing_assets: Existing RegScale Assets
303
+ :return: List of RegScale Scans
304
+ :rtype: List[ScanHistory]
305
+ """
306
+ app = Application()
307
+ existing_scan_history_list = []
308
+ file_list = list(Path(str_path).glob("*"))
309
+ with create_progress_object() as progress:
310
+ processing_pages = progress.add_task(
311
+ f"[#ef5d23]Processing {len(file_list)} pages from Tenable...",
312
+ total=len(file_list),
313
+ )
314
+ for index, file in enumerate(file_list):
315
+ app.logger.debug(f"Processing page {index + 1} of {len(file_list)}")
316
+ with open(file, "rb") as vuln_file_wrapper:
317
+ new_scan_data = []
318
+ # import dict from json file
319
+ nessus_list = [vuln.dict() for vuln in pickle.load(vuln_file_wrapper)]
320
+ new_scan_data.extend(ScanHistory.prepare_scan_history_for_sync(app, nessus_list, existing_assets))
321
+ existing_scan_history_list.extend(ScanHistory.sync_scan_history_to_regscale(app, new_scan_data))
322
+ progress.update(processing_pages, advance=1)
323
+
324
+ return existing_scan_history_list
325
+
326
+ @staticmethod
327
+ def bulk_insert(
328
+ app: Application, scans: List["ScanHistory"], max_workers: Optional[int] = 10
329
+ ) -> List[Tuple[Response, "ScanHistory"]]:
330
+ """Bulk insert assets using the RegScale API and ThreadPoolExecutor
331
+
332
+ :param Application app: Application Instance
333
+ :param List[ScanHistory] scans: List of Scans
334
+ :param Optional[int] max_workers: Max Workers, defaults to 10
335
+ :return: List of Tuples containing Response and Scan
336
+ :rtype: List[Tuple[Response, ScanHistory]]
337
+ """
338
+ api = Api()
339
+ res = []
340
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
341
+ futures = [
342
+ executor.submit(
343
+ ScanHistory.insert_scan,
344
+ app,
345
+ api,
346
+ scan,
347
+ )
348
+ for scan in scans
349
+ ]
350
+ for future in as_completed(futures):
351
+ res.append(future.result()[1])
352
+ return res
353
+
354
+ @staticmethod
355
+ def bulk_update(
356
+ app: Application, scans: List["ScanHistory"], max_workers: Optional[int] = 10
357
+ ) -> List["ScanHistory"]:
358
+ """
359
+ Bulk update assets using the RegScale API and ThreadPoolExecutor
360
+
361
+ :param Application app: Application Instance
362
+ :param List[ScanHistory] scans: List of Scans
363
+ :param Optional[int] max_workers: Max Workers, defaults to 10
364
+ :return: List of Scan
365
+ :rtype: List[ScanHistory]
366
+ """
367
+ api = Api()
368
+ res = []
369
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
370
+ futures = [
371
+ executor.submit(
372
+ ScanHistory.update_scan,
373
+ app,
374
+ api,
375
+ scan,
376
+ )
377
+ for scan in scans
378
+ ]
379
+ for future in as_completed(futures):
380
+ res.append(future.result()[1])
381
+ return res
382
+
383
+ @staticmethod
384
+ def update_scan(app: Application, api: Api, regscale_scan: "ScanHistory") -> Tuple[Response, "ScanHistory"]:
385
+ """
386
+ Api wrapper to update a scan
387
+
388
+ :param Application app: Application Instance
389
+ :param Api api: Api Instance
390
+ :param ScanHistory regscale_scan: Regscale Scan
391
+ :return: RegScale Scan and Response
392
+ :rtype: Tuple[Response, ScanHistory]
393
+ """
394
+ scan_res = api.put(
395
+ url=app.config["domain"] + "/api/scanHistory", # no ID needed on this endpoint
396
+ json=regscale_scan.model_dump(),
397
+ )
398
+ regscale_scan.id = scan_res.json()["id"]
399
+ return scan_res, regscale_scan
400
+
401
+ @staticmethod
402
+ def insert_scan(app: Application, api: Api, regscale_scan: "ScanHistory") -> Tuple[Response, "ScanHistory"]:
403
+ """
404
+ Api wrapper to insert a scan
405
+
406
+ :param Application app: Application Instance
407
+ :param Api api: Api Instance
408
+ :param ScanHistory regscale_scan: Regscale Scan
409
+ :return: RegScale Scan and Response
410
+ :rtype: Tuple[Response, ScanHistory]
411
+ """
412
+ scan_res = api.post(
413
+ url=app.config["domain"] + "/api/scanHistory",
414
+ json=regscale_scan.model_dump(),
415
+ )
416
+ if not scan_res.ok:
417
+ api.logger.error(f"Unable to insert scan: {scan_res.status_code}: {scan_res.reason}. {scan_res.text}")
418
+ else:
419
+ try:
420
+ regscale_scan.id = scan_res.json()["id"]
421
+ except (KeyError, JSONDecodeError) as ex:
422
+ api.logger.error(f"Unable to insert scan: {ex}")
423
+ return scan_res, regscale_scan
424
+
425
+
426
+ class Scan(ScanHistory):
427
+ """
428
+ DEPRECATED: Scan class is deprecated. Use ScanHistory instead.
429
+ """
430
+
431
+ def __init__(self, *args, **kwargs):
432
+ warnings.warn(
433
+ "Scan class is deprecated. Use ScanHistory instead.",
434
+ DeprecationWarning,
435
+ )
436
+ super().__init__(*args, **kwargs)
@@ -0,0 +1,53 @@
1
+ """
2
+ QueryParameter, Query, and Search models used for assets
3
+ """
4
+
5
+ from datetime import datetime
6
+ from typing import List, Optional
7
+
8
+ from pydantic import BaseModel
9
+
10
+
11
+ class QueryParameter(BaseModel):
12
+ """
13
+ QueryParameter object
14
+ """
15
+
16
+ id: int = 0
17
+ field: str = ""
18
+ name: str = ""
19
+ type: str = ""
20
+ operator: str = ""
21
+ value: str = ""
22
+ viewName: Optional[str] = ""
23
+
24
+
25
+ class Query(BaseModel):
26
+ id: int = 0
27
+ viewName: str = ""
28
+ module: str = ""
29
+ scope: str = ""
30
+ createdById: str = ""
31
+ dateCreated: Optional[datetime] = datetime.now()
32
+ parameters: List[QueryParameter] = []
33
+
34
+
35
+ class Search(BaseModel):
36
+ """
37
+ Search object
38
+ """
39
+
40
+ parentID: int = 0
41
+ module: str = ""
42
+ friendlyName: str = ""
43
+ workbench: str = ""
44
+ base: str = ""
45
+ sort: str = "id"
46
+ direction: str = "Ascending"
47
+ simpleSearch: str = ""
48
+ page: int = 0
49
+ pageSize: int = 0
50
+ query: Optional[Query] = None
51
+ groupBy: str = ""
52
+ intDays: int = 0
53
+ subTab: bool = False
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Dataclass for Security Control in the application"""
4
+
5
+ from typing import Any, List, Optional
6
+
7
+ from pydantic import Field, ConfigDict
8
+
9
+ from regscale.core.app.api import Api
10
+ from regscale.core.app.application import Application
11
+ from regscale.core.app.utils.app_utils import get_current_datetime
12
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
13
+
14
+
15
+ class SecurityControl(RegScaleModel):
16
+ """Security Control
17
+
18
+ :return: A RegScale Security Control instance
19
+ """
20
+
21
+ _module_slug = "SecurityControls"
22
+ _module_str = "securitycontrol"
23
+ _unique_fields = [
24
+ ["controlId", "catalogueId"],
25
+ ]
26
+ _parent_id_field = "catalogueId"
27
+
28
+ id: int = 0
29
+ isPublic: bool = True
30
+ uuid: Optional[str] = None
31
+ controlId: Optional[str] = None
32
+ sortId: Optional[str] = None
33
+ title: Optional[str] = None
34
+ description: Optional[str] = None
35
+ controlType: Optional[str] = None
36
+ references: Optional[str] = None
37
+ relatedControls: Optional[str] = None
38
+ subControls: Optional[str] = None
39
+ enhancements: Optional[str] = None
40
+ family: Optional[str] = None
41
+ mappings: Optional[str] = None
42
+ assessmentPlan: Optional[str] = None
43
+ weight: float
44
+ catalogueId: int = Field(..., alias="catalogueID")
45
+ practiceLevel: Optional[str] = None
46
+ objectives: Optional[List[object]] = None
47
+ tests: Optional[List[object]] = None
48
+ parameters: Optional[List[object]] = None
49
+ archived: bool = False
50
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
51
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
52
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
53
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
54
+ criticality: Optional[str] = None
55
+
56
+ @staticmethod
57
+ def _get_additional_endpoints() -> ConfigDict:
58
+ """
59
+ Get additional endpoints for the SecurityControl
60
+
61
+ :return: Additional endpoints for the SecurityControl
62
+ :rtype: ConfigDict
63
+ """
64
+ return ConfigDict(
65
+ get_all_by_parent="/api/{model_slug}/getAllByCatalog/{intParentID}",
66
+ get_list="/api/{model_slug}/getList/{catalogId}",
67
+ )
68
+
69
+ def __hash__(self) -> hash:
70
+ """
71
+ Enable object to be hashable
72
+
73
+ :return: Hashed SecurityControl
74
+ :rtype: hash
75
+ """
76
+ return hash((self.controlId, self.catalogueId))
77
+
78
+ def __eq__(self, other: "SecurityControl") -> bool:
79
+ """
80
+ Update items in SecurityControl class
81
+
82
+ :param SecurityControl other: SecurityControl Object to compare to
83
+ :return: Whether the two objects are equal
84
+ :rtype: bool
85
+ """
86
+ return self.controlId == other.controlId and self.catalogueId == other.catalogueID
87
+
88
+ @classmethod
89
+ def get_list_by_catalog(cls, catalog_id: int) -> List["Catalog"]:
90
+ """
91
+ Get list of Security Controls for the provided Catalog ID
92
+
93
+ :param int catalog_id: Catalog ID
94
+ :return: list of catalogs
95
+ :rtype: List["Catalog"]
96
+ """
97
+ return cls._handle_list_response(
98
+ cls._get_api_handler().get(cls.get_endpoint("get_list").format(catalogId=catalog_id))
99
+ )
100
+
101
+ @staticmethod
102
+ def lookup_control(
103
+ app: Application,
104
+ control_id: int,
105
+ ) -> "SecurityControl":
106
+ """
107
+ Return a Security Control in RegScale via API
108
+
109
+ :param Application app: Application Instance
110
+ :param int control_id: ID of the Security Control to look up
111
+ :return: A Security Control from RegScale
112
+ :rtype: SecurityControl
113
+ """
114
+ api = Api()
115
+ control = api.get(url=app.config["domain"] + f"/api/securitycontrols/{control_id}").json()
116
+ return SecurityControl(**control)
117
+
118
+ @staticmethod
119
+ def lookup_control_by_name(app: Application, control_name: str, catalog_id: int) -> Optional["SecurityControl"]:
120
+ """
121
+ Lookup a Security Control by name and catalog ID
122
+
123
+ :param Application app: Application instance
124
+ :param str control_name: Name of the security control
125
+ :param int catalog_id: Catalog ID for the security control
126
+ :return: A Security Control from RegScale, if found
127
+ :rtype: Optional[SecurityControl]
128
+ """
129
+ api = Api()
130
+ config = api.config
131
+ res = api.get(config["domain"] + f"/api/securitycontrols/findByUniqueId/{control_name}/{catalog_id}")
132
+ return SecurityControl(**res.json()) if res.status_code == 200 else None