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,50 @@
1
+ """This module contains the Profile model."""
2
+
3
+ from typing import Optional
4
+
5
+ from pydantic import ConfigDict, Field
6
+
7
+ from regscale.core.app.utils.app_utils import get_current_datetime
8
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
9
+
10
+
11
+ class Profile(RegScaleModel):
12
+ """
13
+ Represents a security profile with various attributes.
14
+ """
15
+
16
+ _module_slug = "profiles"
17
+
18
+ id: Optional[int] = None
19
+ category: Optional[str] = None
20
+ name: Optional[str]
21
+ createdById: str = Field(default_factory=RegScaleModel.get_user_id)
22
+ dateCreated: str = Field(default_factory=get_current_datetime)
23
+ lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
24
+ dateLastUpdated: str = Field(default_factory=get_current_datetime)
25
+ profileOwnerId: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
26
+ tenantsId: Optional[int] = 1
27
+ uuid: Optional[str] = None
28
+ isPublic: Optional[bool] = True
29
+ availability: Optional[str] = None
30
+ confidentiality: Optional[str] = None
31
+ integrity: Optional[str] = None
32
+
33
+ @staticmethod
34
+ def _get_additional_endpoints() -> ConfigDict:
35
+ """
36
+ Get additional endpoints for the Profile model.
37
+
38
+ :return: A dictionary of additional endpoints
39
+ :rtype: ConfigDict
40
+ """
41
+ return ConfigDict(
42
+ get_list="/api/{model_slug}/getList",
43
+ get_list_with_controls="/api/{model_slug}/getListWithControls",
44
+ get_count="/api/{model_slug}/getCount",
45
+ graph="/api/{model_slug}/graph",
46
+ apply_profile="/api/{model_slug}/applyProfile/{moduleId}/{moduleName}/{profileId}/{isPublic}",
47
+ filter_profiles="/api/{model_slug}/filterProfiles",
48
+ query_by_custom_field="/api/{model_slug}/queryByCustomField/{strFieldName}/{strValue}",
49
+ find_by_name="/api/{model_slug}/findByName/{strName}/{intID}",
50
+ )
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for Profile Link in the application"""
4
+
5
+ from typing import Optional, List
6
+
7
+ from pydantic import ConfigDict, Field
8
+
9
+ from regscale.core.app.utils.app_utils import get_current_datetime
10
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
11
+
12
+
13
+ class ProfileLink(RegScaleModel):
14
+ """
15
+ Profile Mapping Model
16
+ """
17
+
18
+ _module_slug = "profileLinks"
19
+
20
+ id: int
21
+ profileId: int
22
+ linkDate: Optional[str] = Field(default_factory=get_current_datetime)
23
+ parentId: int
24
+ parentModule: Optional[str] = None
25
+ tenantsId: Optional[int] = None
26
+ createdById: Optional[str] = None
27
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
28
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
29
+ isPublic: bool = False
30
+ lastUpdatedById: Optional[str] = None
31
+
32
+ @staticmethod
33
+ def _get_additional_endpoints() -> ConfigDict:
34
+ """
35
+ Get additional endpoints for the ProfileMapping model, using {model_slug} as a placeholder for the model slug.
36
+
37
+ :return: A dictionary of additional endpoints
38
+ :rtype: ConfigDict
39
+ """
40
+
41
+ return ConfigDict( # type: ignore
42
+ get_all_by_parent="/api/{model_slug}/getProfiles/{strModule}/{intParentID}",
43
+ )
44
+
45
+ @classmethod
46
+ def get_all_by_parent(cls, parent_id: int, parent_module: str) -> List["ProfileLink"]:
47
+ """
48
+ Get a list of objects by parent.
49
+ # TODO: Update API to return needed data
50
+
51
+ :param int parent_id: The ID of the parent
52
+ :param str parent_module: The module of the parent
53
+ :return: A list of profile links
54
+ :rtype: List["ProfileLink]
55
+ """
56
+ response = cls._get_api_handler().get(
57
+ endpoint=cls.get_endpoint("get_all_by_parent").format(
58
+ intParentID=parent_id,
59
+ strModule=parent_module,
60
+ )
61
+ )
62
+ records = []
63
+ for obj in response.json():
64
+ obj["parentModule"] = parent_module
65
+ obj["parentId"] = parent_id
66
+ obj["profileId"] = obj["profile"]["id"]
67
+ records.append(cls(**obj))
68
+ return records
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for Profile Mapping in the application"""
4
+ from typing import List, Optional
5
+ from urllib.parse import urljoin
6
+
7
+ from pydantic import ConfigDict, Field
8
+
9
+ from regscale.core.app.api import Api
10
+ from regscale.core.app.application import Application
11
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
12
+ from regscale.models.regscale_models.security_control import SecurityControl
13
+
14
+
15
+ class ProfileMapping(RegScaleModel):
16
+ """
17
+ Profile Mapping Model
18
+ """
19
+
20
+ _module_slug = "profileMapping"
21
+
22
+ id: int = 0
23
+ profileID: int
24
+ controlID: int # the int id of the security control
25
+ controlId: Optional[str] = Field(alias="control_id", default=None) # the control id string i.e. AC-1
26
+ title: Optional[str] = None
27
+ family: Optional[str] = None
28
+ control: Optional[SecurityControl] = None
29
+ tenantsId: Optional[int] = None
30
+ createdById: Optional[str] = None
31
+ dateCreated: Optional[str] = None
32
+ dateLastUpdated: Optional[str] = None
33
+ isPublic: bool = True
34
+ lastUpdatedById: Optional[str] = None
35
+
36
+ @staticmethod
37
+ def _get_additional_endpoints() -> ConfigDict:
38
+ """
39
+ Get additional endpoints for the ProfileMapping model, using {model_slug} as a placeholder for the model slug.
40
+
41
+ :return: A dictionary of additional endpoints
42
+ :rtype: ConfigDict
43
+ """
44
+
45
+ return ConfigDict( # type: ignore
46
+ get_all_by_parent="/api/{model_slug}/getByProfile/{intParentID}",
47
+ lookup="/api/{model_slug}/lookup/{intProfileID}/{intControlID}",
48
+ get_by_profile="/api/{model_slug}/getByProfile/{intProfileID}",
49
+ oscal_prep="/api/{model_slug}/oscalPrep/{intProfileID}",
50
+ create_profile_mapping="/api/{model_slug}",
51
+ batch_create="/api/{model_slug}/batchCreate",
52
+ batch_delete="/api/{model_slug}/batchDelete",
53
+ delete_mapping="/api/{model_slug}/deleteMapping/{intProfileID}/{intControlID}",
54
+ )
55
+
56
+ @classmethod
57
+ def get_by_profile(cls, profile_id: int) -> List["ProfileMapping"]:
58
+ """
59
+ Get profile mappings by profile ID
60
+
61
+ :param int profile_id: Profile ID
62
+ :return: List of profile mappings
63
+ :rtype: List[ProfileMapping]
64
+ """
65
+ response = cls._get_api_handler().get(
66
+ endpoint=cls.get_endpoint("get_by_profile").format(intProfileID=profile_id)
67
+ )
68
+ mappings = []
69
+ if response and response.ok:
70
+ mappings = [cls(**map) for map in response.json()]
71
+ for mapping in mappings:
72
+ if control := SecurityControl.get_object(object_id=mapping.controlID):
73
+ mapping.control = control
74
+ return mappings
75
+
76
+ def insert_profile_mapping(self, app: Application) -> dict:
77
+ """
78
+ Insert a new profile mapping
79
+
80
+ :param Application app: Application
81
+ :raises Exception: API request failed
82
+ :return: dict of profile mapping
83
+ :rtype: dict
84
+ """
85
+ api = Api()
86
+ # Convert the model to a dictionary
87
+ data = self.dict()
88
+ api_url = urljoin(app.config["domain"], "/api/profileMapping")
89
+
90
+ # Make the API call
91
+ response = api.post(url=api_url, json=data)
92
+
93
+ # Check the response
94
+ if not response.ok:
95
+ api.logger.debug(
96
+ f"API Call failed to: {api_url}\n{response.status_code}: {response.reason} {response.text}"
97
+ )
98
+ raise response.raise_for_status()
99
+
100
+ return response.json()
101
+
102
+ @staticmethod
103
+ def insert_batch(app: Application, mappings: List["ProfileMapping"]) -> list[dict]:
104
+ """
105
+ Insert a new list of profile mappings as a batch
106
+
107
+ :param Application app: Application
108
+ :param List[ProfileMapping] mappings: List of profile mappings
109
+ :return: list[dict] of profile mappings
110
+ :rtype: list[dict]
111
+ """
112
+ api = Api()
113
+ # Convert the model to a dictionary
114
+
115
+ data = [item.dict() for item in mappings]
116
+ for d in data:
117
+ d["isPublic"] = "true"
118
+ api_url = urljoin(app.config["domain"], "/api/profileMapping/batchCreate")
119
+
120
+ # Make the API call
121
+ response = api.post(url=api_url, json=data)
122
+
123
+ # Check the response
124
+ return response.json() if response.ok else response.raise_for_status()
@@ -0,0 +1,63 @@
1
+ """Model for a RegScale Link"""
2
+
3
+ from typing import Optional
4
+
5
+ from pydantic import ConfigDict, Field
6
+
7
+ from regscale.core.app.utils.app_utils import get_current_datetime
8
+ from .regscale_model import RegScaleModel
9
+
10
+
11
+ class Project(RegScaleModel):
12
+ _module_slug = "projects"
13
+
14
+ title: Optional[str] = "" # Required
15
+ phase: Optional[str] = "" # Required
16
+ projectManagerId: Optional[str] = Field(default_factory=RegScaleModel.get_user_id) # Required
17
+ id: Optional[int] = 0
18
+ uuid: Optional[str] = ""
19
+ otherID: Optional[str] = ""
20
+ description: Optional[str] = ""
21
+ benefits: Optional[str] = ""
22
+ startDate: Optional[str] = Field(default_factory=get_current_datetime)
23
+ endDate: Optional[str] = ""
24
+ actualFinish: Optional[str] = ""
25
+ percentComplete: Optional[int] = 0
26
+ budget: Optional[float] = 0.0
27
+ actualCosts: Optional[float] = 0.0
28
+ legislativeMandate: Optional[bool] = True
29
+ auditFinding: Optional[bool] = True
30
+ strategicPlan: Optional[bool] = True
31
+ costSavings: Optional[bool] = True
32
+ newRequirement: Optional[bool] = True
33
+ riskReduction: Optional[bool] = True
34
+ revenue: Optional[bool] = True
35
+ facilityId: Optional[int] = 0
36
+ orgId: Optional[int] = 0
37
+ parentId: Optional[int] = 0
38
+ parentModule: Optional[str] = ""
39
+ isPublic: Optional[bool] = True
40
+
41
+ @staticmethod
42
+ def _get_additional_endpoints() -> ConfigDict:
43
+ """
44
+ Get additional endpoints for the Links model.
45
+
46
+ :return: A dictionary of additional endpoints
47
+ :rtype: ConfigDict
48
+ """
49
+ return ConfigDict(
50
+ get_list="/api/{model_slug}/getList",
51
+ calendar_projects="/api/{model_slug}/calendarProjects/{dtDate}/{fId}/{orgId}/{userId}",
52
+ gantt_chart="/api/{model_slug}/ganttChart/{intId}",
53
+ status_board="/api/{model_slug}/statusboard/{strSearch}/{strPhase}/{strOwner}/{intPage}/{pageSize}",
54
+ graph="/api/{model_slug}/graph",
55
+ graph_by_date="/api/{model_slug}/graphByDate/{strGroupBy}/{year}",
56
+ filter_projects="/api/{model_slug}/filterProjects",
57
+ query_by_custom_field="/api/{model_slug}/queryByCustomField/{strFieldName}/{strValue}",
58
+ report="/api/{model_slug}/report/{strReport}",
59
+ schedule="/api/{model_slug}/schedule/{year}/{dvar}",
60
+ dashboard="/api/{model_slug}/dashboard/{strGroupBy}",
61
+ main_dashboard="/api/{model_slug}/mainDashboard/{intYear}",
62
+ main_dashboard_chart="/api/{model_slug}/mainDashboardChart/{year}",
63
+ )
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Create Properties model."""
4
+ import json
5
+ import logging
6
+ import math
7
+ from typing import Any, List, Optional, Union
8
+
9
+ from pydantic import ConfigDict, Field, field_validator
10
+
11
+ from regscale.core.app.api import Api
12
+ from regscale.core.app.application import Application
13
+ from regscale.core.app.internal.model_editor import get_all_by_parent
14
+ from regscale.core.app.utils.app_utils import get_current_datetime, recursive_items
15
+ from regscale.models.regscale_models.regscale_model import RegScaleModel
16
+ from regscale.utils import flatten_dict
17
+
18
+ logger = logging.getLogger("regscale")
19
+
20
+
21
+ class Property(RegScaleModel):
22
+ """Properties plan model"""
23
+
24
+ _module_slug = "properties"
25
+ _unique_fields = [
26
+ ["key", "parentId", "parentModule"],
27
+ ]
28
+ _parent_id_field = "parentId"
29
+
30
+ id: int = 0
31
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
32
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
33
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
34
+ isPublic: bool = True
35
+ key: Optional[str] = ""
36
+ value: Optional[Union[str, int, float]] = ""
37
+ label: Optional[str] = ""
38
+ otherAttributes: Optional[str] = ""
39
+ parentId: Optional[int] = 0
40
+ parentModule: Optional[str] = ""
41
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
42
+ alt_id: Optional[str] = None
43
+
44
+ @field_validator("value", mode="before")
45
+ def validate_value(cls, value: Any) -> Any:
46
+ """
47
+ Validate the value field and convert it to a string if it is a boolean or list
48
+
49
+ :param Any value: Value to validate
50
+ :return: Value if valid
51
+ :rtype: Any
52
+ """
53
+ import math
54
+
55
+ if isinstance(value, bool):
56
+ return "True" if value else "False"
57
+ if isinstance(value, list):
58
+ return ", ".join(value)
59
+ if isinstance(value, float) and math.isnan(value):
60
+ return "NULL"
61
+ if isinstance(value, str) and value.strip() == "":
62
+ return "NULL"
63
+ if isinstance(value, dict):
64
+ return json.dumps(value)
65
+ return value or "NULL"
66
+
67
+ @staticmethod
68
+ def _get_additional_endpoints() -> ConfigDict:
69
+ """
70
+ Get additional endpoints for the Properties model.
71
+
72
+ :return: A dictionary of additional endpoints
73
+ :rtype: ConfigDict
74
+ """
75
+ return ConfigDict( # type: ignore
76
+ batch_create="/api/{model_slug}/batchCreate",
77
+ batch_update="/api/{model_slug}/batchUpdate",
78
+ get_all_by_parent="/api/{model_slug}/getAllByParent/{intParentID}/{strModule}",
79
+ )
80
+
81
+ @staticmethod
82
+ def create_properties_from_list(
83
+ parent_id: Union[str, int],
84
+ parent_module: str,
85
+ properties_list: List[dict],
86
+ ) -> List["Property"]:
87
+ """
88
+ Create a list of Properties objects from a list of dicts
89
+
90
+ :param Union[str, int] parent_id: ID of the SSP to create the Properties objects for
91
+ :param str parent_module: Parent module of the Properties objects
92
+ :param Union[str, int] properties_list: List of dicts to create objects from
93
+ :return: List[dict] of Properties objects
94
+ :rtype: List[Property]
95
+ """
96
+ properties = [
97
+ Property(parentId=int(parent_id), parentModule=parent_module, **properties)
98
+ for properties in properties_list
99
+ ]
100
+ return [property_.create_new_properties(return_object=True) for property_ in properties]
101
+
102
+ def create_new_properties(self, return_object: Optional[bool] = False) -> Union[bool, "Property"]:
103
+ """
104
+ Create a new Properties object in RegScale
105
+
106
+ :param Optional[bool] return_object: Whether to return the object if successful
107
+ , defaults to False
108
+ :return: True or the Properties created if successful, False otherwise
109
+ :rtype: Union[bool, Property]
110
+ """
111
+ api = Api()
112
+ data = self.dict()
113
+ data["id"] = None
114
+ data["createdById"] = api.config["userId"]
115
+ data["lastUpdatedById"] = api.config["userId"]
116
+ properties_response = api.post(
117
+ f'{api.config["domain"]}/api/properties/',
118
+ json=data,
119
+ )
120
+ if properties_response.ok:
121
+ logger.info("Created Properties: %s", properties_response.json()["id"])
122
+ if return_object:
123
+ return Property(**properties_response.json())
124
+ return True
125
+ logger.error("Error creating Properties: %s", properties_response.text)
126
+ return False
127
+
128
+ def __eq__(self, other: "Property") -> bool:
129
+ """
130
+ Test equality of two Property objects
131
+
132
+ :param Property other: Other Property object to compare to
133
+ :return: Equality of two Property objects
134
+ :rtype: bool
135
+ """
136
+ return (
137
+ self.key == other.key
138
+ and self.value == other.value
139
+ and self.parentId == other.parentId
140
+ and self.parentModule == other.parentModule
141
+ )
142
+
143
+ @staticmethod
144
+ def generate_property_list_from_dict(dat: dict) -> list["Property"]:
145
+ """
146
+ Generate Property List from Dict
147
+
148
+ :param dict dat: Data to generate Property list from
149
+ :return: List of Properties
150
+ :rtype: list["Property"]
151
+ """
152
+ kvs = recursive_items(dat)
153
+ return [Property(key=k, value=v, createdById="", parentModule="") for k, v in kvs]
154
+
155
+ @staticmethod
156
+ def update_properties(app: Application, prop_list: list["Property"]) -> None:
157
+ """
158
+ Post a list of properties to RegScale
159
+
160
+ :param Application app: Application object
161
+ :param list[Property] prop_list: List of properties to post to RegScale
162
+ :rtype: None
163
+ """
164
+ api = Api()
165
+ props = [prop.dict() for prop in prop_list]
166
+ res = api.put(
167
+ url=app.config["domain"] + "/api/properties/batchupdate",
168
+ json=props,
169
+ )
170
+ if res.status_code == 200:
171
+ if len(prop_list) > 0:
172
+ logger.info("Successfully updated %i properties to RegScale", len(prop_list))
173
+ else:
174
+ logger.error("Failed to update properties to RegScale\n%s", res.text)
175
+
176
+ @staticmethod
177
+ def existing_properties(app: Application, existing_assets: list[dict]) -> list["Property"]:
178
+ """
179
+ Return a list of existing properties in RegScale
180
+
181
+ :param Application app: Application object
182
+ :param list[dict] existing_assets: List of assets from RegScale
183
+ :return: List of properties for the provided assets
184
+ :rtype: list["Property"]
185
+ """
186
+ properties = []
187
+ api = Api()
188
+ for asset in existing_assets:
189
+ res = api.get(url=app.config["domain"] + f"/api/properties/getAllByParent/{asset['id']}/assets")
190
+ if res.status_code == 200:
191
+ for prop in res.json():
192
+ prop["alt_id"] = asset["wizId"]
193
+ properties.append(Property(**prop))
194
+ return properties
195
+
196
+ @staticmethod
197
+ def insert_properties(app: Application, prop_list: list["Property"]) -> list["Property"]:
198
+ """
199
+ Post a list of properties to RegScale
200
+
201
+ :param Application app: Application instance
202
+ :param list[Property] prop_list: List of properties to post
203
+ :return: List of created properties in RegScale
204
+ :rtype: list["Property"]
205
+ """
206
+ properties = []
207
+ api = Api()
208
+ res = api.post(
209
+ url=app.config["domain"] + "/api/properties/batchcreate",
210
+ json=[prop.dict() for prop in prop_list],
211
+ )
212
+ if res.status_code == 200:
213
+ if len(prop_list) > 0:
214
+ api.logger.info("Successfully posted %i properties to RegScale", len(prop_list))
215
+ properties = [Property(**prop) for prop in res.json()]
216
+ else:
217
+ logger.error("Failed to post properties to RegScale\n%s", res.text)
218
+ return properties
219
+
220
+ @staticmethod
221
+ def get_properties(wiz_data: str, wiz_id: str) -> List["Property"]:
222
+ """
223
+ Convert Wiz properties data into a list of Property objects.
224
+
225
+ :param str wiz_data: JSON string containing Wiz information
226
+ :param str wiz_id: Identifier for a Wiz issue
227
+ :return: A list of Property objects derived from Wiz data
228
+ :rtype: List[Property]
229
+ """
230
+ app = Application()
231
+ wiz_dict = json.loads(wiz_data)
232
+ flattened = flatten_dict(wiz_dict)
233
+ properties = []
234
+
235
+ current_datetime = get_current_datetime()
236
+ user_id = app.config["userId"]
237
+
238
+ for key, value in flattened:
239
+ # Skip empty values or empty dictionaries converted to strings
240
+ if not value or value == "{}":
241
+ continue
242
+ value = _value_checks(value)
243
+ # Create and add Property object if there's a meaningful value
244
+ if value:
245
+ prop = Property(
246
+ createdById=user_id,
247
+ dateCreated=current_datetime,
248
+ lastUpdatedById=user_id,
249
+ isPublic=True,
250
+ alt_id=wiz_id,
251
+ key=key,
252
+ value=value,
253
+ parentId=0,
254
+ parentModule="assets",
255
+ dateLastUpdated=current_datetime,
256
+ )
257
+ properties.append(prop)
258
+
259
+ return properties
260
+
261
+
262
+ def _value_checks(value: Any) -> Any:
263
+ """
264
+ Check if the value is a boolean or list and convert it to a string if needed
265
+ :param Any value: Value to check
266
+ :return: Converted value
267
+ :rtype: Any
268
+ """
269
+ # Simplify handling of list and dict values
270
+ if isinstance(value, list):
271
+ value = value[0] if value else None # Get first item of the list if not empty
272
+ if isinstance(value, dict):
273
+ value = next((v for _, v in flatten_dict(value)), None)
274
+
275
+ # Replace NaN values with an empty string
276
+ if isinstance(value, (int, float)) and math.isnan(value):
277
+ value = ""
278
+ return value
@@ -0,0 +1,85 @@
1
+ """
2
+ This module contains the Questions model for RegScale.
3
+ """
4
+
5
+ from enum import Enum
6
+ from typing import Optional, List, Dict
7
+ from pydantic import ConfigDict, Field
8
+ from regscale.core.app.utils.app_utils import get_current_datetime
9
+ from .regscale_model import RegScaleModel
10
+
11
+
12
+ class QuestionType(str, Enum):
13
+ """
14
+ Enum for the QuestionType field in the Questions model.
15
+ """
16
+
17
+ ShortAnswer = 0
18
+ LongAnswer = 1
19
+ Instructional = 2
20
+ Date = 3
21
+ PhoneNumber = 4
22
+ Email = 5
23
+ DigitalSignature = 6
24
+ MultipleChoice = 10
25
+ CheckBoxes = 20
26
+ Dropdown = 30
27
+ FileAccess = 50
28
+
29
+
30
+ class AnswerOptions(RegScaleModel):
31
+ answerOption: Optional[str]
32
+ answerScore: Optional[int] = 0
33
+
34
+
35
+ class Questions(RegScaleModel):
36
+ """
37
+ A class to represent the Questions model in RegScale.
38
+ """
39
+
40
+ _module_slug = "questions"
41
+
42
+ id: Optional[int] = None
43
+ parentQuestionnaireId: int = 0
44
+ uuid: Optional[str] = None
45
+ questionType: int = 0
46
+ name: Optional[str] = None
47
+ label: Optional[str] = None
48
+ prompt: Optional[str] = None
49
+ tenantsId: Optional[int] = 1
50
+ createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
51
+ dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
52
+ dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
53
+ isPublic: bool = True
54
+ lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
55
+ controlNumber: Optional[str] = None
56
+ section: int = 0
57
+ staticAnswerOptions: Optional[List[Dict]] = None # Adjust the type if it's not a string
58
+ askQuestion: bool = True
59
+ quid: Optional[str] = None
60
+ required: bool = True
61
+ sectionIndex: int = 1
62
+ uploadEnabled: bool = False
63
+ response: Optional[str] = None # Adjust the type if it's not a string
64
+
65
+ @staticmethod
66
+ def _get_additional_endpoints() -> ConfigDict:
67
+ """
68
+ Get endpoints for the Question model.
69
+
70
+ :return: A dictionary of endpoints
71
+ :rtype: ConfigDict
72
+ """
73
+ return ConfigDict(
74
+ get_all_by_parent_get="/api/{model_slug}/getAllByParent",
75
+ get="/api/{model_slug}/find/{id}",
76
+ insert="/api/{model_slug}/create",
77
+ update="/api/{model_slug}/update",
78
+ delete="/api/{model_slug}/delete/{id}",
79
+ get_new_section_index_post="/api/{model_slug}/getNewSectionIndex",
80
+ update_origin_section_put="/api/{model_slug}/updateOriginSection",
81
+ section_update_from_insert_put="/api/{model_slug}/sectionUpdateFromInsert",
82
+ section_update_from_cancel_put="/api/{model_slug}/sectionUpdateFromCancel",
83
+ index_up_put="/api/{model_slug}/indexUp",
84
+ index_down_put="/api/{model_slug}/indexDown",
85
+ )