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,922 @@
1
+ """
2
+ System Characteristics are a Model Layer in the OSCAL SSP implementation model. The
3
+ model is documented at https://pages.nist.gov/OSCAL/concepts/layer/implementation/ssp/
4
+ Note that the RegScale SSP Data model collapses several NIST OSCAL model layers together
5
+ including Metadata, System Characteristics, and System Implementation.
6
+ """
7
+
8
+ import json
9
+ from json import JSONDecodeError
10
+ from typing import List, Optional, Union
11
+
12
+ from lxml.etree import Element
13
+ from pydantic import ValidationError
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.integrations.public.fedramp.reporting import log_error, log_event
19
+ from regscale.integrations.public.fedramp.resources import parse_backmatter
20
+ from regscale.integrations.public.fedramp.xml_utils import update_ssp
21
+
22
+ # flake8: noqa: C901
23
+ from regscale.models import SecurityPlan
24
+
25
+ logger = create_logger()
26
+ SYSTEM_CHARS = "System Characteristics"
27
+ SYSTEM_INFO = "System Information"
28
+
29
+ CAT_MAPPING = [
30
+ ("fips-199-low", "Low"),
31
+ ("fips-199-moderate", "Moderate"),
32
+ ("fips-199-high", "High"),
33
+ ]
34
+
35
+ LEVEL_MAPPING = [
36
+ ("1", "Low"),
37
+ ("2", "Moderate"),
38
+ ("3", "High"),
39
+ ]
40
+
41
+ FR_AUTH_MAPPING = [
42
+ ("fedramp-jab", "Joint Authorization Board (JAB)"),
43
+ ("fedramp-agency", "Agency Authorization"),
44
+ ("fedramp-li-saas", "Low Impact SaaS"),
45
+ ]
46
+
47
+ STATUS_MAPPING = [
48
+ ("operational", "Operational"),
49
+ ("under-development", "Under Development"),
50
+ ("under-major-modification", "Undergoing a Major Modification"),
51
+ ]
52
+
53
+
54
+ def get_compliance_settings_id() -> int:
55
+ # TODO: Move to REG-13149
56
+ """
57
+ Return the Compliance Settings ID for FedRAMP
58
+
59
+ :return: Compliance Setting ID
60
+ :rtype: int
61
+ """
62
+ from regscale.models.regscale_models.compliance_settings import ComplianceSettings
63
+
64
+ try:
65
+ fedramp_comp = next(
66
+ comp.id for comp in ComplianceSettings.get_by_current_tenant() if comp.title == "FedRAMP Compliance Setting"
67
+ )
68
+ except (StopIteration, JSONDecodeError):
69
+ # Handle the case where the Compliance Setting ID is not found or the RegScale version is not compatible
70
+ logger.warning("Unable to find Compliance Setting ID, defaulting to 1.")
71
+ fedramp_comp = 1
72
+ return fedramp_comp
73
+
74
+
75
+ def parse_minimum_ssp(
76
+ api: Api,
77
+ root: Element,
78
+ events_list: Optional[list] = None,
79
+ new_ssp: Optional[dict] = None,
80
+ ns: Optional[dict] = None,
81
+ ) -> Union[str, int]:
82
+ """The objective of this function is to parse the elements needed for an initial POST to create and return a new
83
+ SSP ID. The SSP ID can then be later used to update the SSP with additional information in a PUT operation, or to
84
+ provide the necessary ParentID for database records that require the SSP ID as a foreign key.
85
+
86
+ :param Api api: RegScale API object
87
+ :param Element root: lxml root Element from SSP
88
+ :param Optional[list] events_list: list to be populated with parsed data
89
+ :param Optional[dict] new_ssp: dict to be populated with parsed data
90
+ :param Optional[dict] ns: namespace dict
91
+ :return: SSP ID
92
+ :rtype: Union[str, int]
93
+ """
94
+ app = Application()
95
+ properties_list = [] # track any properties collected during this time
96
+ fedrampId = root.xpath(
97
+ '/*/ns1:system-characteristics/ns1:system-id[@identifier-type="https://fedramp.gov"]',
98
+ namespaces=ns,
99
+ )
100
+ if len(fedrampId) == 0:
101
+ events_list.append(
102
+ log_error(
103
+ record_type="FedRAMP ID",
104
+ missing_element="FedRAMP ID",
105
+ model_layer=SYSTEM_CHARS,
106
+ )
107
+ )
108
+ else:
109
+ new_ssp["fedrampId"] = fedrampId[0].text
110
+ events_list.append(
111
+ log_event(
112
+ record_type="FedRAMP ID",
113
+ model_layer=SYSTEM_CHARS,
114
+ event_msg=f'Found FedRAMP-assigned identifier: {new_ssp["fedrampId"]}',
115
+ )
116
+ )
117
+ #
118
+ xpath_query = "/*/ns1:system-characteristics/ns1:system-id"
119
+ additional_identifiers = root.xpath(xpath_query, namespaces=ns)
120
+ for additional_identifier in additional_identifiers:
121
+ try:
122
+ if additional_identifier.attrib["identifier-type"] != "https://fedramp.gov":
123
+ property_ = {
124
+ "key": "identifier-type=" + additional_identifier.attrib["identifier-type"],
125
+ "value": additional_identifier.text,
126
+ "label": "Other System ID",
127
+ "otherAttributes": xpath_query.replace("ns1:", "{http://csrc.nist.gov/ns/oscal/1.0}"),
128
+ }
129
+ properties_list.append(property_)
130
+ events_list.append(
131
+ log_event(
132
+ record_type="System Identifier",
133
+ model_layer=SYSTEM_CHARS,
134
+ event_msg=f'Additional System ID detected & recorded as Property: {property_["value"]}',
135
+ )
136
+ )
137
+ except Exception as e:
138
+ logger.error(e)
139
+ events_list.append(
140
+ log_error(
141
+ missing_element=additional_identifier.tag,
142
+ record_type="Property",
143
+ model_layer=SYSTEM_CHARS,
144
+ event_msg=f"Problem importing Additional System ID {additional_identifier.text}",
145
+ )
146
+ )
147
+
148
+ #
149
+ other_identifier = root.xpath("/*/ns1:system-characteristics/ns1:system-name-short", namespaces=ns)
150
+ if len(other_identifier) == 0:
151
+ events_list.append(
152
+ log_error(
153
+ record_type=SYSTEM_INFO,
154
+ missing_element="System Short Name",
155
+ model_layer=SYSTEM_CHARS,
156
+ )
157
+ )
158
+ else:
159
+ new_ssp["otherIdentifier"] = other_identifier[0].text
160
+ events_list.append(
161
+ log_event(
162
+ record_type="System Short Name",
163
+ event_msg=f'System Short Name identified as {new_ssp["otherIdentifier"]}',
164
+ model_layer=SYSTEM_CHARS,
165
+ )
166
+ )
167
+ #
168
+ description = root.xpath("/*/ns1:system-characteristics/ns1:description", namespaces=ns)
169
+ if len(description) == 0:
170
+ events_list.append(
171
+ log_error(
172
+ record_type=SYSTEM_INFO,
173
+ missing_element="System Description",
174
+ model_layer=SYSTEM_CHARS,
175
+ )
176
+ )
177
+ else:
178
+ # TODO: This needs the text collapsing function that Joshua is working on.
179
+ # new_ssp["description"] = extract_markup_content(description[0])
180
+ new_ssp["description"] = ""
181
+ for p in description[0].findall("ns1:p", namespaces=ns):
182
+ new_ssp["description"] = new_ssp["description"] + p.text + " "
183
+ events_list.append(
184
+ log_event(
185
+ record_type=SYSTEM_INFO,
186
+ event_msg=f'System description recorded: {new_ssp["description"][:30]}... ',
187
+ model_layer=SYSTEM_CHARS,
188
+ )
189
+ )
190
+ #
191
+ fedrampAuthorizationType = root.xpath(
192
+ '/*/ns1:system-characteristics/ns1:prop[@name="authorization-type"][@ns="https://fedramp.gov/ns/oscal"]',
193
+ namespaces=ns,
194
+ )
195
+ if len(fedrampAuthorizationType) == 0:
196
+ events_list.append(
197
+ log_error(
198
+ record_type=SYSTEM_INFO,
199
+ missing_element="FedRAMP Authorization Type",
200
+ model_layer=SYSTEM_CHARS,
201
+ )
202
+ )
203
+ else:
204
+ new_ssp["fedrampAuthorizationType"] = apply_mapping(
205
+ FR_AUTH_MAPPING, fedrampAuthorizationType[0].attrib["value"]
206
+ )
207
+ events_list.append(
208
+ log_event(
209
+ record_type=SYSTEM_INFO,
210
+ event_msg=f'FedRAMP Authorization Type: {new_ssp["fedrampAuthorizationType"]}',
211
+ model_layer=SYSTEM_CHARS,
212
+ )
213
+ )
214
+ #
215
+ authenticationLevel = root.xpath(
216
+ '/*/ns1:system-characteristics/ns1:prop[@name="security-eauth-level"][@class="security-eauth"]',
217
+ namespaces=ns,
218
+ )
219
+ if len(authenticationLevel) == 0:
220
+ events_list.append(
221
+ log_error(
222
+ record_type=SYSTEM_INFO,
223
+ missing_element="FedRAMP Authentication Level",
224
+ model_layer=SYSTEM_CHARS,
225
+ )
226
+ )
227
+ else:
228
+ new_ssp["authenticationLevel"] = apply_mapping(LEVEL_MAPPING, authenticationLevel[0].attrib["value"])
229
+ events_list.append(
230
+ log_event(
231
+ record_type=SYSTEM_INFO,
232
+ event_msg=f'FedRAMP Authentication Level: {new_ssp["authenticationLevel"]}',
233
+ model_layer=SYSTEM_CHARS,
234
+ )
235
+ )
236
+ #
237
+ identityAssuranceLevel = root.xpath(
238
+ '/*/ns1:system-characteristics/ns1:prop[@name="identity-assurance-level"]/@value',
239
+ namespaces=ns,
240
+ )
241
+ if len(identityAssuranceLevel) == 0:
242
+ events_list.append(
243
+ log_error(
244
+ record_type=SYSTEM_INFO,
245
+ missing_element="FedRAMP Identity Assurance Level",
246
+ model_layer=SYSTEM_CHARS,
247
+ )
248
+ )
249
+ else:
250
+ new_ssp["identityAssuranceLevel"] = apply_mapping(LEVEL_MAPPING, identityAssuranceLevel[0])
251
+ events_list.append(
252
+ log_event(
253
+ record_type=SYSTEM_INFO,
254
+ event_msg=f'FedRAMP Identity Assurance Level: {new_ssp["identityAssuranceLevel"]}',
255
+ model_layer=SYSTEM_CHARS,
256
+ )
257
+ )
258
+ #
259
+ authenticatorAssuranceLevel = root.xpath(
260
+ '/*/ns1:system-characteristics/ns1:prop[@name="authenticator-assurance-level"]/@value',
261
+ namespaces=ns,
262
+ )
263
+ if len(authenticatorAssuranceLevel) == 0:
264
+ events_list.append(
265
+ log_error(
266
+ record_type=SYSTEM_INFO,
267
+ missing_element="FedRAMP Authenticator Assurance Level",
268
+ model_layer=SYSTEM_CHARS,
269
+ )
270
+ )
271
+ else:
272
+ new_ssp["authenticatorAssuranceLevel"] = apply_mapping(LEVEL_MAPPING, identityAssuranceLevel[0])
273
+ events_list.append(
274
+ log_event(
275
+ record_type=SYSTEM_INFO,
276
+ event_msg=f'FedRAMP Authenticator Assurance Level: {new_ssp["authenticatorAssuranceLevel"]}',
277
+ model_layer=SYSTEM_CHARS,
278
+ )
279
+ )
280
+ #
281
+ federationAssuranceLevel = root.xpath(
282
+ '/*/ns1:system-characteristics/ns1:prop[@name="federation-assurance-level"]/@value',
283
+ namespaces=ns,
284
+ )
285
+ if len(federationAssuranceLevel) == 0:
286
+ events_list.append(
287
+ log_error(
288
+ record_type=SYSTEM_INFO,
289
+ missing_element="FedRAMP Federation Assurance Level",
290
+ model_layer=SYSTEM_CHARS,
291
+ )
292
+ )
293
+ else:
294
+ new_ssp["federationAssuranceLevel"] = apply_mapping(LEVEL_MAPPING, federationAssuranceLevel[0])
295
+ events_list.append(
296
+ log_event(
297
+ record_type=SYSTEM_INFO,
298
+ event_msg=f'FedRAMP Federation Assurance Level: {new_ssp["federationAssuranceLevel"]}',
299
+ model_layer=SYSTEM_CHARS,
300
+ )
301
+ )
302
+
303
+ #
304
+ system_name = root.xpath("/*/ns1:system-characteristics/ns1:system-name", namespaces=ns)
305
+ if len(system_name) == 0:
306
+ events_list.append(
307
+ log_error(
308
+ record_type=SYSTEM_INFO,
309
+ missing_element="System Name",
310
+ model_layer=SYSTEM_CHARS,
311
+ )
312
+ )
313
+ new_ssp["systemName"] = "Cloud Service Provider System" # FAILSAFE W/ DUMMY DATA FOR REQUIRED VALUES
314
+ else:
315
+ new_ssp["systemName"] = system_name[0].text
316
+ events_list.append(
317
+ log_event(
318
+ record_type="System Name",
319
+ event_msg=f'System Name identified as {new_ssp["systemName"]}',
320
+ model_layer=SYSTEM_CHARS,
321
+ )
322
+ )
323
+ #
324
+ new_ssp["confidentiality"] = "Low" # default value
325
+ confidentiality = root.xpath(
326
+ "/*/ns1:system-characteristics/ns1:security-impact-level/ns1:security-objective-confidentiality",
327
+ namespaces=ns,
328
+ )
329
+ if len(confidentiality) == 0:
330
+ events_list.append(
331
+ log_error(
332
+ record_type=SYSTEM_INFO,
333
+ missing_element="Security Objective (Confidentiality) ",
334
+ model_layer=SYSTEM_CHARS,
335
+ )
336
+ )
337
+ else:
338
+ new_ssp["confidentiality"] = apply_mapping(CAT_MAPPING, confidentiality[0].text)
339
+ events_list.append(
340
+ log_event(
341
+ record_type=SYSTEM_INFO,
342
+ event_msg=f'Recorded System Security Confidentiality: {new_ssp["confidentiality"]}',
343
+ model_layer=SYSTEM_CHARS,
344
+ )
345
+ )
346
+ #
347
+ new_ssp["integrity"] = "Low" # default value
348
+ integrity = root.xpath(
349
+ "/*/ns1:system-characteristics/ns1:security-impact-level/ns1:security-objective-integrity",
350
+ namespaces=ns,
351
+ )
352
+ if len(integrity) == 0:
353
+ events_list.append(
354
+ log_error(
355
+ record_type=SYSTEM_INFO,
356
+ missing_element="Security Objective (Integrity) ",
357
+ model_layer=SYSTEM_CHARS,
358
+ )
359
+ )
360
+ else:
361
+ new_ssp["integrity"] = apply_mapping(CAT_MAPPING, integrity[0].text)
362
+ events_list.append(
363
+ log_event(
364
+ record_type=SYSTEM_INFO,
365
+ event_msg=f'Recorded System Security Integrity: {new_ssp["integrity"]}',
366
+ model_layer=SYSTEM_CHARS,
367
+ )
368
+ )
369
+ #
370
+ new_ssp["availability"] = "Low" # default value
371
+ availability = root.xpath(
372
+ "/*/ns1:system-characteristics/ns1:security-impact-level/ns1:security-objective-availability",
373
+ namespaces=ns,
374
+ )
375
+ if len(availability) == 0:
376
+ events_list.append(
377
+ log_error(
378
+ record_type=SYSTEM_INFO,
379
+ missing_element="Security Objective (Availability) ",
380
+ model_layer=SYSTEM_CHARS,
381
+ )
382
+ )
383
+ else:
384
+ new_ssp["availability"] = apply_mapping(CAT_MAPPING, availability[0].text)
385
+ events_list.append(
386
+ log_event(
387
+ record_type=SYSTEM_INFO,
388
+ event_msg=f'Recorded System Security Availability: {new_ssp["availability"]}',
389
+ model_layer=SYSTEM_CHARS,
390
+ )
391
+ )
392
+ #
393
+ new_ssp["overallCategorization"] = "Low" # default value
394
+ overall_categorization = root.xpath("/*/ns1:system-characteristics/ns1:security-sensitivity-level", namespaces=ns)
395
+ if len(overall_categorization) == 0:
396
+ events_list.append(
397
+ log_error(
398
+ record_type=SYSTEM_INFO,
399
+ missing_element="Security Objective (Overall Categorization) ",
400
+ model_layer=SYSTEM_CHARS,
401
+ )
402
+ )
403
+ else:
404
+ new_ssp["overallCategorization"] = apply_mapping(CAT_MAPPING, overall_categorization[0].text)
405
+ events_list.append(
406
+ log_event(
407
+ record_type=SYSTEM_INFO,
408
+ event_msg=f'Recorded System Security Overall Categorization: {new_ssp["overallCategorization"]}',
409
+ model_layer=SYSTEM_CHARS,
410
+ )
411
+ )
412
+ #
413
+ new_ssp["status"] = "Operational" # default value
414
+ status = root.xpath("/*/ns1:system-characteristics/ns1:status", namespaces=ns)
415
+ if len(status) == 0:
416
+ events_list.append(
417
+ log_error(
418
+ record_type=SYSTEM_INFO,
419
+ missing_element="System Operating Status",
420
+ model_layer=SYSTEM_CHARS,
421
+ )
422
+ )
423
+ else:
424
+ new_ssp["status"] = apply_mapping(STATUS_MAPPING, status[0].attrib["state"])
425
+ events_list.append(
426
+ log_event(
427
+ record_type=SYSTEM_INFO,
428
+ event_msg=f'System Operating status detected: {new_ssp["status"]}',
429
+ model_layer=SYSTEM_CHARS,
430
+ )
431
+ )
432
+ status_remarks = root.xpath("/*/ns1:system-characteristics/ns1:status/ns1:remarks", namespaces=ns)
433
+ if len(status_remarks) > 0:
434
+ new_ssp["explanationForNonOperational"] = ""
435
+ for p in status_remarks[0].findall("ns1:p", namespaces=ns):
436
+ new_ssp["explanationForNonOperational"] = new_ssp["explanationForNonOperational"] + p.text + " "
437
+ #
438
+ # CLOUD SERVICE MODELS
439
+ new_ssp["bModelSaaS"] = root.xpath(
440
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-service-model'][@value='saas']",
441
+ namespaces=ns,
442
+ )
443
+ if len(new_ssp["bModelSaaS"]) == 0:
444
+ new_ssp["bModelSaaS"] = False
445
+ else:
446
+ new_ssp["bModelSaaS"] = True
447
+ #
448
+ new_ssp["bModelPaaS"] = root.xpath(
449
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-service-model'][@value='paas']",
450
+ namespaces=ns,
451
+ )
452
+ if len(new_ssp["bModelPaaS"]) == 0:
453
+ new_ssp["bModelPaaS"] = False
454
+ else:
455
+ new_ssp["bModelPaaS"] = True
456
+ #
457
+ new_ssp["bModelIaaS"] = root.xpath(
458
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-service-model'][@value='iaas']",
459
+ namespaces=ns,
460
+ )
461
+ if len(new_ssp["bModelIaaS"]) == 0:
462
+ new_ssp["bModelIaaS"] = False
463
+ else:
464
+ new_ssp["bModelIaaS"] = True
465
+ #
466
+ new_ssp["bModelOther"] = root.xpath(
467
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-service-model'][@value='other']",
468
+ namespaces=ns,
469
+ )
470
+ if len(new_ssp["bModelOther"]) == 0:
471
+ new_ssp["bModelOther"] = False
472
+ else:
473
+ new_ssp["bModelOther"] = True
474
+ #
475
+ remarks = root.xpath(
476
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-service-model'][@value='other']/ns1:remarks",
477
+ namespaces=ns,
478
+ )
479
+ if len(remarks) == 0:
480
+ pass
481
+ else:
482
+ new_ssp["OtherModelRemarks"] = ""
483
+ for p in remarks[0].findall("ns1:p", namespaces=ns):
484
+ new_ssp["OtherModelRemarks"] = new_ssp["OtherModelRemarks"] + p.text + " "
485
+
486
+ # CLOUD DEPLOYMENTS
487
+
488
+ new_ssp["bDeployPublic"] = root.xpath(
489
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-deployment-model'][@value='public-cloud']",
490
+ namespaces=ns,
491
+ )
492
+ if len(new_ssp["bDeployPublic"]) == 0:
493
+ new_ssp["bDeployPublic"] = False
494
+ else:
495
+ new_ssp["bDeployPublic"] = True
496
+ #
497
+ new_ssp["bDeployPrivate"] = root.xpath(
498
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-deployment-model'][@value='private-cloud']",
499
+ namespaces=ns,
500
+ )
501
+ if len(new_ssp["bDeployPrivate"]) == 0:
502
+ new_ssp["bDeployPrivate"] = False
503
+ else:
504
+ new_ssp["bDeployPrivate"] = True
505
+ #
506
+ new_ssp["bDeployGov"] = root.xpath(
507
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-deployment-model'][@value='government-only-cloud']",
508
+ namespaces=ns,
509
+ )
510
+ if len(new_ssp["bDeployGov"]) == 0:
511
+ new_ssp["bDeployGov"] = False
512
+ else:
513
+ new_ssp["bDeployGov"] = True
514
+ #
515
+ new_ssp["bDeployHybrid"] = root.xpath(
516
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-deployment-model'][@value='hybrid-cloud']",
517
+ namespaces=ns,
518
+ )
519
+ if len(new_ssp["bDeployHybrid"]) == 0:
520
+ new_ssp["bDeployHybrid"] = False
521
+ else:
522
+ new_ssp["bDeployHybrid"] = True
523
+ #
524
+ new_ssp["bDeployOther"] = root.xpath(
525
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-deployment-model'][@value='other-cloud']",
526
+ namespaces=ns,
527
+ )
528
+ if len(new_ssp["bDeployOther"]) == 0:
529
+ new_ssp["bDeployOther"] = False
530
+ else:
531
+ new_ssp["bDeployOther"] = True
532
+ #
533
+ remarks = root.xpath(
534
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:prop[@name='cloud-service-model'][@value='other']/ns1:remarks",
535
+ namespaces=ns,
536
+ )
537
+ if len(remarks) == 0:
538
+ pass
539
+ else:
540
+ new_ssp["DeployOtherRemarks"] = ""
541
+ for p in remarks[0].findall("ns1:p", namespaces=ns):
542
+ new_ssp["DeployOtherRemarks"] = new_ssp["DeployOtherRemarks"] + p.text + " "
543
+ # TODO: This RegScale value doesn't seem to have a FedRAMP counterpart. Confirm w/ Travis or Dale
544
+ new_ssp["systemType"] = "Major Application"
545
+ new_ssp["systemOwnerId"] = app.config["userId"]
546
+ from regscale.utils.version import RegscaleVersion
547
+ from packaging.version import Version
548
+
549
+ regscale_version = RegscaleVersion.get_platform_version()
550
+ if len(regscale_version) >= 10 or Version(regscale_version) >= Version("6.13.0.0"):
551
+ new_ssp["complianceSettingsId"] = get_compliance_settings_id()
552
+ ssp_id = post_SSP(api, new_ssp)
553
+ return ssp_id
554
+
555
+
556
+ def parse_system_characteristics(
557
+ ssp_id: Union[int, str], root: Element, events_list: Optional[list] = None, ns: Optional[dict] = None
558
+ ):
559
+ """Parse system characteristics from OSCAL SSP XML to RegScale SSP JSON
560
+
561
+ :param Union[int, str] ssp_id: The ID of the SSP to be updated
562
+ :param Element root: lxml root Element from SSP
563
+ :param Optional[list] events_list: list to be populated with parsed data, defaults to None
564
+ :param Optional[dict] ns: namespace dict, defaults to None
565
+ """
566
+
567
+ ssp_updates = {} # store any key value pairs to update SSP with
568
+
569
+ # Information / Classification Types
570
+ information_types = root.xpath(
571
+ "/*/ns1:system-characteristics/ns1:system-information/ns1:information-type",
572
+ namespaces=ns,
573
+ )
574
+ if len(information_types) == 0:
575
+ events_list.append(
576
+ log_error(
577
+ record_type="Information Types",
578
+ missing_element="At least one Information Type",
579
+ model_layer=SYSTEM_CHARS,
580
+ )
581
+ )
582
+ else:
583
+ parse_classificationType(information_types, ns, events_list, ssp_id)
584
+
585
+ # Privacy Impact Assessment
586
+ # TODO: Doesn't seem to be a RegScale counterpart for <prop name="privacy-sensitive" value="yes"/> - confirm w/ SME
587
+ parse_privacy(root=root, ns=ns, events_list=events_list, ssp_id=ssp_id)
588
+
589
+ # SYSTEM DESCRIPTION
590
+ authorizationBoundary = root.xpath(
591
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:authorization-boundary/ns1:description",
592
+ namespaces=ns,
593
+ )
594
+ if len(authorizationBoundary) > 0:
595
+ ssp_updates["authorizationBoundary"] = ""
596
+ for p in authorizationBoundary[0].findall("ns1:p", namespaces=ns):
597
+ if p.text:
598
+ ssp_updates["authorizationBoundary"] = ssp_updates["authorizationBoundary"] + p.text + " "
599
+ events_list.append(
600
+ log_event(
601
+ model_layer=SYSTEM_CHARS,
602
+ record_type=SYSTEM_INFO,
603
+ event_msg="Authorization Boundary recorded.",
604
+ )
605
+ )
606
+ else:
607
+ events_list.append(
608
+ log_error(
609
+ model_layer=SYSTEM_CHARS,
610
+ record_type=SYSTEM_INFO,
611
+ missing_element="Auth. Boundary Description",
612
+ )
613
+ )
614
+
615
+ # check if there is back-matter
616
+ if back_matter := root.find(".//ns1:back-matter", namespaces=ns):
617
+ # get the resources
618
+ resources = back_matter.findall(".//ns1:resource", namespaces=ns)
619
+ results = parse_backmatter(
620
+ resource_elem=resources,
621
+ back_matter=back_matter,
622
+ root=root,
623
+ ns=ns,
624
+ ssp_id=ssp_id,
625
+ events_list=events_list,
626
+ )
627
+ event_msg = (
628
+ f"Created {results['linksCreated']} new link(s), created "
629
+ f"{results['referencesCreated']} reference(s), and uploaded "
630
+ f"{results['filesUploaded']} file(s) in RegScale."
631
+ )
632
+ events_list.append(
633
+ log_event(
634
+ record_type="Back Matter",
635
+ event_msg=event_msg,
636
+ model_layer="Back Matter",
637
+ )
638
+ )
639
+ else:
640
+ events_list.append(
641
+ log_error(
642
+ model_layer=SYSTEM_CHARS,
643
+ record_type=SYSTEM_INFO,
644
+ missing_element="back-matter",
645
+ )
646
+ )
647
+
648
+ network_architecture = (
649
+ root.xpath(
650
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:network-architecture/ns1:description",
651
+ namespaces=ns,
652
+ )
653
+ or []
654
+ )
655
+
656
+ if len(network_architecture) > 0:
657
+ ssp_updates["networkArchitecture"] = ""
658
+ for p in network_architecture[0].findall("ns1:p", namespaces=ns):
659
+ if p.text:
660
+ ssp_updates["networkArchitecture"] = ssp_updates["networkArchitecture"] + p.text + " "
661
+ events_list.append(
662
+ log_event(
663
+ model_layer=SYSTEM_CHARS,
664
+ record_type=SYSTEM_INFO,
665
+ event_msg="Network Architecture description recorded.",
666
+ )
667
+ )
668
+ else:
669
+ events_list.append(
670
+ log_error(
671
+ model_layer=SYSTEM_CHARS,
672
+ record_type=SYSTEM_INFO,
673
+ missing_element="Network Architecture",
674
+ )
675
+ )
676
+ #
677
+ dataFlow = root.xpath(
678
+ "/ns1:system-security-plan/ns1:system-characteristics/ns1:data-flow/ns1:description",
679
+ namespaces=ns,
680
+ )
681
+ if len(dataFlow) > 0:
682
+ ssp_updates["dataFlow"] = ""
683
+ for p in dataFlow[0].findall("ns1:p", namespaces=ns):
684
+ if p.text:
685
+ ssp_updates["dataFlow"] = ssp_updates["dataFlow"] + p.text + " "
686
+ events_list.append(
687
+ log_event(
688
+ model_layer=SYSTEM_CHARS,
689
+ record_type=SYSTEM_INFO,
690
+ event_msg="Data Flow description recorded.",
691
+ )
692
+ )
693
+ else:
694
+ events_list.append(
695
+ log_error(
696
+ model_layer=SYSTEM_CHARS,
697
+ record_type=SYSTEM_INFO,
698
+ missing_element="Data Flow",
699
+ )
700
+ )
701
+
702
+ update_ssp(ssp_updates, ssp_id)
703
+
704
+ # properties such as authorization type will be mapped to regscale counterparts, where applicable, but will also be
705
+ # stored as properties for consistency in export.
706
+ # if Export team needs these NOT to be recorded in properties. that can be arranged. Export could just choose
707
+ # to check if a property already exists before adding it, however, which would avoid potential for duplication on export
708
+ """
709
+ else: # if none of these other condit`ions are met, store as a custom property
710
+ ancestry = ''
711
+ for parent in prop.parents:
712
+ ancestry = ancestry + '/' + parent.name
713
+ property_ = {}
714
+ property_['key'] = prop.attrs['name']
715
+ property_['value'] = prop.attrs['value']
716
+ property_['label'] = 'Custom Property'
717
+ property_['otherAttributes'] = ancestry + str(prop)
718
+ properties_list.append(property_)
719
+ """
720
+
721
+
722
+ def apply_mapping(mapping: List[tuple], value: str) -> str:
723
+ """
724
+ Apply a mapping to a value
725
+
726
+ :param List[tuple] mapping: List of mapping pair tuples - (original,new)
727
+ :param str value: Thing to be mapped to a new value
728
+ :return: New value
729
+ :rtype: str
730
+ """
731
+ for original, new in mapping:
732
+ if value == original:
733
+ value = new
734
+ break
735
+ return value
736
+
737
+
738
+ def post_SSP(api: Api, new_ssp: dict):
739
+ """Create the initial SSP"""
740
+ app = Application()
741
+ headers_json = {
742
+ "accept": "*/*",
743
+ "Content-Type": "application/json-patch+json",
744
+ "Authorization": app.config["token"],
745
+ }
746
+ # If data is incomplete This fails w/ 500 error ( which means the json string being received by the server is either malformed or missing something
747
+ logger.info("Uploading SSP to RegScale...")
748
+ try:
749
+ ssp = SecurityPlan(**new_ssp)
750
+ except ValidationError as exc:
751
+ logger.error(f"Failed to validate: {exc}")
752
+ return "artifacts/import-results.csv", {
753
+ "status": "failed",
754
+ }
755
+
756
+ if new_ssp := ssp.create():
757
+ new_ssp_id = new_ssp.id
758
+ else:
759
+ new_ssp_id = None
760
+ logger.debug(new_ssp_id)
761
+
762
+ if not new_ssp_id:
763
+ # This generally succeeds if the ssp failed to pass pydantic check for required values in securityplans module
764
+ logger.warning("Some required data may have failed to be imported. Trying to upload SSP with incomplete data ")
765
+ import json
766
+
767
+ dat = {}
768
+ response = api.post(
769
+ url=app.config["domain"] + "/api/securityplans",
770
+ json=new_ssp,
771
+ )
772
+ logger.debug(response.status_code)
773
+ if not response.raise_for_status():
774
+ dat = response.json()
775
+ if "id" in dat:
776
+ new_ssp_id = dat["id"]
777
+
778
+ return new_ssp_id
779
+
780
+
781
+ def parse_classificationType(information_types, ns, events_list, ssp_id):
782
+ """Information Types in FedRAMP language correspond to Classification Types in RegScale, and are stored in the
783
+ ClassificationTypes table. . Classification/Information Types are created in the 'Setup' portion of the RegScale app
784
+ & at the Tenant level. Classification/Information types are then associated with an individual SSP through the
785
+ 'Subsystems' menu. The mapping between a Classification/Information type and the SSP is stored in the
786
+ ClassifiedRecords database table."""
787
+
788
+ # TODO: There currently isn't capability to track the base vs selected & adjustment reason, or categ. system
789
+ for information_type in information_types:
790
+ classificationType_dict = {}
791
+ classificationType_dict["uuid"] = information_type.attrib["uuid"]
792
+ # start with default values to avoid breaking on import
793
+ classificationType_dict["title"] = "Name of Information Type"
794
+ classificationType_dict["description"] = ""
795
+ classificationType_dict["confidentiality"] = "Low"
796
+ classificationType_dict["integrity"] = "Low"
797
+ classificationType_dict["availability"] = "Low"
798
+ if information_type.find("ns1:title", namespaces=ns) is not None:
799
+ classificationType_dict["title"] = information_type.find("ns1:title", namespaces=ns).text
800
+ if information_type.find("ns1:description", namespaces=ns) is not None:
801
+ for p in information_type.find("ns1:description", namespaces=ns).findall("ns1:p", namespaces=ns):
802
+ classificationType_dict["description"] = classificationType_dict["description"] + p.text + " "
803
+ if information_type.find("ns1:confidentiality-impact/ns1:selected", namespaces=ns) is not None:
804
+ classificationType_dict["confidentiality"] = apply_mapping(
805
+ CAT_MAPPING,
806
+ information_type.find("ns1:confidentiality-impact/ns1:selected", namespaces=ns).text,
807
+ )
808
+ if information_type.find("ns1:integrity-impact/ns1:selected", namespaces=ns) is not None:
809
+ classificationType_dict["integrity"] = apply_mapping(
810
+ CAT_MAPPING,
811
+ information_type.find("ns1:integrity-impact/ns1:selected", namespaces=ns).text,
812
+ )
813
+ if information_type.find("ns1:availability-impact/ns1:selected", namespaces=ns) is not None:
814
+ classificationType_dict["availability"] = apply_mapping(
815
+ CAT_MAPPING,
816
+ information_type.find("ns1:availability-impact/ns1:selected", namespaces=ns).text,
817
+ )
818
+ classification_type_id = upload_classificationType(classificationType_dict, ssp_id)
819
+ if classification_type_id:
820
+ events_list.append(
821
+ log_event(
822
+ record_type="Information Type",
823
+ model_layer=SYSTEM_CHARS,
824
+ event_msg=f'Recorded Information Type for: {classificationType_dict["title"]}',
825
+ )
826
+ )
827
+ else:
828
+ events_list.append(
829
+ log_error(
830
+ record_type="Information Type",
831
+ model_layer=SYSTEM_CHARS,
832
+ missing_element="Information Type",
833
+ event_msg='Failed to post Information Type for {classificationType_dict["title"]}.',
834
+ )
835
+ )
836
+
837
+
838
+ def upload_classificationType(classificationType_dict, ssp_id):
839
+ app = Application()
840
+ api = Api()
841
+ headers_json = {
842
+ "accept": "*/*",
843
+ "Content-Type": "application/json-patch+json",
844
+ "Authorization": app.config["token"],
845
+ }
846
+ ssp_classification = json.dumps(classificationType_dict)
847
+ response = api.post(
848
+ url=app.config["domain"] + "/api/classificationTypes",
849
+ data=ssp_classification,
850
+ headers=headers_json,
851
+ )
852
+ if response.status_code == 200: # If successfully upload classification type, then add mapping to SSP
853
+ classifiedRecords_entry = {}
854
+ classifiedRecords_entry["classificationTypeId"] = json.loads(response.content)["id"]
855
+ classifiedRecords_entry["parentRecordId"] = ssp_id
856
+ classifiedRecords_entry["parentModule"] = "securityplans"
857
+ classifiedRecord_json = json.dumps(classifiedRecords_entry)
858
+ response = api.post(
859
+ url=app.config["domain"] + "/api/classifiedRecords",
860
+ data=classifiedRecord_json,
861
+ headers=headers_json,
862
+ )
863
+ if response.status_code == 200:
864
+ return "Success"
865
+ else:
866
+ return None
867
+ else:
868
+ return None
869
+
870
+
871
+ def parse_privacy(root, events_list, ns, ssp_id):
872
+ "Privacy Impact Assessment pertains to the Privacy tab of RegScale Application and the Privacy database table."
873
+ try:
874
+ privacyImpactAssessment = {}
875
+ privacyImpactAssessment["piiCollection"] = root.xpath(
876
+ '/*/ns1:system-characteristics/ns1:system-information/ns1:prop[@name="pta-1"][@ns="https://fedramp.gov/ns/oscal"]/@value',
877
+ namespaces=ns,
878
+ )[0].capitalize()
879
+ privacyImpactAssessment["piiPublicCollection"] = root.xpath(
880
+ '/*/ns1:system-characteristics/ns1:system-information/ns1:prop[@name="pta-2"][@ns="https://fedramp.gov/ns/oscal"]/@value',
881
+ namespaces=ns,
882
+ )[0].capitalize()
883
+ privacyImpactAssessment["piaConducted"] = root.xpath(
884
+ '/*/ns1:system-characteristics/ns1:system-information/ns1:prop[@name="pta-3"][@ns="https://fedramp.gov/ns/oscal"]/@value',
885
+ namespaces=ns,
886
+ )[0].capitalize()
887
+ privacyImpactAssessment["privacyActSystem"] = root.xpath(
888
+ '/*/ns1:system-characteristics/ns1:system-information/ns1:prop[@name="pta-4"][@ns="https://fedramp.gov/ns/oscal"]/@value',
889
+ namespaces=ns,
890
+ )[0].capitalize()
891
+ privacyImpactAssessment["sornExists"] = root.xpath(
892
+ '/*/ns1:system-characteristics/ns1:system-information/ns1:prop[@name="pta-4"][@ns="https://fedramp.gov/ns/oscal"]/@value',
893
+ namespaces=ns,
894
+ )[0].capitalize()
895
+ privacyImpactAssessment["sornId"] = root.xpath(
896
+ '/*/ns1:system-characteristics/ns1:system-information/ns1:prop[@name="sorn-id"][@ns="https://fedramp.gov/ns/oscal"]/@value',
897
+ namespaces=ns,
898
+ )[0].capitalize()
899
+ privacyImpactAssessment["SecurityPlanId"] = ssp_id
900
+ privacyImpactAssessment["isPublic"] = True
901
+ # Will have to come back to this. Requires linking to the Privacy officer / information officer contacts per
902
+ # application layer logic, if any of the privacy questions are "yes".
903
+ """
904
+ response_id = post_privacy(privacyImpactAssessment)
905
+ if response_id:
906
+ events_list.append(log_event(model_layer='System Characteristics', record_type='Privacy Impact Assessment',
907
+ event_msg='Successfully imported PTA/PIA data.'))
908
+ else:
909
+ events_list.append(log_error(model_layer='System Characteristics', record_type='Privacy Assessment',
910
+ missing_element='Privacy Assessment',
911
+ event_msg='Problem extracting or uploading PTA/PIA data.'))
912
+ """
913
+ except Exception as e:
914
+ logger.warning(e)
915
+ events_list.append(
916
+ log_error(
917
+ model_layer=SYSTEM_CHARS,
918
+ record_type="Privacy Assessment",
919
+ missing_element="Privacy Assessment",
920
+ event_msg="Problem extracting PTA/PIA data.",
921
+ )
922
+ )