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,496 @@
1
+ """Module to parse the back-matter and resources from an SSP and post the items into RegScale"""
2
+
3
+ # flake8: noqa: C901
4
+ import base64
5
+ import json
6
+ import mimetypes
7
+ from io import BytesIO
8
+ from typing import Any, List, Optional
9
+
10
+ from lxml.etree import Element
11
+
12
+ from regscale.core.app.api import Api
13
+ from regscale.core.app.application import Application
14
+ from regscale.core.app.logz import create_logger
15
+ from regscale.integrations.public.fedramp.reporting import log_error, log_event
16
+ from regscale.models.regscale_models import File, Link, Reference
17
+
18
+ logger = create_logger()
19
+ RESOURCE = "Resources"
20
+ NS_TITLE = "ns1:title"
21
+ NS_CAPTION = "ns1:caption"
22
+ NS_DESC = "ns1:description"
23
+ NS_PROP = 'ns1:prop[@name="type"]'
24
+
25
+ TYPE_MAPPING = [
26
+ ("Acronym", "acronyms"),
27
+ ("Administrator Guide", "administrators-guide"),
28
+ ("Agreement", "agreement"),
29
+ ("Artifact", "artifact"),
30
+ ("Citation", "citations"),
31
+ ("Evidence", "evidence"),
32
+ ("Guidance", "external-guidance"),
33
+ ("Image", "image"),
34
+ ("Interview Notes", "interview-notes"),
35
+ ("Law", "law"),
36
+ ("Logo", "logo"),
37
+ ("Plan", "plan"),
38
+ ("Policy", "policy"),
39
+ ("Procedure", "procedure"),
40
+ ("Questionnaire", "questionnaire"),
41
+ ("Raw Data", "raw-data"),
42
+ ("Regulation", "regulation"),
43
+ ("Report", "report"),
44
+ ("Rules of Behavior", "rules-of-behavior"),
45
+ ("Screenshot", "screen-shot"),
46
+ ("Standard", "standard"),
47
+ ("System Guide", "system-guide"),
48
+ ("Tool Output", "tool-output"),
49
+ ("User Guide", "users-guide"),
50
+ ]
51
+
52
+
53
+ def parse_backmatter(resource_elem: Any, back_matter: Any, root: Any, ns: dict, ssp_id: int, events_list: list) -> dict:
54
+ """
55
+ A function to parse a <resource> element from an SSP and post it to RegScale
56
+
57
+ :param Any resource_elem: The data element that is being passed to be parsed into a resource
58
+ :param Any back_matter: The back-matter element of the SSP
59
+ :param Any root: The root element of the xml document
60
+ :param dict ns: Namespace dict to use for xpath element selection
61
+ :param int ssp_id: SSP ID in RegScale
62
+ :param list events_list: List of events to send to logs
63
+ :return: dictionary containing the results of the resource uploads
64
+ :rtype: dict
65
+ """
66
+ app = Application()
67
+ api = Api()
68
+ results = {
69
+ "filesUploaded": 0,
70
+ "linksCreated": 0,
71
+ "referencesCreated": 0,
72
+ }
73
+ # remove resources that do not have a uuid
74
+ resources = {
75
+ resource.attrib["uuid"]: resource_to_dict(resource)
76
+ for resource in resource_elem
77
+ if resource.attrib.get("uuid") is not None
78
+ }
79
+ # iterate the resources and put them in the right list
80
+ for uuid, resource in resources.items():
81
+ # check for references of the uuid elsewhere
82
+ matching_elements = root.xpath(f".//*[@uuid='{uuid}']", namespaces=ns)
83
+
84
+ # Exclude back-matter from results
85
+ if filtered_elements := [el for el in matching_elements if back_matter not in el.iterancestors()]:
86
+ resource["references"] = filtered_elements
87
+
88
+ if resource["hasBase64"]:
89
+ upload = File.upload_file_to_regscale(
90
+ file_name=resource["base64_filename"],
91
+ parent_id=ssp_id,
92
+ parent_module="securityplans",
93
+ api=api,
94
+ file_data=base64.b64decode(resource["base64_data"]),
95
+ return_object=True,
96
+ )
97
+ if upload:
98
+ results["filesUploaded"] += 1
99
+ events_list.append(
100
+ log_event(
101
+ record_type="File",
102
+ event_msg=f"File {resource['base64_filename']} uploaded successfully.",
103
+ model_layer=RESOURCE,
104
+ )
105
+ )
106
+ else:
107
+ events_list.append(
108
+ log_error(
109
+ record_type="File",
110
+ event_msg=f"File {resource['base64_filename']} failed to upload.",
111
+ model_layer=RESOURCE,
112
+ )
113
+ )
114
+ # if there is no base64, then there should be a link
115
+ other_attributes = None
116
+ if "title_rlink_href" in resource:
117
+ other_attributes = None
118
+ try:
119
+ if "title_prop" in resource:
120
+ other_attributes = ", ".join(
121
+ [
122
+ f"{key}: {value}"
123
+ for key, value in resource["title_prop"].items()
124
+ if resource.get("title_prop")
125
+ ]
126
+ )
127
+ except KeyError:
128
+ other_attributes = None
129
+ link_to_post = Link(
130
+ title=resource.get("title") or uuid,
131
+ url=resource["title_rlink_href"],
132
+ parentID=ssp_id,
133
+ parentModule="securityplans",
134
+ createdById=app.config["userId"],
135
+ externalId=uuid,
136
+ otherAttributes=other_attributes,
137
+ )
138
+ if _ := Link.insert_link(app, link_to_post):
139
+ results["linksCreated"] += 1
140
+ events_list.append(
141
+ log_event(
142
+ record_type="Link",
143
+ event_msg=f"Link {resource['title_rlink_href']} created successfully.",
144
+ model_layer=RESOURCE,
145
+ )
146
+ )
147
+ else:
148
+ events_list.append(
149
+ log_error(
150
+ record_type="Link",
151
+ event_msg=f"Link {resource['title_rlink_href']} failed to be created.",
152
+ model_layer=RESOURCE,
153
+ )
154
+ )
155
+
156
+ if references := resource.get("references"):
157
+ for reference in references:
158
+ if post_dict_reference(
159
+ api=api,
160
+ ssp_id=ssp_id,
161
+ reference_data=reference_to_dict(reference, ns),
162
+ resource_uuid=uuid,
163
+ resource=resource,
164
+ ):
165
+ results["referencesCreated"] += 1
166
+ events_list.append(
167
+ log_event(
168
+ record_type="Reference",
169
+ event_msg=f"Reference {reference.attrib['uuid']} created successfully.",
170
+ model_layer=RESOURCE,
171
+ )
172
+ )
173
+ else:
174
+ events_list.append(
175
+ log_error(
176
+ record_type="Reference",
177
+ event_msg=f"Reference {reference.attrib['uuid']} failed to be created.",
178
+ model_layer=RESOURCE,
179
+ )
180
+ )
181
+
182
+ return results
183
+
184
+
185
+ def post_dict_reference(
186
+ api: Api, ssp_id: int, reference_data: dict, resource: dict, resource_uuid: str
187
+ ) -> Optional[Reference]:
188
+ """
189
+ A function to post a reference to RegScale
190
+
191
+ :param Api api: Api object
192
+ :param int ssp_id: ID of the SSP to post the reference to
193
+ :param dict reference_data: Reference to parse and post to RegScale
194
+ :param dict resource: Resource that the reference is associated with
195
+ :param str resource_uuid: UUID of the resource that the reference is associated with
196
+ :return: Reference object if successful, None otherwise
197
+ :rtype: Optional[Reference]
198
+ """
199
+ reference_to_post = Reference(
200
+ createdById=api.config["userId"],
201
+ identificationNumber=resource_uuid,
202
+ title=reference_data.get("title"),
203
+ parentId=ssp_id,
204
+ parentModule="securityplans",
205
+ referenceType="Other",
206
+ link=resource.get("base64_filename") or resource.get("title_rlink_href"),
207
+ )
208
+ return reference_to_post.create_new_references(return_object=True)
209
+
210
+
211
+ def reference_to_dict(reference: Element, ns: dict) -> dict:
212
+ """
213
+ Function to convert a reference, lxml Element, into a dictionary
214
+
215
+ :param Element reference: reference to parse
216
+ :param dict ns: Namespace dict to use for xpath element selection
217
+ :return: dictionary of the provided reference
218
+ :rtype: dict
219
+ """
220
+ ref = {}
221
+ # DESCRIPTION
222
+ if reference.find(NS_DESC, namespaces=ns) is not None:
223
+ ref["description"] = ""
224
+ for p in reference.find(NS_DESC, namespaces=ns).findall("ns1:p", namespaces=ns):
225
+ ref["description"] = ref["description"] + p.text + " "
226
+
227
+ # TITLE (RegScale required)
228
+ if reference.find(NS_TITLE, namespaces=ns) is not None: # first check for title element
229
+ ref["title"] = reference.find(NS_TITLE, namespaces=ns).text
230
+ elif reference.find(NS_CAPTION, namespaces=ns) is not None: # if not that, use caption for title
231
+ ref["title"] = reference.find(NS_CAPTION, namespaces=ns).text
232
+ elif reference.find(NS_DESC, namespaces=ns) is not None: # if no caption, use description up to 50 char
233
+ ref["title"] = ref["description"][:50]
234
+ else: # if all else fails, just make it "Untitled
235
+ ref["title"] = "Untitled"
236
+
237
+ # TYPE (RegScale required)
238
+ if reference.find(NS_PROP, namespaces=ns) is not None:
239
+ ref["referenceType"] = apply_type_mapping(
240
+ TYPE_MAPPING,
241
+ reference.find(NS_PROP, namespaces=ns)[0].text,
242
+ )
243
+ else:
244
+ ref["referenceType"] = "Other"
245
+
246
+ return ref
247
+
248
+
249
+ def apply_type_mapping(mapping: List[tuple], value: str) -> Any:
250
+ """
251
+ A function to apply a mapping to a value
252
+
253
+ :param List[tuple] mapping: List of mapping pair tuples - (new, original)
254
+ :param str value: Thing to be mapped to a new value
255
+ :return: The new value
256
+ :rtype: Any
257
+ """
258
+ for new, original in mapping:
259
+ if value == original:
260
+ value = new
261
+ break
262
+ else:
263
+ value = "Other"
264
+ return value
265
+
266
+
267
+ def resource_to_dict(resource: Element) -> dict:
268
+ """
269
+ Recursive function to convert a lxml Element into a dictionary
270
+
271
+ :param Element resource: The lxml Element to convert to a dict
272
+ :return: Dictionary representation of the Element
273
+ :rtype: dict
274
+ """
275
+ resource_dict = {"hasBase64": False} # Initialize dictionary for each resource
276
+
277
+ for child in resource:
278
+ tag = str(child.tag).split("}")[-1] # Convert tag to string and then strip namespace
279
+
280
+ if tag == "title":
281
+ resource_dict["title"] = child.text
282
+
283
+ elif tag == "description":
284
+ for p_tag in child.findall(".//p"):
285
+ resource_dict["title_description"] = p_tag.text
286
+
287
+ elif tag == "prop":
288
+ name = child.get("name")
289
+ value = child.get("value")
290
+ if name and value:
291
+ resource_dict["title_prop"] = {"name": name, "value": value}
292
+
293
+ elif tag == "rlink":
294
+ href = child.get("href")
295
+ media_type = child.get("media-type")
296
+ if href:
297
+ resource_dict["title_rlink_href"] = href
298
+ if media_type:
299
+ resource_dict["title_media-type"] = media_type
300
+
301
+ elif tag == "base64":
302
+ resource_dict["hasBase64"] = True
303
+ base64_data = child.text.strip() # Get base64 content and strip whitespace
304
+ filename = child.get("filename")
305
+ media_type = child.get("media-type")
306
+ resource_dict["base64_data"] = base64_data
307
+ if filename:
308
+ resource_dict["base64_filename"] = filename
309
+ if media_type:
310
+ resource_dict["base64_media-type"] = media_type
311
+
312
+ return resource_dict
313
+
314
+
315
+ def parse_title(resource: Any, ref: dict, ns: dict, resource_elem: Any) -> str:
316
+ """
317
+ Function to parse the title of a resource
318
+
319
+ :param Any resource: The resource to parse
320
+ :param dict ref: Reference dictionary
321
+ :param dict ns: Namespace dictionary
322
+ :param Any resource_elem: The resource element to parse
323
+ :return: The title of the resource
324
+ :rtype: str
325
+ """
326
+ if resource.find(NS_TITLE, namespaces=ns) is not None: # first check for title element
327
+ return resource.find(NS_TITLE, namespaces=ns).text
328
+ elif resource.find(NS_CAPTION, namespaces=ns) is not None: # if not that, use caption for title
329
+ return resource.find(NS_CAPTION, namespaces=ns).text
330
+ elif resource_elem.find(NS_CAPTION, namespaces=ns) is not None: # also check referring element for caption
331
+ return resource_elem.find(NS_CAPTION, namespaces=ns).text
332
+ elif resource.find(NS_DESC, namespaces=ns) is not None: # if no caption, use description up to to 50 char
333
+ return ref["description"][:50]
334
+ else: # if all else fails, just make it "Untitled
335
+ return "Untitled"
336
+
337
+
338
+ def record_resource(resource_elem: Any, root: Any, ns: dict, ssp_id: int, tags: Optional[Any] = None) -> None:
339
+ """
340
+ A function to parse a <resource> element from an SSP and post it to RegScale
341
+
342
+ :param Any resource_elem: The data element that is being passed to be parsed into a resource
343
+ :param Any root: The root element of the xml document
344
+ :param dict ns: Namespace dict to use for xpath element selection
345
+ :param int ssp_id: SSP ID in RegScale
346
+ :param Optional[Any] tags: Optional string of semicolon-delimited tags to identify specific critical assets like network diagrams, defaults to None
347
+ :rtype: None
348
+ """
349
+ api = Api()
350
+ object_uuid = resource_elem.attrib[
351
+ "uuid"
352
+ ] # the id of the object that the back-matter resource is intended to describe
353
+ resource_link_id = resource_elem.find("ns1:link", namespaces=ns).attrib["href"].replace("#", "") # get uuid URI
354
+
355
+ # find the <resource> assembly whose uuid matches the URI
356
+ query_string = f"/ns1:system-security-plan/ns1:back-matter/ns1:resource[@uuid='{resource_link_id}']"
357
+ resource = root.xpath(query_string, namespaces=ns)[0]
358
+
359
+ ref = {}
360
+
361
+ # DESCRIPTION
362
+ if resource.find(NS_DESC, namespaces=ns) is not None:
363
+ ref["description"] = ""
364
+ for p in resource.find(NS_DESC, namespaces=ns).findall("ns1:p", namespaces=ns):
365
+ ref["description"] = ref["description"] + p.text + " "
366
+
367
+ # TITLE (RegScale required)
368
+ ref["title"] = parse_title(resource, ref, ns, resource_elem)
369
+
370
+ # TYPE (RegScale required)
371
+ if resource.find(NS_PROP, namespaces=ns) is not None:
372
+ ref["referenceType"] = apply_type_mapping(TYPE_MAPPING, resource.find(NS_PROP, namespaces=ns)[0].text)
373
+ else:
374
+ ref["referenceType"] = "Other"
375
+ # PARENT
376
+ ref["parentID"] = ssp_id
377
+ ref["parentModule"] = "securityplans"
378
+ if object_uuid is not None:
379
+ ref["identificationNumber"] = object_uuid
380
+
381
+ # RLINKS
382
+ for rlink in resource.findall("ns1:rlink", namespaces=ns):
383
+ new_reference = ref # start a new instance of a reference with the shared default values
384
+ new_reference["link"] = rlink.attrib["href"]
385
+ post_reference(new_reference)
386
+
387
+ # BASE64
388
+ for base64elem in resource.findall("ns1:base64", namespaces=ns):
389
+ new_reference = ref # start a new instance of a reference with the shared default values
390
+ new_reference["link"] = base64elem.attrib["filename"]
391
+ post_reference(new_reference)
392
+ file_metadata = {
393
+ "trustedDisplayName": base64elem.attrib["filename"],
394
+ "filesize": len(base64elem.text) * 0.75 - (base64elem.text[len(base64elem.text) - 2 :].count("=")),
395
+ }
396
+ if "media-type" in base64elem.attrib:
397
+ file_metadata["mimeType"] = base64elem.attrib["media-type"]
398
+ else:
399
+ file_metadata["mimeType"], _ = mimetypes.guess_type(file_metadata["trustedDisplayName"])
400
+ if tags:
401
+ file_metadata["tags"] = tags
402
+ file_metadata["parentId"] = (ssp_id,)
403
+ file_metadata["ParentModule"] = ("securityplans",)
404
+ file_response = File.upload_file_to_regscale(
405
+ file_name=file_metadata["trustedDisplayName"],
406
+ parent_id=ssp_id,
407
+ parent_module="securityplans",
408
+ api=api,
409
+ file_data=base64.b64decode(base64elem.text),
410
+ )
411
+ logger.info(file_response)
412
+ # upload_base64_file(file_metadata, base64elem.text, ssp_id)
413
+
414
+
415
+ def post_reference(reference_dict: dict) -> None:
416
+ """
417
+ A function to post a reference to RegScale
418
+
419
+ :param dict reference_dict: Reference object to post to RegScale
420
+ :rtype: None
421
+ """
422
+ app = Application()
423
+ api = Api()
424
+ headers_json = {
425
+ "accept": "*/*",
426
+ "Content-Type": "application/json-patch+json",
427
+ "Authorization": app.config["token"],
428
+ }
429
+ ssp_json = json.dumps(reference_dict)
430
+ response = api.post(
431
+ url=app.config["domain"] + "/api/references",
432
+ data=ssp_json,
433
+ headers=headers_json,
434
+ )
435
+ if response.status_code == 200:
436
+ ref_id = json.loads(response.text)["id"]
437
+ ref_title = reference_dict["title"]
438
+ log_event(
439
+ record_type="Resource",
440
+ model_layer="Back-matter",
441
+ event_msg=f"Successfully posted reference #: {ref_id} - {ref_title}.",
442
+ )
443
+ else:
444
+ log_error(
445
+ record_type="Resource",
446
+ model_layer="Back-matter",
447
+ event_msg="Problem posting reference.",
448
+ )
449
+
450
+
451
+ def upload_base64_file(file_metadata: dict, filestring: str, ssp_id: int) -> None:
452
+ """
453
+ A function to upload a base64 file to RegScale
454
+
455
+ :param dict file_metadata: Metadata for the file to be uploaded
456
+ :param str filestring: The base64 string of the file to be uploaded
457
+ :param int ssp_id: The ID of the SSP to upload the file to
458
+ :rtype: None
459
+ """
460
+ app = Application()
461
+ api = Api()
462
+ decoded_file = base64.b64decode(filestring)
463
+ files = {"file": (file_metadata["trustedDisplayName"], BytesIO(decoded_file))}
464
+ data = {"id": ssp_id, "module": "securityplans"}
465
+ response = api.post(
466
+ url=app.config["domain"] + "/files/file",
467
+ files=files,
468
+ data=data,
469
+ )
470
+ if response.status_code == 200:
471
+ logger.info("File uploaded successfully!")
472
+ logger.debug("Response content:", response.text)
473
+ response_data = json.loads(response.text)
474
+
475
+ file_metadata["fullPath"] = (response_data["fullPath"],)
476
+ file_metadata["fileHash"] = (response_data["fileHash"],)
477
+ file_metadata["shaHash"] = (response_data["shaHash"],)
478
+ file_metadata["uploadDate"] = (response_data["uploadDate"],)
479
+
480
+ file_metadata_json = json.dumps(file_metadata)
481
+ response = api.post(
482
+ url=app.config["domain"] + "/files",
483
+ data=file_metadata_json,
484
+ )
485
+ if response.status_code == 200:
486
+ logger.info("File entered to database")
487
+ logger.debug(response.text)
488
+ else:
489
+ logger.debug(response.status_code)
490
+ logger.debug(response.text)
491
+
492
+ elif response.status_code == 401:
493
+ logger.info("401: Unauthorized")
494
+ else:
495
+ logger.info("File upload failed. Status code:", response.status_code)
496
+ logger.debug("Response content:", response.text)
@@ -0,0 +1,110 @@
1
+ """
2
+ Rosetta Stone class Standardized approach to mapping identifiers between control id in FedRAMP and other frameworks
3
+ """
4
+
5
+ import json
6
+ from typing import Dict
7
+ from regscale.core.decorators import singleton
8
+ from pathlib import Path
9
+
10
+
11
+ @singleton
12
+ class RosettaStone:
13
+ """
14
+ Rosetta Stone class Standardized approach to mapping identifiers between control id in FedRAMP and other frameworks
15
+ """
16
+
17
+ def __init__(self):
18
+ self.map = None
19
+ self.rs_data = {}
20
+ self.rosetta = {}
21
+ self.name = ""
22
+ self.uuid = ""
23
+ self.description = ""
24
+ self.list0_name = ""
25
+ self.list1_name = ""
26
+ self.list2_name = ""
27
+ self.stone = []
28
+
29
+ def __str__(self):
30
+ return self.name
31
+
32
+ def loads(self, json_str: str):
33
+ """
34
+ Load json from a str
35
+ :param str json_str: JSON string
36
+ """
37
+ parsed_json = json.loads(json_str)
38
+ self._populate(parsed_json)
39
+
40
+ def load_json_from_file(self, json_file: str):
41
+ """
42
+ Load json from a file
43
+ :param str json_file: string name of a file
44
+ """
45
+ with open(json_file) as jf:
46
+ parsed_json = json.load(jf)
47
+ self._populate(parsed_json)
48
+
49
+ def load_fedramp_version_5_mapping(self):
50
+ """
51
+ Load FedRAMP version 5 mapping
52
+ """
53
+ from importlib.resources import path as resource_path
54
+
55
+ with resource_path("regscale.integrations.public.fedramp.mappings", "fedramp_r5_params.json") as json_file_path:
56
+ self.load_json_from_file(json_file_path.__str__())
57
+
58
+ def _populate(self, rs_dict: Dict):
59
+ """
60
+ Populate attributes from dictionary
61
+ :param Dict rs_dict: Dictionary of Rosetta Stone data
62
+ """
63
+ self.rs_data = rs_dict
64
+ self.rosetta = self.rs_data.get("rosetta", None)
65
+ self.name = self.rosetta.get("name", None)
66
+ self.uuid = self.rosetta.get("uuid", None)
67
+ self.description = self.rosetta.get("description", None)
68
+ self.list0_name = self.rosetta.get("list0_name", None)
69
+ self.list1_name = self.rosetta.get("list1_name", None)
70
+ self.list2_name = self.rosetta.get("list2_name", None)
71
+ self.stone = self.rosetta.get("stone", None)
72
+ # create quick_maps
73
+ self.quick_map = self.lookup_l1_by_l0()
74
+ self.reverse_quick_map = self.lookup_l0_by_l1()
75
+ self.list_guessed = self.guessed()
76
+
77
+ def lookup_l1_by_l0(self) -> Dict:
78
+ """
79
+ Map first items of list0, list1 as dictionary
80
+ :return: Dict
81
+ :rtype: Dict
82
+ """
83
+ self.map = {}
84
+ for item in self.stone:
85
+ self.map[item["list0"][0]] = item["list1"][0]
86
+ return self.map
87
+
88
+ def lookup_l0_by_l1(self) -> Dict:
89
+ """
90
+ Map first items of list0, list1 as dictionary
91
+ :return: Dict
92
+ :rtype: Dict
93
+ """
94
+ self.map = {}
95
+ for item in self.stone:
96
+ self.map[item["list1"][0]] = item["list0"][0]
97
+ return self.map
98
+
99
+ def guessed(self) -> Dict:
100
+ """
101
+ Return list of items with guesses
102
+ :return: Dict
103
+ :rtype: Dict
104
+ """
105
+ self.map = {}
106
+ for line in self.stone:
107
+ for c_score in line.get("confidence", None):
108
+ if 0 < c_score < 1:
109
+ self.map[line.get("list0")[0]] = line.get("list1")[0]
110
+ return self.map
@@ -0,0 +1,87 @@
1
+ from regscale.integrations.public.fedramp.reporting import (
2
+ write_events,
3
+ log_error,
4
+ log_event,
5
+ )
6
+
7
+ import logging
8
+ from regscale.core.app.logz import create_logger
9
+
10
+
11
+ class CaptureEventsHandler:
12
+ def __init__(self, events, errors, infos):
13
+ self.handler = logging.Handler()
14
+ self.events = events
15
+ self.errors = errors
16
+ self.infos = infos
17
+
18
+ def emit(self, record):
19
+ self.handler.emit(record)
20
+ try:
21
+ log_entry = self.handler.format(record)
22
+ if record.levelname == "INFO":
23
+ self.events.append(log_entry)
24
+ elif record.levelname == "ERROR":
25
+ self.errors.append(log_entry)
26
+ except Exception:
27
+ self.handler.handleError(record)
28
+
29
+
30
+ class SSPLogger:
31
+ def __init__(self):
32
+ self.events = []
33
+ self.errors = []
34
+ self.infos = []
35
+ self.capture_handler = CaptureEventsHandler(self.events, self.errors, self.infos)
36
+ self.logger = create_logger(custom_handler=self.capture_handler)
37
+
38
+ def create_logger(self):
39
+ return self.logger
40
+
41
+ def info(self, event_msg: str, record_type: str = "", model_layer: str = ""):
42
+ self.logger.info(event_msg)
43
+ info = {
44
+ "event_msg": event_msg,
45
+ "record_type": record_type,
46
+ "model_layer": model_layer,
47
+ }
48
+ self.infos.append(log_event(**info, level="Info"))
49
+
50
+ def debug(self, msg, *args, **kwargs):
51
+ self.logger.debug(msg, *args, **kwargs)
52
+
53
+ def error(
54
+ self,
55
+ event_msg: str,
56
+ record_type: str = "",
57
+ model_layer: str = "",
58
+ missing_element: str = "",
59
+ ):
60
+ self.logger.error(event_msg)
61
+ error = {
62
+ "event_msg": event_msg,
63
+ "missing_element": missing_element,
64
+ "record_type": record_type,
65
+ "model_layer": model_layer,
66
+ }
67
+ self.errors.append(log_error(**error, level="Error"))
68
+
69
+ def warning(self, event_msg: str, record_type: str = "", model_layer: str = ""):
70
+ self.logger.warning(event_msg)
71
+ warning = {
72
+ "event_msg": event_msg,
73
+ "record_type": record_type,
74
+ "model_layer": model_layer,
75
+ }
76
+ self.infos.append(log_event(**warning, level="Warning"))
77
+
78
+ def get_events(self):
79
+ return self.events
80
+
81
+ def get_errors(self):
82
+ return self.errors
83
+
84
+ def write_events(self):
85
+ # Write the events.
86
+ final_list = [*self.events, *self.errors, *self.infos]
87
+ write_events(final_list)