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,647 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Model for STIGs in the application"""
4
+
5
+ import os
6
+ import re
7
+ from enum import Enum
8
+ from pathlib import PosixPath
9
+ from typing import Any, Optional
10
+
11
+ from requests import JSONDecodeError
12
+ from rich.console import Console
13
+ from xmltodict import parse
14
+
15
+ from regscale.core.app.api import Api
16
+ from regscale.core.app.application import Application
17
+ from regscale.core.app.logz import create_logger
18
+ from regscale.models.integration_models.implementation_results import (
19
+ ImplementationResults,
20
+ )
21
+ from regscale.models.regscale_models import (
22
+ Component,
23
+ Checklist,
24
+ ImplementationObjective,
25
+ ImplementationOptionDeprecated,
26
+ T,
27
+ )
28
+
29
+
30
+ class Status(Enum):
31
+ """
32
+ Map STIG Status
33
+ """
34
+
35
+ NOT_REVIEWED = "Not Reviewed" # Create POAM
36
+ OPEN = "Open" # Create POAM
37
+ NOTAFINDING = "Not A Finding" # Pass
38
+ NOT_APPLICABLE = "Not Applicable" # Pass
39
+
40
+
41
+ class Severity(Enum):
42
+ """
43
+ Map STIG Severity to RegScale
44
+ """
45
+
46
+ HIGH = "I - High - Significant Deficiency"
47
+ MEDIUM = "II - Moderate - Reportable Condition"
48
+ LOW = "III - Low - Other Weakness"
49
+
50
+
51
+ class STIG_FILE:
52
+ """CKL File Processing to RegScale"""
53
+
54
+ def __init__(
55
+ self,
56
+ file_path: PosixPath,
57
+ ssp_id: int,
58
+ mapping: dict,
59
+ control_objectives: list,
60
+ security_controls: list,
61
+ assets: set,
62
+ control_implementations: list[dict],
63
+ app: Application = None,
64
+ ):
65
+ self.logger = create_logger(propagate=True)
66
+ self.app = app
67
+ self.api = Api(timeout=40)
68
+ self.security_controls = security_controls
69
+ self.existing_components = Component.get_components_from_ssp(app=self.app, ssp_id=ssp_id)
70
+ self.existing_assets = assets
71
+ self.update_assets = []
72
+ self.insert_assets = []
73
+ self.control_objectives = control_objectives
74
+ self.assessed_controls = []
75
+ self.parentids = set()
76
+ self.impids = set()
77
+ self.assets = []
78
+ self.file_path = file_path
79
+ self.mtime = os.path.getmtime(file_path)
80
+ self.obj = self._parse_xml()
81
+ metadata = self.obj["CHECKLIST"]["STIGS"]["iSTIG"]["STIG_INFO"]["SI_DATA"]
82
+ self.metadata = metadata
83
+ platform_objectives = []
84
+ self.platform_objectives = platform_objectives
85
+ self.ssp_id = ssp_id
86
+ self.control_implementations = control_implementations
87
+ self.implementation_options = []
88
+ self.cci_mapping = mapping
89
+ dict_data = self._to_dict()
90
+ self.dict_data = dict_data
91
+ self.issue_list = []
92
+ self.existing_checklists = []
93
+ self.update_checklists = set()
94
+ self.insert_checklists = set()
95
+ console = Console()
96
+ self.implementation_results = ImplementationResults(stig_file_name=self.file_path.name, console=console)
97
+ self.update_checks()
98
+ self._process_rules()
99
+
100
+ self.logger.debug("Finished processing %s", self.file_path.name)
101
+
102
+ def update_checks(self) -> None:
103
+ """
104
+ Update existing
105
+
106
+ :rtype: None
107
+ """
108
+ self.existing_checklists = []
109
+ for component in self.existing_components:
110
+ self.existing_checklists.extend(Checklist.get_checklists(component["id"]))
111
+
112
+ @classmethod
113
+ def _find_dict_by_key(cls, input_list: list, search_key: Any, search_value: Any) -> Optional[T]:
114
+ """
115
+ Find a dictionary in a list of dictionaries by searching for a key value pair
116
+
117
+ :param list input_list: List of dictionaries
118
+ :param Any search_key: Key to search for
119
+ :param Any search_value: Value to search for
120
+ :return: A dictionary from the list
121
+ :rtype: Optional[T]
122
+ """
123
+ return next((item for item in input_list if item.get(search_key) == search_value), None)
124
+
125
+ def _parse_xml(self) -> dict:
126
+ """
127
+ Convert CKL to a dictionary
128
+
129
+ :return: A dictionary with the CKL data
130
+ :rtype: dict
131
+ """
132
+
133
+ with open(self.file_path, encoding="utf-8") as file:
134
+ return parse(file.read(), dict_constructor=dict)
135
+
136
+ def _to_dict(self) -> dict:
137
+ """
138
+ Convert xmltodict object to friendly dictionary
139
+
140
+ :return: A dictionary with the CKL data
141
+ :rtype: dict
142
+ """
143
+
144
+ def extract_value(key: str) -> Any:
145
+ """
146
+ Extract a value from the metadata
147
+
148
+ :param str key: Key to search for
149
+ :return: Value from the metadata
150
+ :rtype: Any
151
+ """
152
+ data = ""
153
+ try:
154
+ dat = [name for name in self.metadata if name["SID_NAME"] == key][0]
155
+ if "SID_DATA" in dat.keys():
156
+ data = dat["SID_DATA"]
157
+ data = {k.replace('"', ""): v for k, v in dat.items()}
158
+ except IndexError:
159
+ return ""
160
+ return data
161
+
162
+ data = {}
163
+ data["Title"] = extract_value("title")
164
+ data["Description"] = extract_value("description")
165
+ data["Version"] = extract_value("version")
166
+ data["Release"] = extract_value("release")
167
+ data["Notice"] = extract_value("notice")
168
+ data["UUID"] = extract_value("uuid")
169
+ data["Source"] = extract_value("source")
170
+ data["Rules"] = self._parse_rules()
171
+ data["StigID"] = extract_value("stigid")
172
+ data["Classification"] = extract_value("classification")
173
+ return data
174
+
175
+ def _has_assets(self) -> bool:
176
+ """
177
+ Determine if the CKL has assets
178
+
179
+ :return: Whether the CKL has assets
180
+ :rtype: bool
181
+ """
182
+ data = self.obj["CHECKLIST"]["ASSET"]
183
+ if isinstance(data, dict) and data["HOST_NAME"] is None:
184
+ self.logger.warning("%s contains missing asset information, exiting..", self.file_path)
185
+ return False
186
+ return True
187
+
188
+ @staticmethod
189
+ def _format_type(key: Any, rule: Any) -> str:
190
+ """
191
+ Function to deal with list of str or strings
192
+
193
+ :param Any key: Rule key
194
+ :param Any rule: Rule object
195
+ :return: concatenated string or ""
196
+ :rtype: str
197
+ """
198
+ result = ""
199
+ if isinstance(rule, list):
200
+ res = ". ".join(rule)
201
+ elif isinstance(rule, dict):
202
+ res = rule[key]
203
+ elif isinstance(rule, str):
204
+ res = rule
205
+ if isinstance(res, list) and res:
206
+ result = ". ".join(res)
207
+ return result
208
+
209
+ def _get_component_id(self, asset_type: str) -> dict:
210
+ """
211
+ Return the component id for the asset type
212
+
213
+ :param str asset_type: Asset type (e.g. hardware, software, etc)
214
+ :return: component dictionary
215
+ :rtype: dict
216
+ """
217
+ res = [cmp for cmp in self.existing_components if cmp["componentType"] == asset_type.lower()]
218
+ if res:
219
+ return res[0]
220
+
221
+ def _process_rule(self, rule: dict) -> None:
222
+ """
223
+ Process a single rule (from the CKL)
224
+
225
+ :param dict rule: CKL rule
226
+ :rtype: None
227
+ """
228
+ ccis = rule["CCI"] # Gather list of CCI IDs
229
+ controls = self._get_control_ids(ccis=ccis)
230
+ for cci_info in controls: # Get CCI to Control Mapping
231
+ control_id = cci_info["ctl_id_main"]
232
+ # security_control_id = self.api.get(url=self.)
233
+ # Match rules to regcsale objectives
234
+ if not control_id:
235
+ return
236
+ # Create Component Control if not exists
237
+ if control_id:
238
+ status = "Fail"
239
+ obj_status = "Not Implemented"
240
+ try:
241
+ if (
242
+ "Status" in rule
243
+ and isinstance(rule["Status"], str)
244
+ and rule["Status"].lower() == Status.NOTAFINDING.name.lower()
245
+ ):
246
+ status = "Pass"
247
+ obj_status = "Fully Implemented"
248
+ except AttributeError:
249
+ self.logger.debug(
250
+ "Unable to process status for %s\nstatus will be set to 'Not Implemented'",
251
+ rule["RuleID"],
252
+ )
253
+ # Map STIG CCI to RegScale Control
254
+ security_control_list = [
255
+ cntrl for cntrl in self.security_controls if cntrl["controlId"].upper() == control_id.upper()
256
+ ]
257
+ if security_control_list:
258
+ security_control = security_control_list[0]
259
+ else:
260
+ continue
261
+ implementations = self._get_control_implementations(security_control=security_control)
262
+ raw_asset = self.obj["CHECKLIST"]["ASSET"]
263
+ # Link this checklist to assets
264
+ assets = [
265
+ asset.dict()
266
+ for asset in self.existing_assets
267
+ if raw_asset["HOST_FQDN"].lower() == asset["fqdn"].lower()
268
+ and raw_asset["TARGET_KEY"] == asset["otherTrackingNumber"]
269
+ ]
270
+ if not assets:
271
+ self.logger.debug(
272
+ "No assets found for %s or %s, skipping rule..",
273
+ raw_asset["HOST_FQDN"],
274
+ raw_asset["TARGET_KEY"],
275
+ )
276
+ return
277
+ component_id = self._get_component_id(asset_type=assets[0]["assetCategory"])["id"]
278
+ # grab the correct implementation based on asset type and component
279
+ imps = [imp for imp in implementations if imp["parentId"] == component_id]
280
+
281
+ if imps: # and (status.lower() == Status.OPEN.value.lower()):
282
+ implementation = imps[0]
283
+ imp_id = implementation["id"]
284
+ # Assets are loaded, lets update checklists
285
+
286
+ self.implementation_results.add_result(obj_status)
287
+
288
+ # Select Option to update the Implementation Objective (required)
289
+ comments = self._format_type(rule=rule, key="Comments")
290
+ finding_details = self._format_type(rule=rule, key="FindingDetails")
291
+
292
+ if not finding_details and status == "Pass":
293
+ finding_details = "Not a finding"
294
+ if not finding_details and status == "Fail":
295
+ finding_details = "An Unknown Error leading to failed check. STIG contains no finding details"
296
+
297
+ for asset in assets:
298
+ assert asset["id"]
299
+ for _, cci in enumerate(ccis):
300
+ baseline = (((self.file_path).name).split(".")[0]).split("-")[0].strip()
301
+ checklist = Checklist(
302
+ assetId=asset["id"],
303
+ status=status,
304
+ tool="STIGs",
305
+ vulnerabilityId=rule["VulnID"],
306
+ ruleId=rule["RuleID"],
307
+ cci=cci,
308
+ baseline=baseline,
309
+ check=(
310
+ rule["RuleTitle"] + "\n" + rule["Check_Content"]
311
+ ), # TODO: Where should i implement fix text?
312
+ results=finding_details,
313
+ comments=comments,
314
+ )
315
+ if checklist not in {Checklist(**chk) for chk in self.existing_checklists}:
316
+ # Post
317
+ self.insert_checklists.add(checklist)
318
+ else:
319
+ # Update
320
+ existing_checklist = {
321
+ Checklist(**chk)
322
+ for chk in self.existing_checklists
323
+ if Checklist(**chk) == checklist
324
+ }.pop()
325
+ checklist.id = existing_checklist.id
326
+ if checklist.status != existing_checklist.status:
327
+ self.update_checklists.add(checklist)
328
+ self.impids.add(imp_id)
329
+
330
+ # end default constructor
331
+ # flake8: noqa: C901
332
+ def _process_rules(self) -> None:
333
+ """
334
+ Convert Stig vulnerabilities/rules to RegScale objects
335
+
336
+ :rtype: None
337
+ """
338
+
339
+ if not self._has_assets():
340
+ return
341
+ for rule in self.dict_data["Rules"]:
342
+ self._process_rule(rule)
343
+ self.implementation_results.report_log()
344
+ self._update_checklists()
345
+
346
+ def _update_checklists(self) -> None:
347
+ """
348
+ Update or Insert checklists into RegScale
349
+
350
+ :rtype: None
351
+ """
352
+ if self.update_checklists:
353
+ res = self.api.post(
354
+ url=self.app.config["domain"] + "/api/securitychecklist/batchUpdate",
355
+ json=[chk for chk in self.update_checklists],
356
+ )
357
+ # update list
358
+ updated = res.json()
359
+ # update existing
360
+ for ix, check in enumerate(self.existing_checklists):
361
+ found_check = self._find_dict_by_key(input_list=updated, search_key="id", search_value=check["id"])
362
+ if found_check:
363
+ self.existing_checklists[ix] = found_check
364
+
365
+ if self.insert_checklists:
366
+ res = self.api.post(
367
+ url=self.app.config["domain"] + "/api/securitychecklist/batchCreate",
368
+ json=[chk.dict() for chk in self.insert_checklists],
369
+ )
370
+ if res.status_code == 200:
371
+ self.existing_checklists.append(res.json())
372
+
373
+ def _get_saved_implementation_objectives(self, control_id: int) -> list[dict]:
374
+ """
375
+ Return implementation objectives for a given control
376
+
377
+ :param int control_id: The control id to lookup
378
+ :return: list containing implementation objective matching the control id
379
+ :rtype: list[dict]
380
+ """
381
+ return ImplementationObjective.fetch_implementation_objectives(self.app, control_id)
382
+
383
+ def _control_id_lookup(self, control_name: str) -> int:
384
+ """
385
+ Lookup a control id from a friendly string id. (ex: AC-10)
386
+
387
+ :param str control_name: The control name to lookup
388
+ :return: control id
389
+ :rtype: int
390
+ """
391
+ ids = []
392
+ result = None
393
+ try:
394
+ ids = [
395
+ control
396
+ for control in [imp["control"] for imp in self.control_implementations]
397
+ if control["controlId"].lower() == control_name.lower()
398
+ ]
399
+ except (AttributeError, TypeError) as aex:
400
+ self.logger.warning("Unable to find control id for %s\n%s", control_name, aex)
401
+ return result
402
+ if ids:
403
+ result = ids[0]["id"]
404
+ return result
405
+
406
+ def _get_control_objectives(self, control_id: int) -> list[dict]:
407
+ """
408
+ Return control objectives for a given control ID
409
+
410
+ :param int control_id: id to fetch objectives for
411
+ :return: A list of control objectives
412
+ :rtype: list[dict]
413
+ """
414
+ control_objectives = []
415
+ try:
416
+ response = self.api.get(self.app.config["domain"] + f"/api/controlObjectives/getByControl/{control_id}")
417
+ if not response.raise_for_status():
418
+ control_objectives = response.json()
419
+ except (JSONDecodeError, IndexError) as jex:
420
+ self.logger.error(jex)
421
+ return control_objectives
422
+
423
+ def _get_control_ids(self, ccis: list) -> list[Any]:
424
+ """
425
+ Return friendly control id
426
+
427
+ :param list ccis: A list of CCIs to lookup
428
+ :return: A list of dict with control id and control name
429
+ :rtype: list[Any]
430
+ """
431
+ # TODO:
432
+ # [5:07 PM] Greg Elin
433
+ # A single control in a catalog will have multiple CCIs. Each CCI identfies an explicit "chieck" or "detail" in a control since controls often referred to multiple activities a team needs to do.  Example, a control will say "Organization will define and disseminate access policy to users."  In this case two CCIs exist, one to reference "define access policy" and one to reference "disseminate access policy"
434
+ # like 1
435
+ # Example, a control will say "Organization will define and disseminate access policy to users." In this case two CCIs exist, one to reference "define access policy" and one to reference "disseminate access policy"
436
+ # Awareness training controls, organizational..
437
+ result = []
438
+ # 99% of the cci-ref entries should be the following form of NIST SP 800-53:
439
+ if ccis is None:
440
+ ccis = {"CCI-000366"}
441
+ result = ccis
442
+ return result
443
+ try:
444
+ result = self.cci_mapping[ccis[0]]
445
+ except TypeError as tex:
446
+ self.logger.error("Unable to fetch control id %s\n%s", ccis, tex)
447
+ return result
448
+
449
+ @staticmethod
450
+ def _gen_notes(data: tuple[str, str, str, str, str]) -> str:
451
+ """
452
+ Generate notes section in a similar format to the STIGViewer
453
+ (vuln_id, check_text, fix_text, discussion, rule_title)
454
+
455
+ :param tuple[str, str, str, str, str] data: A tuple of strings
456
+ :return: A formatted string
457
+ :rtype: str
458
+ """
459
+ notes = f"""Vul ID: {data[0]}
460
+ Rule Title: {data[4]}
461
+ Discussion: {data[3]}
462
+ Check Text: {data[1]}
463
+ Fix Text: {data[2]}
464
+ """
465
+
466
+ return notes
467
+
468
+ def _get_control_implementations(self, security_control: dict) -> list[dict]:
469
+ """
470
+ Lookup or create a control implementation for a given checklist rule
471
+
472
+ :param dict security_control: Security Control as a dictionary from RegScale
473
+ :return: List of a Control implementation
474
+ :rtype: list[dict]
475
+ """
476
+ control_implementations = [
477
+ imp for imp in self.control_implementations if imp["controlID"] == security_control["id"]
478
+ ]
479
+ return control_implementations
480
+
481
+ def _option_lookup(self, control_id: int) -> list[ImplementationOptionDeprecated]:
482
+ """
483
+ Fetch implementation options by security control id
484
+
485
+ :param int control_id: Security Control ID
486
+ :return: A list of implementation options
487
+ :rtype: list[ImplementationOptionDeprecated]
488
+ """
489
+ return ImplementationOptionDeprecated.fetch_implementation_options(app=self.app, control_id=control_id)
490
+
491
+ def _attribute_lookup(self, j_array: dict, key: str) -> list:
492
+ """
493
+ Attribute lookup
494
+
495
+ :param dict j_array: json object of attributes for a STIG
496
+ :param str key: key to filter STIG attributes
497
+ :return: list of attributes
498
+ :rtype: list
499
+ """
500
+ result = []
501
+ try:
502
+ result = [value for value in j_array if value["VULN_ATTRIBUTE"].lower() == key.lower()]
503
+ except AttributeError as aex:
504
+ self.logger.error("Unable to pull attribute value\n%s", aex)
505
+ return result
506
+
507
+ def _process_stig_data(self, info: dict, key: str) -> Any:
508
+ """
509
+ Check data length, if valid return
510
+
511
+ :param dict info: A dict of stig information
512
+ :param str key: key to look up in the dictionary
513
+ :return: A list or string with lookup data
514
+ :rtype: Any
515
+ """
516
+ dat = info[key.upper()] if key.upper() in info else None
517
+ try:
518
+ if not dat:
519
+ dat = self._attribute_lookup(info["STIG_DATA"], key)
520
+ if len(dat) > 0:
521
+ if key == "cci_ref":
522
+ return [data["ATTRIBUTE_DATA"] for data in dat if "CCI" in data["ATTRIBUTE_DATA"]]
523
+ if dat and "ATTRIBUTE_DATA" in dat[0]:
524
+ return dat[0]["ATTRIBUTE_DATA"]
525
+ except TypeError:
526
+ self.logger.error("Unable to process %s\n", key)
527
+ return dat
528
+
529
+ def _parse_rules(self) -> list:
530
+ """
531
+ Format the rule data to a simple list.
532
+
533
+ :return: list of rules
534
+ :rtype: list
535
+ """
536
+ stig_vulns = self.obj["CHECKLIST"]["STIGS"]["iSTIG"]["VULN"]
537
+ result = []
538
+ for info in stig_vulns:
539
+ if isinstance(info, dict) and "STIG_DATA" in info:
540
+ rule = {
541
+ "VulnID": "",
542
+ "RuleID": "",
543
+ "StigID": "",
544
+ "Severity": "",
545
+ "Cat": "",
546
+ "Classification": "",
547
+ "GroupTitle": "",
548
+ "RuleTitle": "",
549
+ "Description": "",
550
+ "VulnDiscussion": "",
551
+ "FalsePositives": "",
552
+ "FalseNegatives": "",
553
+ "Documentable": "",
554
+ "Mitigations": "",
555
+ "SeverityOverrideGuidance": "",
556
+ "PotentialImpacts": "",
557
+ "ThirdPartyTools": "",
558
+ "MitigationControl": "",
559
+ "Responsibility": "",
560
+ "IAControls": "",
561
+ "CheckText": "",
562
+ "FixText": "",
563
+ "CCI": "",
564
+ }
565
+ try:
566
+ info["STATUS"].replace("_", " ") if "STATUS" in info else None
567
+ except AttributeError:
568
+ info["STATUS"] = "" # Leave Empty
569
+ severity = (
570
+ self._process_stig_data(info, "severity").upper()
571
+ if self._process_stig_data(info, "severity")
572
+ else None
573
+ )
574
+ rule["GroupTitle"] = self._process_stig_data(info, "group_title")
575
+ rule["Check_Content"] = self._process_stig_data(info, "check_content")
576
+ rule["Description"] = self._process_stig_data(info, "description")
577
+ rule["Documentable"] = self._process_stig_data(info, "documentable")
578
+ rule["Mitigations"] = self._process_stig_data(info, "mitigatons")
579
+ rule["PotentialImpacts"] = self._process_stig_data(info, "potential_impact")
580
+ rule["FalsePositives"] = self._process_stig_data(info, "false_positives")
581
+ rule["FalseNegatives"] = self._process_stig_data(info, "false_negatives")
582
+ rule["ThirdPartyTools"] = self._process_stig_data(info, "third_party_tools")
583
+ rule["MitigationControl"] = self._process_stig_data(info, "mitigation_control")
584
+ rule["Responsibility"] = self._process_stig_data(info, "responsibility")
585
+ rule["Status"] = self._process_stig_data(info, "status")
586
+ rule["FindingDetails"] = self._process_stig_data(info, "finding_details")
587
+ rule["Comments"] = self._process_stig_data(info, "comments")
588
+ rule["SecurityOverride"] = self._process_stig_data(info, "security_override")
589
+ rule["SecurityJustification"] = self._process_stig_data(info, "security_justification")
590
+ rule["Severity"] = severity
591
+ rule["VulnID"] = self._process_stig_data(info, "vuln_num")
592
+ rule["RuleTitle"] = self._process_stig_data(info, "rule_title")
593
+ rule["RuleID"] = self._process_stig_data(info, "rule_id")
594
+ rule["IAControls"] = self._process_stig_data(info, "ia_controls")
595
+ rule["StigID"] = self._process_stig_data(info, "stig_id")
596
+ rule["FixText"] = self._process_stig_data(info, "fix_text")
597
+ rule["CheckText"] = self._process_stig_data(info, "check_text")
598
+ rule["CCI"] = self._process_stig_data(info, "cci_ref") # TODO: handle multiple cci-refs
599
+ rule["Weight"] = self._process_stig_data(info, "weight")
600
+ rule["Classification"] = self._process_stig_data(info, "class")
601
+ rule["SecurityOverrideGuidence"] = self._process_stig_data(info, "security_override_Guidence")
602
+ rule["STIGRef"] = self._process_stig_data(info, "stigref")
603
+ discussion = self._process_stig_data(info, "vuln_discuss")
604
+ rule["VulnDiscussion"] = discussion if discussion is not None else rule["FixText"]
605
+ if rule["CCI"]:
606
+ result.append(rule)
607
+ return result
608
+
609
+ def oscalize_control_id(self, cl_id: str) -> Any:
610
+ """
611
+ Output an oscal standard control id from various common formats for control ids
612
+ Source: https://github.com/RegScale/ComponentHub/blob/389347aa8a267aeed96b9b856c66e88c5c1127d9/muse/ComponentTools.py#L218
613
+
614
+ :param str cl_id: A standard control id
615
+ :return: An oscal control id
616
+ :rtype: Any
617
+ """
618
+ # Handle improperly formatted control id
619
+ # Recognize only properly formmated control id:
620
+ pattern = re.compile("^[A-Za-z][A-Za-z]-[0-9() .a-z]*$")
621
+ if not pattern.match(cl_id):
622
+ self.logger.error("Problem OSCAL-izing %s", cl_id)
623
+ return "at.4"
624
+ # Handle properly formatted existing id
625
+ # Transform various patterns of control ids into OSCAL format
626
+ # Fix leading zero in at-01, ac-02.3, ac-02 (3)
627
+ cl_id = re.sub(r"^([A-Za-z][A-Za-z]-)0(.*)$", r"\1\2", cl_id)
628
+ # Change paranthesis into a dot
629
+ # Match: AU-3, AU-3 c, IA-5 (1), IA-5 (1) (c), IA-2 (12)
630
+ match = re.match(
631
+ r"^([A-Za-z][A-Za-z]-)([0-9]*)([ ]*[a-z]*)(\(([0-9][0-9]*)\))*( \(([a-z]*)\))?$",
632
+ cl_id,
633
+ )
634
+ cl_id = (
635
+ "".join(filter(None, (match.group(1), match.group(2)))).lower().strip()
636
+ + "."
637
+ + "".join(filter(None, (match.group(4),))).lower().strip()
638
+ )
639
+ cl_pid = "".join(filter(None, (match.group(6),))).lower().strip()
640
+ # Remove trailing space
641
+ cl_id = cl_id.strip(" ").strip(".")
642
+ # Remove paranthesis
643
+ cl_id = re.sub(r"[()]", "", cl_id)
644
+ cl_pid = re.sub(r"[()]", "", cl_pid)
645
+ # Set to lowercase
646
+ cl_id = cl_id.lower()
647
+ return cl_id, cl_pid