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,582 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """standard python imports"""
4
+
5
+ import logging
6
+ from concurrent.futures import ThreadPoolExecutor, as_completed
7
+ from json import JSONDecodeError
8
+ from typing import Any, List
9
+
10
+ import requests
11
+ from lxml.etree import Element
12
+ from packaging.version import Version
13
+
14
+ from regscale.core.app.application import Application
15
+ from regscale.core.app.utils.app_utils import get_current_datetime
16
+ from regscale.integrations.public.fedramp.fedramp_traversal import FedrampTraversal
17
+ from regscale.models.regscale_models.control_implementation import ControlImplementation
18
+ from regscale.models.regscale_models.implementation_objective import ImplementationObjective
19
+ from regscale.models.regscale_models.implementation_option import ImplementationOptionDeprecated
20
+ from regscale.models.regscale_models.security_plan import SecurityPlan
21
+ from regscale.utils.version import RegscaleVersion
22
+
23
+ logger = logging.getLogger("regscale")
24
+
25
+ FULLY_IMPLEMENTED = "Fully Implemented"
26
+ NOT_IMPLEMENTED = "Not Implemented"
27
+
28
+
29
+ def get_parts_list(ele: Any) -> list[dict]:
30
+ """
31
+ Get the parts list
32
+
33
+ :param Any ele: The element
34
+ :return: A list of parts
35
+ :rtype: list[dict]
36
+ """
37
+ oscal_component = ".//oscal:by-component"
38
+ parts_list = []
39
+ nsmap = {"oscal": "http://csrc.nist.gov/ns/oscal/1.0"}
40
+ statements = ele.xpath("//*[contains(@statement-id, 'smt')]", namespaces=nsmap)
41
+ parameters = ele.xpath("//*[contains(@param-id, 'prm') or contains(@param-id, 'odp')]", namespaces=nsmap)
42
+ objectives = ele.xpath("//*[contains(@statement-id, 'obj')]", namespaces=nsmap)
43
+
44
+ for statement in statements:
45
+ parts = {}
46
+ component_uuid = statement.xpath(oscal_component, namespaces=nsmap)[0].attrib["component-uuid"]
47
+ parts["part_id"] = statement.attrib["statement-id"]
48
+ parts["uuid"] = statement.attrib["uuid"]
49
+ if component_uuid:
50
+ parts["component_uuid"] = component_uuid
51
+ p_texts = statement.xpath(
52
+ ".//oscal:by-component/oscal:description/oscal:p/text()",
53
+ namespaces=nsmap,
54
+ )
55
+ parts["text"] = p_texts
56
+ if statement.attrib["statement-id"] not in {part["part_id"] for part in parts_list}:
57
+ parts_list.append(parts)
58
+
59
+ for objective in objectives:
60
+ parts = {}
61
+ parts["part_id"] = objective.attrib["statement-id"]
62
+ comp = objective.xpath(oscal_component, namespaces=nsmap)
63
+ if comp:
64
+ component_uuid = comp[0].attrib["component-uuid"]
65
+ b_texts = objective.xpath(
66
+ ".//oscal:by-component/oscal:description/oscal:p/text()",
67
+ namespaces=nsmap,
68
+ )
69
+ parts["text"] = b_texts
70
+ if component_uuid:
71
+ parts["component_uuid"] = component_uuid
72
+ if objective.attrib["statement-id"] not in {part["part_id"] for part in parts_list}:
73
+ parts_list.append(parts)
74
+
75
+ for parameter in parameters:
76
+ parts = {}
77
+ parts["part_id"] = parameter.attrib["param-id"]
78
+ comp = parameter.xpath(oscal_component, namespaces=nsmap)
79
+ if comp:
80
+ component_uuid = comp[0].attrib["component-uuid"]
81
+ b_texts = parameter.xpath(
82
+ ".//oscal:set-parameter/value/text()",
83
+ namespaces=nsmap,
84
+ )
85
+ b_texts = parameter.xpath(
86
+ ".//oscal:value/text()",
87
+ namespaces=nsmap,
88
+ )
89
+ if b_texts:
90
+ parts["text"] = b_texts.pop()
91
+ if component_uuid:
92
+ parts["component_uuid"] = component_uuid
93
+ if parameter.attrib["param-id"] not in {part["part_id"] for part in parts_list}:
94
+ parts_list.append(parts)
95
+ return parts_list
96
+
97
+
98
+ def get_maps() -> tuple:
99
+ """
100
+ Get the status and responsibility maps
101
+
102
+ :return: A tuple of status and responsibility maps
103
+ :rtype: tuple
104
+ """
105
+ status_map = {
106
+ FULLY_IMPLEMENTED: "Implemented",
107
+ "Partially Implemented": "Partially Implemented",
108
+ "Not Applicable": "Not Applicable",
109
+ NOT_IMPLEMENTED: NOT_IMPLEMENTED,
110
+ "Planned": "Planned",
111
+ }
112
+ responsibility_map = {
113
+ "Provider": "Service Provider Corporate",
114
+ "Provider (System Specific)": "Service Provider System Specific",
115
+ "Customer": "Provided by Customer (Customer System Specific)",
116
+ "Hybrid": "Service Provider Hybrid (Corporate and System Specific)",
117
+ "Customer Configured": "Configured by Customer (Customer System Specific)",
118
+ "Shared": "Shared (Service Provider and Customer Responsibility)",
119
+ "Inherited": "Inherited from pre-existing FedRAMP Authorization",
120
+ }
121
+
122
+ return status_map, responsibility_map
123
+
124
+
125
+ def fetch_implementations(trv: FedrampTraversal, root: Element, ssp: SecurityPlan) -> list:
126
+ """
127
+ Fetch the control implementations for the provided SSP in RegScale
128
+
129
+ :param FedrampTraversal trv: FedrampTraversal instance
130
+ :param Element root: The root element of the OSCAL document
131
+ :param SecurityPlan ssp: RegScale security plan object
132
+ :return: List of control implementations
133
+ :rtype: list
134
+ """
135
+ app = trv.api.app
136
+ api = trv.api
137
+ # Compliance settings groups are too inconsistent to auto map, so we need to manually map them
138
+ status_map, responsibility_map = get_maps()
139
+ ns = {"ns1": "http://csrc.nist.gov/ns/oscal/1.0"}
140
+ parts = []
141
+ imps = []
142
+ reqs = root.xpath("//ns1:implemented-requirement", namespaces=ns)
143
+ ssp.parentId = trv.catalogue_id
144
+ ssp.parentModule = "catalogues"
145
+ cat_id = ssp.parentId
146
+ detail = {}
147
+ trv.log_info(
148
+ {
149
+ "model_layer": "System Control Implementation",
150
+ "record_type": "Control Implementation",
151
+ "event_msg": "Pulling Catalog details.",
152
+ }
153
+ )
154
+
155
+ detail_res = api.get(url=app.config["domain"] + f"/api/catalogues/getCatalogWithAllDetails/{cat_id}")
156
+ if detail_res.ok:
157
+ try:
158
+ detail = detail_res.json()
159
+ except JSONDecodeError as jex:
160
+ logger.error(jex)
161
+ return
162
+ control_objectives = detail["objectives"] if "objectives" in detail else []
163
+ options = detail["options"] if "options" in detail else []
164
+ existing_parameters = detail["parameters"] if "parameters" in detail else []
165
+ existing_controls = detail["controls"] if "controls" in detail else []
166
+ # Build options if they do not exist
167
+ updated_options = build_options(app=app, existing_options=options, control_objectives=control_objectives)
168
+ options.extend(updated_options)
169
+
170
+ new_options = post_options(trv, updated_options)
171
+ options.extend(new_options)
172
+ # TODO: Pull the options for just the control objectives we are working with.
173
+ # Get Parts data, mapped to a compoment id.
174
+ uuid = ""
175
+ for req in reqs:
176
+ for name, value in req.attrib.items():
177
+ if name == "uuid":
178
+ uuid = value
179
+ if name == "control-id":
180
+ logger.debug(f"Property: {name}, Value: {value}")
181
+ if ssp.parentModule == "catalogues":
182
+ logger.info("Building implementation: %s", value)
183
+
184
+ # This try catch is tied to modification to catalogs object returned by above API call
185
+ # The otherId field is to be added to new OSCAL catalogs which will be migrated for existing customers.
186
+ # If otherId exists use it to match to control otherwise use original controlId
187
+ # Handle case where otherId does not exist in catalog object and do not throw an error
188
+ # if otherid exists in catalog object make sure it has something in it before matching
189
+ # this case may exist while new catalogs are being migrated to for customers
190
+ matching_controls = [
191
+ control for control in existing_controls if control.get("otherId", "") == value
192
+ ]
193
+ if not matching_controls:
194
+ matching_controls = [
195
+ control for control in existing_controls if control.get("controlId", "") == value
196
+ ]
197
+
198
+ control = matching_controls[0] if matching_controls else None
199
+
200
+ if control is None:
201
+ trv.log_error(
202
+ {
203
+ "record_type": "System Control Implementation",
204
+ "event_msg": f"Failed to locate control {value} in the selected profile.",
205
+ "missing_element": f"Control {value}",
206
+ "model_layer": "System Control Implementation",
207
+ }
208
+ )
209
+ logger.warning("Unable to find a control, do you have a catalog?")
210
+ break
211
+
212
+ implementation = ControlImplementation.from_oscal_element(app=app, obj=req, control=control)
213
+ implementation.parentId = ssp.id
214
+ implementation.uuid = uuid
215
+ implementation.parentModule = "securityplans"
216
+
217
+ implementation.controlOwnerId = app.config["userId"]
218
+
219
+ # do a version check to use new compliance settings
220
+ regscale_version = RegscaleVersion.get_platform_version()
221
+ if len(regscale_version) >= 10 or Version(regscale_version) >= Version("6.13.0.0"):
222
+ implementation.status = status_map.get(implementation.status.value)
223
+ implementation.responsibility = responsibility_map.get(implementation.responsibility.value)
224
+ imps.append(implementation)
225
+ if control is None:
226
+ logger.error("Unable to locate the control in RegScale.")
227
+
228
+ parts.extend(get_parts_list(req))
229
+
230
+ logger.info("Loading control implementations to RegScale")
231
+ num_successful_post = 0
232
+ num_failed_post = 0
233
+ with ThreadPoolExecutor(max_workers=10) as executor:
234
+ post_futures = {
235
+ executor.submit(ControlImplementation.post_implementation, app=app, implementation=imp): imp for imp in imps
236
+ }
237
+
238
+ for future in as_completed(post_futures):
239
+ imp = post_futures[future]
240
+ try:
241
+ data = future.result()
242
+ if data is not None:
243
+ num_successful_post += 1
244
+ except Exception as ex:
245
+ logger.warning(f"An error occurred while posting implementation {imp}: {ex}")
246
+ num_failed_post += 1
247
+ else:
248
+ logger.info(f"Finished posting Implementation {num_successful_post} to RegScale")
249
+
250
+ trv.log_info(
251
+ {
252
+ "model_layer": "System Control Implementation",
253
+ "record_type": "Control Implementation",
254
+ "event_msg": f"Finished loading {num_successful_post} Control Implementations (Failed: {num_failed_post})",
255
+ }
256
+ )
257
+
258
+ logger.info("Processing Control Parts...")
259
+ imps = ControlImplementation.fetch_existing_implementations(
260
+ app=app, regscale_parent_id=ssp.id, regscale_module="securityplans"
261
+ )
262
+
263
+ process_parts(
264
+ trv,
265
+ control_objectives,
266
+ existing_parameters,
267
+ parts,
268
+ imps,
269
+ options,
270
+ )
271
+
272
+ # Update implementation options with implementation objectives.
273
+ return imps
274
+
275
+
276
+ def process_parts(
277
+ trv: FedrampTraversal,
278
+ control_objectives: List[dict],
279
+ existing_parameters: List[dict],
280
+ parts: List[dict],
281
+ imps: List[dict],
282
+ single_system: bool = True,
283
+ ):
284
+ """
285
+ Process parts of the implementation
286
+
287
+ :param FedrampTraversal trv: FedrampTraversal instance
288
+ :param List[dict] control_objectives: A list of control objectives
289
+ :param List[dict] existing_parameters: A list of existing parameters
290
+ :param List[dict] parts: A list of parts
291
+ :param List[dict] imps: A list of implementations
292
+ :param bool single_system: A flag to indicate if the system is a single system, defaults to True
293
+ """
294
+ app = trv.api.app
295
+ api = trv.api
296
+ config = app.config
297
+ implementation_objectives = []
298
+ all_params = []
299
+
300
+ for imp in imps:
301
+ status = imp["status"]
302
+ imp_id = imp["id"]
303
+
304
+ logger.info(f"Loading parts for {imp['controlName']}...")
305
+
306
+ part_notes = [
307
+ part
308
+ for part in parts
309
+ if "smt" in part["part_id"]
310
+ and imp["controlName"] == part["part_id"].split("_")[0]
311
+ and "_smt" in part["part_id"]
312
+ ]
313
+
314
+ params = [
315
+ part
316
+ for part in parts
317
+ if (
318
+ ("prm" in part["part_id"] and imp["controlName"] == part["part_id"].split("_prm")[0])
319
+ or (
320
+ "odp" in part["part_id"]
321
+ and imp["controlName"] == part["part_id"].replace("-0", "-").split("_odp")[0]
322
+ )
323
+ )
324
+ ]
325
+ parameters = [dict(t) for t in set(tuple(d.items()) for d in params)]
326
+
327
+ # Just load statement parts _smt parts
328
+ for part in part_notes:
329
+ prefix = part["part_id"].split("_")[0]
330
+ control_objectives_items = {
331
+ obj["name"]: obj
332
+ for obj in control_objectives
333
+ if obj["name"].startswith(f"{prefix}_smt") or "_fr_smt" in obj["name"]
334
+ }
335
+
336
+ c_objective = control_objectives_items.get(part.get("part_id"))
337
+ if c_objective is None:
338
+ continue
339
+ cntrl_objectives = [obj for obj in control_objectives if obj["name"] == part["part_id"]]
340
+ status_map, _ = get_maps()
341
+ regscale_version = RegscaleVersion.get_platform_version()
342
+ if len(regscale_version) >= 10 or Version(regscale_version) >= Version("6.13.0.0"):
343
+ status = status_map.get(status)
344
+
345
+ if cntrl_objectives:
346
+ imp_objective = ImplementationObjective(
347
+ notes=part["part_id"],
348
+ status=status,
349
+ implementationId=imp_id,
350
+ # optionId=option["id"],
351
+ securityControlId=imp["controlID"],
352
+ objectiveId=c_objective["id"], # controlObjective['id]
353
+ id=0,
354
+ uuid=part["uuid"],
355
+ createdById=config["userId"],
356
+ statement=part["text"].pop() if part["text"] else "",
357
+ # TODO: Find and update these data fields.
358
+ authorizationId=None,
359
+ responsibility=None,
360
+ cloudResponsibility=None,
361
+ customerResponsibility=None,
362
+ )
363
+
364
+ if imp_objective not in implementation_objectives:
365
+ implementation_objectives.append(imp_objective)
366
+
367
+ params = update_parameters(trv, existing_parameters, parameters, imp)
368
+ all_params.extend(params)
369
+ post_params(trv, all_params)
370
+
371
+ trv.log_info(
372
+ {
373
+ "model_layer": "System Control Implementation",
374
+ "record_type": "Implementation Objective",
375
+ "event_msg": f"Finished loading {len(implementation_objectives)} Implementation Objectives",
376
+ }
377
+ )
378
+
379
+ def post_objective(obj: ImplementationObjective) -> requests.Response:
380
+ """
381
+ Post an objective to RegScale
382
+
383
+ :param ImplementationObjective obj: An implementation objective
384
+ :return: A response
385
+ :rtype: requests.Response
386
+ """
387
+ url = config["domain"] + "/api/implementationObjectives"
388
+ return api.post(url=url, json=obj.__dict__)
389
+
390
+ num_impl_success = 0
391
+ num_impl_failed = 0
392
+ for obj in implementation_objectives:
393
+ response = post_objective(obj)
394
+ if not response:
395
+ num_impl_failed += 1
396
+ else:
397
+ num_impl_success += 1
398
+
399
+ trv.log_info(
400
+ {
401
+ "model_layer": "System Control Implementation",
402
+ "record_type": "Implementation Objective",
403
+ "event_msg": f"Finished posting {num_impl_success} Implementation Objectives (Failed: {num_impl_failed})",
404
+ }
405
+ )
406
+
407
+
408
+ def post_params(trv: FedrampTraversal, params: List[dict]):
409
+ """
410
+ Post Parameters to RegScale
411
+
412
+ :param FedrampTraversal trv: FedrampTraversal instance
413
+ :param List[dict] params: A list of parameters to post
414
+ """
415
+
416
+ def post_parameter(param: dict) -> requests.Response:
417
+ """
418
+ Post a parameter to RegScale
419
+
420
+ :param dict param: A parameter
421
+ :return: A response
422
+ :rtype: requests.Response
423
+ """
424
+ url = trv.api.app.config["domain"] + "/api/parameters"
425
+ return trv.api.post(url=url, json=param)
426
+
427
+ logger.info("Posting %i Parameters to RegScale", len(params))
428
+ num_params_success = 0
429
+ num_params_failed = 0
430
+ with ThreadPoolExecutor(max_workers=10) as executor: # Increase the number of workers
431
+ post_futures = {executor.submit(post_parameter, param): param for param in params}
432
+
433
+ for future in as_completed(post_futures):
434
+ param = post_futures[future]
435
+ try:
436
+ data = future.result()
437
+ if data is not None:
438
+ num_params_success += 1
439
+ except Exception as ex:
440
+ logger.debug(f"An error occurred while posting parameter {param}: {ex}")
441
+ num_params_failed += 1
442
+
443
+ trv.log_info(
444
+ {
445
+ "model_layer": "System Control Implementation",
446
+ "record_type": "Parameters",
447
+ "event_msg": f"Finished posting {num_params_success} Parameters (Failed: {num_params_failed})",
448
+ }
449
+ )
450
+
451
+
452
+ def update_parameters(
453
+ trv: FedrampTraversal, existing_parameters: List[dict], parameters: List[dict], imp: dict
454
+ ) -> list[dict]:
455
+ """
456
+ Update parameters
457
+
458
+ :param FedrampTraversal trv: FedrampTraversal instance
459
+ :param List[dict] existing_parameters: A list of existing parameters
460
+ :param List[dict] parameters: A list of parameters
461
+ :param dict imp: An implementation object
462
+ :return: A list of updated parameters
463
+ :rtype: list[dict]
464
+ """
465
+ app = trv.api.app
466
+ new_params = []
467
+
468
+ for param in parameters:
469
+ dat = [
470
+ par
471
+ for par in existing_parameters
472
+ if par["parameterId"] == param["part_id"] and par["securityControlId"] == imp["controlID"]
473
+ ]
474
+ if dat:
475
+ param["default"] = dat[0]["text"]
476
+ new_param = {
477
+ "id": 0,
478
+ "uuid": "",
479
+ "name": param["part_id"],
480
+ "value": param["text"],
481
+ "controlImplementationId": imp["id"],
482
+ "createdById": app.config["userId"],
483
+ "lastUpdatedById": app.config["userId"],
484
+ }
485
+ new_params.append(new_param)
486
+ return new_params
487
+
488
+
489
+ def get_control_objectives(control_id: int, existing_objectives: List[dict]) -> List[dict]:
490
+ """
491
+ Return control objectives for a given control ID
492
+
493
+ :param int control_id: id to fetch objectives for
494
+ :param List[dict] existing_objectives: A list of existing objectives
495
+ :return: A list of control objectives
496
+ :rtype: List[dict]
497
+ """
498
+ return [obj for obj in existing_objectives if obj["securityControlId"] == control_id]
499
+
500
+
501
+ def post_options(trv: FedrampTraversal, options: list[ImplementationOptionDeprecated]) -> list[dict]:
502
+ """
503
+ Post Implementation Option to RegScale
504
+
505
+ :param FedrampTraversal trv: FedrampTraversal object
506
+ :param list[ImplementationOptionDeprecated] options: A list of Implementation Options
507
+ :return: A list of responses
508
+ :rtype: list[dict]
509
+ """
510
+ api = trv.api
511
+ res = []
512
+ num_options_success = 0
513
+ num_options_failed = 0
514
+ num_duplicates = 0
515
+ with ThreadPoolExecutor(max_workers=10) as executor: # Increase the number of workers
516
+ post_futures = {executor.submit(dt.insert, api): dt for dt in options}
517
+
518
+ for future in as_completed(post_futures):
519
+ dt = post_futures[future]
520
+ try:
521
+ response = future.result()
522
+ if not response.raise_for_status():
523
+ res.append(response.json())
524
+ logger.debug(
525
+ "Created a New Implementation Option: #%i",
526
+ response.json()["id"],
527
+ )
528
+ num_options_success += 1
529
+ except Exception as ex:
530
+ # rev 5 contains multiple parts for each control with implemention options
531
+ # there will be duplicates (which is ok)
532
+ # do not log a message but count them.
533
+ if response.status_code != 400 and "Duplicate" not in response.text:
534
+ logger.warning(f"An error occurred while posting data {dt}: {ex}")
535
+ num_options_failed += 1
536
+ else:
537
+ num_duplicates += 1
538
+
539
+ trv.log_info(
540
+ {
541
+ "model_layer": "System Control Implementation",
542
+ "record_type": "Implementation Option",
543
+ "event_msg": f"Finished posting {num_options_success} Implementation Options (Failed: {num_options_failed} Duplicates: {num_duplicates})",
544
+ }
545
+ )
546
+
547
+ return res
548
+
549
+
550
+ def build_options(
551
+ app: Application, existing_options: List[dict], control_objectives: List[dict]
552
+ ) -> List[ImplementationOptionDeprecated]:
553
+ config = app.config
554
+ results = []
555
+ options = [
556
+ {
557
+ "Status": FULLY_IMPLEMENTED,
558
+ "Description": "The control is fully implemented.",
559
+ },
560
+ {"Status": NOT_IMPLEMENTED, "Description": "The control is not implemented."},
561
+ ]
562
+ for obj in control_objectives:
563
+ for option in options:
564
+ if option["Status"] not in {opt["name"] for opt in existing_options if opt["objectiveId"] == obj["id"]}:
565
+ results.append(
566
+ ImplementationOptionDeprecated(
567
+ id=0,
568
+ uuid="",
569
+ createdById=config["userId"],
570
+ dateCreated=get_current_datetime(),
571
+ lastUpdatedById=app.config["userId"],
572
+ dateLastUpdated=get_current_datetime(),
573
+ name=option["Status"],
574
+ description=option["Description"],
575
+ archived=False,
576
+ securityControlId=obj["securityControlId"],
577
+ objectiveId=obj["id"],
578
+ otherId="",
579
+ acceptability=FULLY_IMPLEMENTED,
580
+ )
581
+ )
582
+ return results