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,34 @@
1
+ """Mappings for System Roles."""
2
+
3
+ from lxml import etree
4
+
5
+ from regscale.core.app.application import Application
6
+ from regscale.integrations.public.fedramp.mappings.values import (
7
+ UUID,
8
+ FunctionPerformed,
9
+ Title,
10
+ )
11
+ from regscale.core.app.utils.app_utils import get_current_datetime
12
+ from regscale.models.regscale_models.system_role import SystemRole
13
+
14
+
15
+ def create_system_role(element: etree._Element) -> SystemRole:
16
+ """
17
+ Create a SystemRoles object from an XML Element
18
+
19
+ :param etree._Element element: The XML Element to parse
20
+ :return: A SystemRole object
21
+ :rtype: SystemRole
22
+ """
23
+ data = {}
24
+ for field in [UUID, Title, FunctionPerformed]:
25
+ for elem in element:
26
+ if results := field.parse_from_element(elem):
27
+ data[field.value] = results[1]
28
+ app = Application()
29
+ data["id"] = 0
30
+ data["createdById"] = app.config.get("userId")
31
+ data["lastUpdatedById"] = app.config.get("userId")
32
+ data["dateCreated"] = get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ")
33
+ data["dateLastUpdated"] = get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ")
34
+ return SystemRole(**data)
@@ -0,0 +1,175 @@
1
+ # flake8: noqa
2
+ """LeveragedAuthMapping classes for FedRAMP."""
3
+
4
+ from typing import List, Optional
5
+
6
+ from lxml import etree
7
+
8
+ from regscale.core.app.api import Api
9
+ from regscale.core.app.application import Application
10
+ from regscale.core.app.logz import create_logger
11
+ from regscale.integrations.public.fedramp.fedramp_traversal import FedrampTraversal
12
+ from regscale.core.app.utils.XMLIR import XMLIR2, XMLIRTraversal
13
+ from regscale.models.regscale_models.system_role import SystemRole
14
+
15
+ logger = create_logger()
16
+
17
+
18
+ class UserMappingIRAuthorizedPrivilegesIR(XMLIR2):
19
+ title: Optional[str] = None
20
+
21
+ def get_title(self, trv: XMLIRTraversal) -> Optional[str]:
22
+ """The title of the authorized privilege."""
23
+ vlist = trv.el_xpath(".//oscal:title")
24
+ return vlist[0].text if vlist else None
25
+
26
+ description: Optional[str] = None
27
+
28
+ def get_description(self, trv: XMLIRTraversal) -> Optional[str]:
29
+ """The description of the authorized privilege."""
30
+ vlist = trv.el_xpath(".//oscal:description")
31
+ return vlist[0].text if vlist else None
32
+
33
+
34
+ class UserMappingIR(XMLIR2):
35
+ title: Optional[str] = None
36
+
37
+ def get_title(self, trv: XMLIRTraversal) -> Optional[str]:
38
+ """The user's title"""
39
+ vlist = trv.el_xpath(".//oscal:title")
40
+ return vlist[0].text if vlist else None
41
+
42
+ type: Optional[str] = None
43
+
44
+ def get_type(self, trv: XMLIRTraversal) -> Optional[str]:
45
+ """The type of the user."""
46
+ vlist = trv.el_xpath('.//oscal:prop[@name="type"]')
47
+ return vlist[0].get("value") if vlist else None
48
+
49
+ sensitivity: Optional[str] = None
50
+
51
+ def get_sensitivity(self, trv: XMLIRTraversal) -> Optional[str]:
52
+ """The sensitivity of the user."""
53
+ vlist = trv.el_xpath('.//oscal:prop[@name="sensitivity"]')
54
+
55
+ return vlist[0].get("value") if vlist else None
56
+
57
+ privilege_level: Optional[str] = None
58
+
59
+ def get_privilege_level(self, trv: XMLIRTraversal) -> Optional[str]:
60
+ """The privilege level of the user."""
61
+ vlist = trv.el_xpath('.//oscal:prop[@name="privilege-level"]')
62
+
63
+ return vlist[0].get("value") if vlist else None
64
+
65
+ role_id: Optional[str] = None
66
+
67
+ def get_role_id(self, trv: XMLIRTraversal) -> Optional[str]:
68
+ """The role id of the user."""
69
+ vlist = trv.el_xpath(".//oscal:role-id")
70
+
71
+ return vlist[0].text if vlist else None
72
+
73
+ authorized_privileges: List[UserMappingIRAuthorizedPrivilegesIR] = []
74
+
75
+ def get_authorized_privileges(self, trv: XMLIRTraversal) -> List[UserMappingIRAuthorizedPrivilegesIR]:
76
+ """The authorized privileges of the user."""
77
+ vlist = trv.el_xpath(".//oscal:authorized-privilege")
78
+
79
+ return [
80
+ UserMappingIRAuthorizedPrivilegesIR(
81
+ XMLIRTraversal(xpathToThis="....", el=el, root=trv.root, namespaces=trv.namespaces)
82
+ )
83
+ for el in vlist
84
+ ]
85
+
86
+
87
+ def handle_user(trv: FedrampTraversal):
88
+ """
89
+ Extract user nodes from the SSP and send them to the RegScale API.
90
+ """
91
+ try:
92
+ api = trv.api
93
+ root = trv.root
94
+
95
+ namespaces = {
96
+ "oscal": "http://csrc.nist.gov/ns/oscal/1.0",
97
+ "fedramp": "https://fedramp.gov/ns/oscal",
98
+ }
99
+
100
+ # Extract user nodes
101
+ users = root.xpath(".//oscal:system-implementation/oscal:user", namespaces=namespaces)
102
+
103
+ if len(users) == 0:
104
+ trv.log_info(
105
+ {
106
+ "model_layer": "system-implementation",
107
+ "record_type": "user",
108
+ "event_msg": "No users / System Roles detected.",
109
+ }
110
+ )
111
+
112
+ for elem in users:
113
+ res = UserMappingIR(XMLIRTraversal(xpathToThis="....", el=elem, root=root, namespaces=namespaces))
114
+
115
+ logger.debug("parsed object", res)
116
+
117
+ sending = {
118
+ "id": 0,
119
+ # Title
120
+ "roleName": res.title,
121
+ "fedrampRoleId": res.role_id,
122
+ "roleType": res.type,
123
+ "assignedUserId": None,
124
+ "accessLevel": res.privilege_level,
125
+ "sensitivityLevel": res.sensitivity,
126
+ "privilegeDescription": res.privilege_level,
127
+ "functions": ", ".join([str(dict(r)) for r in res.authorized_privileges]),
128
+ "securityPlanId": trv.ssp_id,
129
+ "createdById": api.config["userId"],
130
+ "isPublic": True,
131
+ }
132
+
133
+ system_roles = SystemRole(**sending)
134
+ if system_roles.insert_systemrole(api.app):
135
+ trv.log_info(
136
+ {
137
+ "model_layer": "system-implementation",
138
+ "record_type": "user",
139
+ "event_msg": f"Created user '{res.title}' with role id '{res.role_id}'",
140
+ }
141
+ )
142
+
143
+ logger.info("System role was created successfully in RegScale.")
144
+ else:
145
+ trv.log_error(
146
+ {
147
+ "model_layer": "system-implementation",
148
+ "record_type": "user",
149
+ "event_msg": "Failed to create user",
150
+ }
151
+ )
152
+ except Exception as e:
153
+ trv.log_error(
154
+ {
155
+ "model_layer": "system-implementation",
156
+ "record_type": "user",
157
+ "event_msg": f"Unknown issue: Failed to create user (ERROR: {str(e)})",
158
+ }
159
+ )
160
+
161
+
162
+ if __name__ == "__main__":
163
+ # If data is incomplete This fails w/ 500 error ( which means the json string being received by the server is either malformed or missing something
164
+ __app = Application()
165
+ __api = Api()
166
+
167
+ def basic_test():
168
+ tree = etree.parse("fr_ssp_gold_v1.1.xml")
169
+ root = tree.getroot()
170
+ ARG_SSP_ID = 360
171
+
172
+ handle_user(FedrampTraversal(api=__api, root=root, ssp_id=ARG_SSP_ID))
173
+
174
+ # Run tests
175
+ basic_test()
@@ -0,0 +1,141 @@
1
+ """Provide base models for values in the FedRAMP SSP."""
2
+
3
+ from typing import Callable, List, Optional, Tuple, Type, Union
4
+
5
+ from lxml import etree
6
+ from pydantic import BaseModel
7
+
8
+ from regscale.core.app.logz import create_logger
9
+ from regscale.integrations.public.fedramp.xml_utils import extract_markup_content
10
+
11
+ logger = create_logger()
12
+
13
+
14
+ class SSPField(BaseModel):
15
+ value: str
16
+ xpath: str
17
+ type_: Type = str
18
+ namespace: Optional[dict] = None
19
+ callable: Optional[Callable] = None
20
+
21
+ def parse_from_element(
22
+ self,
23
+ element: etree._Element,
24
+ ) -> Union[Tuple[str, str], List[Tuple[str, str]]]:
25
+ """Parse an SSPField from an XML Element
26
+
27
+ :param etree._Element element: The XML Element to parse
28
+ :return: A tuple of the field name and value
29
+ :rtype: Union[Tuple[str, str], List[Tuple[str, str]]]
30
+ """
31
+ result_list = element.xpath(self.xpath, namespaces=self.namespace)
32
+ output = []
33
+
34
+ def _helper(result):
35
+ if self.callable and callable(self.callable):
36
+ return self.value, self.type_(self.callable(result))
37
+ return self.value, self.type_(result)
38
+
39
+ if len(result_list) == 0:
40
+ logger.warning(f"No results found for {self.value} in {element.tag}")
41
+ if result_list and len(result_list) > 0:
42
+ output = [_helper(result) for result in result_list]
43
+ try:
44
+ return output[0][1] if len(result_list) == 1 and output and len(output[0]) > 1 else output
45
+ except IndexError:
46
+ return output
47
+
48
+
49
+ UUID = SSPField(value="uuid", xpath="@uuid")
50
+ Link = SSPField(value="link", xpath="link/@href")
51
+ Title = SSPField(value="title", xpath="title/text()")
52
+ PartyUUID = SSPField(
53
+ value="party_uuid",
54
+ xpath="party-uuid/text()",
55
+ namespace={"oscal": "http://csrc.nist.gov/ns/oscal/1.0"},
56
+ )
57
+ DateAuthorized = SSPField(
58
+ value="date_authorized",
59
+ xpath="date-authorized/text()",
60
+ namespace={"oscal": "http://csrc.nist.gov/ns/oscal/1.0"},
61
+ )
62
+ Remarks = SSPField(value="remarks", xpath="remarks", callable=extract_markup_content)
63
+ Description = SSPField(value="description", xpath="description", callable=extract_markup_content)
64
+ RoleId = SSPField(value="role-id", xpath="role-id/text()")
65
+ PropName = SSPField(value="prop-name", xpath="prop/@name")
66
+ PropValue = SSPField(value="prop-value", xpath="prop/@value")
67
+ UserUUID = SSPField(value="user-uuid", xpath="user/@uuid")
68
+ FunctionPerformed = SSPField(value="function-performed", xpath="function-performed/text()")
69
+
70
+
71
+ if __name__ == "__main__":
72
+ from regscale.models.regscale_models import (
73
+ LeveragedAuthorization,
74
+ )
75
+
76
+ xml_string = """<leveraged-authorization uuid="5a9c98ab-8e5e-433d-a7bd-515c07cd1497">
77
+ <title>AWS GovCloud</title>
78
+ <prop ns="https://fedramp.gov/ns/oscal" name="leveraged-system-identifier" value="F1603047866"/>
79
+ <link href="//path/to/leveraged_system_ssp.xml"/>
80
+ <link href="//path/to/leveraged_system_legacy_crm.xslt"/>
81
+ <link href="//path/to/leveraged_system_responsibility_and_inheritance.xml"/>
82
+ <party-uuid>f0bc13a4-3303-47dd-80d3-380e159c8362</party-uuid>
83
+ <date-authorized>2015-01-01</date-authorized>
84
+ <remarks>
85
+ <h1>Remarks</h1>
86
+ <p>The leveraged-authorizaton assembly is supposed to have a required uuid flag instead
87
+ of an optional id flag. This will be fixed in the syntax shortly.</p>
88
+ <p>Use one leveraged-authorization assembly for each underlying system. (In the legacy
89
+ world, these may be general support systems.</p>
90
+ <p>The link fields are optional, but preferred where known. Often, a leveraging system's
91
+ SSP author will not have access to the leveraged system's SSP, but should have access
92
+ to the leveraged system's CRM.</p>
93
+ </remarks>
94
+ <description>
95
+ <p>The description of the object contains the remarks.</p>
96
+ <h2>Services Used</h2>
97
+ <p>Services used by the leveraged system:</p>
98
+ <ul>
99
+ <li>EC2</li>
100
+ </ul>
101
+ </description>
102
+ </leveraged-authorization>
103
+ """
104
+ root = etree.fromstring(xml_string)
105
+ uuid = UUID.parse_from_element(root)
106
+ print(uuid)
107
+ date_authorized = DateAuthorized.parse_from_element(root)
108
+ print(date_authorized)
109
+ party_uuid = PartyUUID.parse_from_element(root)
110
+ print(party_uuid)
111
+ links = Link.parse_from_element(root)
112
+ print(links)
113
+ title = Title.parse_from_element(root)
114
+ print(title)
115
+ remarks = Remarks.parse_from_element(root)
116
+ print(remarks)
117
+ description = Description.parse_from_element(root)
118
+ print(description)
119
+ from regscale.core.app.application import Application
120
+ from regscale.core.app.utils.app_utils import get_current_datetime
121
+
122
+ app = Application()
123
+ leveraged_authorizations = LeveragedAuthorization(
124
+ uuid=uuid[1],
125
+ title=title[1],
126
+ fedrampId=None,
127
+ ownerId=party_uuid[1],
128
+ securityPlanId=1,
129
+ dateAuthorized=date_authorized[1],
130
+ description=remarks[1],
131
+ servicesUsed=None,
132
+ securityPlanLink=links[0][1],
133
+ crmLink=links[1][1],
134
+ responsibilityAndInheritanceLink=links[2][1],
135
+ createdById=app.config["userId"],
136
+ dateCreated=get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ"),
137
+ lastUpdatedById=app.config["userId"],
138
+ dateLastUpdated=get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ"),
139
+ tenantsId=None,
140
+ )
141
+ print(leveraged_authorizations)
@@ -0,0 +1,150 @@
1
+ """
2
+ This module contains the MDDocParser class, which is used to parse an SSP Appendix A file
3
+ and return a dictionary representing the data in the markdown document.
4
+ """
5
+
6
+ import re
7
+ import logging
8
+ import zipfile # Assuming you need this for other file handling
9
+ import pypandoc
10
+ from collections import defaultdict
11
+ from typing import Dict, TextIO, Optional, Tuple
12
+ from regscale.models import ProfileMapping
13
+
14
+ # Configure logger
15
+ logging.basicConfig(level=logging.DEBUG)
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # Tokens used in HTML parsing
19
+ BEGINPARTTOKEN = "<tr>"
20
+ ENDPARTTOKEN = "</tr>"
21
+ BODYSTARTTOKEN = "<tbody>"
22
+ BODYENDTOKEN = "</tbody>"
23
+ CONTROLSUMMARYTOKEN = "What is the solution"
24
+
25
+ FULL_SUMMARY_TOKEN = "What is the solution and how is it implemented?"
26
+ html_tag_pattern = re.compile(r"</?[^>]+>")
27
+
28
+
29
+ def clean_part(part: str) -> str:
30
+ """
31
+ Cleans an HTML part string by removing specific HTML tags.
32
+
33
+ :param part: The HTML part string
34
+ :return: A cleaned HTML part string with specific tags removed
35
+ """
36
+ # Pattern to match specified HTML tags, using non-capturing groups for better performance
37
+ pattern = re.compile(r"</?(td|tr|th|tbody|thead)(?: [^>]*)?>", re.IGNORECASE)
38
+ return pattern.sub("", part).strip()
39
+
40
+
41
+ class MDDocParser:
42
+ """
43
+ Parses an SSP .md file and extracts control parts into a dictionary.
44
+ """
45
+
46
+ def __init__(self, md_path: str, profile_id: int):
47
+ """
48
+ Initializes the MDDocParser with the path to the markdown file.
49
+
50
+ :param str md_path: Path to the markdown file
51
+ :param int profile_id: The profile ID to associate with the control parts
52
+ """
53
+ # List of controls to parse
54
+ self.md_path = md_path
55
+ try:
56
+ self.controls = [profile_map.controlId for profile_map in ProfileMapping.get_by_profile(profile_id)]
57
+ # Convert .md file to markdown_strict format and save output
58
+ self.md_text = pypandoc.convert_file(md_path, "markdown_strict", outputfile="app_a.md")
59
+ self.md_doc = "app_a.md"
60
+ except Exception as e:
61
+ logger.error(f"Error converting file: {e}")
62
+ raise
63
+
64
+ def get_parts(self) -> Dict[str, str]:
65
+ """
66
+ Parses the .md file and extracts control parts.
67
+
68
+ :return: A dictionary of control parts, keyed by control ID
69
+ """
70
+ control_parts_dict = defaultdict(str)
71
+ try:
72
+ with open(self.md_doc, "r") as file:
73
+ for line in file:
74
+ if CONTROLSUMMARYTOKEN in line:
75
+ control_id = self._handle_control_summary_line(line)
76
+ if not control_id:
77
+ continue
78
+ # Skip lines to find the table content
79
+ next(file) # Skip HTML table definition line
80
+ # Loop through file to capture parts between tbody tags
81
+ self.find_parts(file, control_parts_dict, control_id)
82
+ except FileNotFoundError as e:
83
+ logger.error(f"File not found: {e}")
84
+ except Exception as e:
85
+ logger.error(f"Error parsing file: {e}")
86
+ return control_parts_dict
87
+
88
+ @staticmethod
89
+ def clean_html_and_newlines(input_text: str) -> str:
90
+ """
91
+ Cleans HTML tags and newlines from a string.
92
+ :param str input_text: The text to clean
93
+ :return: The cleaned text
94
+ :rtype: str
95
+ """
96
+ # Remove HTML tags
97
+ cleaner_text = html_tag_pattern.sub("", input_text)
98
+ # Remove newlines
99
+ return cleaner_text.replace("\n", "")
100
+
101
+ def _handle_control_summary_line(self, line: str) -> Optional[str]:
102
+ """
103
+ Handles a line of text from the markdown file.
104
+
105
+ :param str line: The line of text
106
+ :return: The control ID
107
+ :rtype: Optional[str]
108
+ """
109
+ # Extract control ID and clean it
110
+ html_free_line = self.clean_html_and_newlines(line)
111
+ clean_line = html_free_line.replace(FULL_SUMMARY_TOKEN, "")
112
+ if not clean_line:
113
+ return None
114
+ clean_control_id_from_line = clean_line.strip()
115
+ return clean_control_id_from_line
116
+
117
+ def find_parts(self, file: TextIO, control_parts_dict: Dict, cntrlid: str):
118
+ """
119
+ Parses and collects parts from a markdown file into a dictionary by control ID.
120
+
121
+ :param file: The markdown file
122
+ :param control_parts_dict: Dictionary to store parts by control ID
123
+ :param cntrlid: The control ID
124
+ """
125
+ allparts = ""
126
+ for line in file:
127
+ if BODYSTARTTOKEN in line:
128
+ continue
129
+ elif BODYENDTOKEN in line:
130
+ break
131
+ allparts += self.part_cleaner(file, line)
132
+
133
+ control_parts_dict[cntrlid] = allparts
134
+ logger.debug(f"Control ID: {cntrlid}, Parts: {allparts}")
135
+
136
+ @staticmethod
137
+ def part_cleaner(file: TextIO, line: str) -> str:
138
+ """
139
+ Cleans and accumulates parts of text from the markdown file.
140
+
141
+ :param file: The markdown file
142
+ :param line: The current line of text
143
+ :return: The cleaned part as a string
144
+ """
145
+ part = ""
146
+ for next_line in file:
147
+ part += " " + clean_part(next_line)
148
+ if ENDPARTTOKEN in next_line:
149
+ break
150
+ return part