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,689 @@
1
+ # flake8: noqa
2
+ import json
3
+ from typing import List
4
+
5
+ from lxml import etree
6
+
7
+ from regscale.core.app.application import Application
8
+ from regscale.core.app.logz import create_logger
9
+ from regscale.core.app.utils.XMLIR import XMLIR, XMLIRTraversal
10
+ from regscale.integrations.public.fedramp.fedramp_traversal import FedrampTraversal
11
+ from regscale.integrations.public.fedramp.xml_utils import extract_markup_content
12
+ from regscale.models.regscale_models import StakeHolder, SystemRole, SystemRoleExternalAssignment
13
+ from regscale.models.regscale_models.data_center import DataCenter
14
+ from regscale.models.regscale_models.facility import Facility
15
+
16
+ logger = create_logger()
17
+
18
+
19
+ class MetadataRoleIR(XMLIR):
20
+ @XMLIR.from_el(".")
21
+ def id(self, v: List[etree._Element], traversal: XMLIRTraversal):
22
+ """The user's role"""
23
+ return v[0].get("id")
24
+
25
+ @XMLIR.from_el(".//oscal:title")
26
+ def title(self, v: List[etree._Element], traversal: XMLIRTraversal):
27
+ return v[0].text if v else None
28
+
29
+ @XMLIR.from_el(".//oscal:desc")
30
+ def description(self, v: List[etree._Element], traversal: XMLIRTraversal):
31
+ text_inside = extract_markup_content(v[0]) if v else None
32
+
33
+ return text_inside
34
+
35
+
36
+ class MetadataLocationAddressIR(XMLIR):
37
+ @XMLIR.from_el(".//oscal:addr-line")
38
+ def addr_line(self, v: List[etree._Element], traversal: XMLIRTraversal):
39
+ return v[0].text if v else None
40
+
41
+ @XMLIR.from_el(".//oscal:city")
42
+ def city(self, v: List[etree._Element], traversal: XMLIRTraversal):
43
+ return v[0].text if v else None
44
+
45
+ @XMLIR.from_el(".//oscal:state")
46
+ def state(self, v: List[etree._Element], traversal: XMLIRTraversal):
47
+ return v[0].text if v else None
48
+
49
+ @XMLIR.from_el(".//oscal:postal-code")
50
+ def postal_code(self, v: List[etree._Element], traversal: XMLIRTraversal):
51
+ return v[0].text if v else None
52
+
53
+ @XMLIR.from_el(".")
54
+ def type(self, v: List[etree._Element], traversal: XMLIRTraversal):
55
+ return v[0].get("type") if v else None
56
+
57
+
58
+ class MetadataLocationIR(XMLIR):
59
+ @XMLIR.from_el(".")
60
+ def uuid(self, v: List[etree._Element], traversal: XMLIRTraversal):
61
+ return v[0].get("uuid") if v else None
62
+
63
+ @XMLIR.from_el(".//oscal:title")
64
+ def title(self, v: List[etree._Element], traversal: XMLIRTraversal):
65
+ return v[0].text if v else None
66
+
67
+ @XMLIR.from_el(".//oscal:address")
68
+ def address(self, v: List[etree._Element], traversal: XMLIRTraversal):
69
+ return MetadataLocationAddressIR().parse(
70
+ XMLIRTraversal(
71
+ namespaces=traversal.namespaces,
72
+ root=traversal.root,
73
+ el=v[0],
74
+ xpathToThis="...",
75
+ )
76
+ )
77
+
78
+ # Pass on remarks
79
+ @XMLIR.from_el(".//oscal:remarks")
80
+ def remarks(self, v: List[etree._Element], traversal: XMLIRTraversal):
81
+ text_inside = extract_markup_content(v[0]) if v else None
82
+
83
+ return text_inside
84
+
85
+
86
+ # TODO
87
+ """
88
+ ----
89
+ EXAMPLE 1:
90
+ ----
91
+
92
+ <party uuid="6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" type="organization">
93
+ <name>Cloud Service Provider (CSP) Name</name>
94
+ <short-name>CSP Acronym/Short Name</short-name>
95
+ <link href="#31a46c4f-2959-4287-bc1c-67297d7da60b" rel="logo"/>
96
+ <location-uuid>27b78960-59ef-4619-82b0-ae20b9c709ac</location-uuid>
97
+ <remarks>
98
+ <p>Replace sample CSP information.</p>
99
+ <p>CSP informaton must be present and associated with the "cloud-service-provider" role
100
+ via <code>responsible-party</code>.</p>
101
+ </remarks>
102
+ </party>
103
+
104
+ ----
105
+ EXAMPLE 2:
106
+ ----
107
+
108
+ <party uuid="77e0e2c8-2560-4fe9-ac78-c3ff4ffc9f6d" type="organization">
109
+ <name>Federal Risk and Authorization Management Program: Program Management Office</name>
110
+ <short-name>FedRAMP PMO</short-name>
111
+ <link href="https://fedramp.gov" rel="homepage"/>
112
+ <link href="#a2381e87-3d04-4108-a30b-b4d2f36d001f" rel="logo"/>
113
+ <link href="#985475ee-d4d6-4581-8fdf-d84d3d8caa48" rel="reference"/>
114
+ <link href="#1a23a771-d481-4594-9a1a-71d584fa4123" rel="reference"/>
115
+ <email-address>info@fedramp.gov</email-address>
116
+ <address type="work">
117
+ <addr-line>1800 F St. NW</addr-line>
118
+ <city>Washington</city>
119
+ <state>DC</state>
120
+ <postal-code>20006</postal-code>
121
+ <country>US</country>
122
+ </address>
123
+ <remarks>
124
+ <p>This party entry must be present in a FedRAMP SSP.</p>
125
+ <p>The uuid may be different; however, the uuid must be associated with the
126
+ "fedramp-pmo" role in the responsible-party assemblies.</p>
127
+ </remarks>
128
+ </party>
129
+
130
+ """
131
+
132
+
133
+ class MetadataOrgPartyIR(XMLIR):
134
+ @XMLIR.from_el(".")
135
+ def uuid(self, v: List[etree._Element], traversal: XMLIRTraversal):
136
+ """The user's uuid"""
137
+ return v[0].get("uuid") if v else None
138
+
139
+ @XMLIR.from_el(".")
140
+ def type(self, v: List[etree._Element], traversal: XMLIRTraversal):
141
+ """The user's type"""
142
+ return v[0].get("type") if v else None
143
+
144
+ @XMLIR.from_el(".//oscal:link")
145
+ def links(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
146
+ """The user's links"""
147
+ return [
148
+ {
149
+ "href": v.get("href"),
150
+ "rel": v.get("rel"),
151
+ }
152
+ for v in vlist
153
+ ]
154
+
155
+ @XMLIR.from_el(".//oscal:location-uuid")
156
+ def location_uuids(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
157
+ """The user's location uuid"""
158
+ return [v.text for v in vlist]
159
+
160
+ @XMLIR.from_el(".//oscal:name")
161
+ def name(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
162
+ """The user's name"""
163
+ return vlist[0].text if vlist else None
164
+
165
+ @XMLIR.from_el(".//oscal:short-name")
166
+ def short_name(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
167
+ """The user's short name"""
168
+ return vlist[0].text if vlist else None
169
+
170
+ @XMLIR.from_el(".//oscal:email-address")
171
+ def email_address(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
172
+ """The user's email address"""
173
+ return vlist[0].text if vlist else None
174
+
175
+ @XMLIR.from_el(".//oscal:remarks")
176
+ def remarks(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
177
+ """The text of the remark"""
178
+ text_inside = extract_markup_content(vlist[0]) if vlist else None
179
+
180
+ return text_inside
181
+
182
+
183
+ """
184
+ <party uuid="uuid-of-person-1" type="person">
185
+ <name>[SAMPLE]Person Name 1</name>
186
+ <prop name="job-title" value="Individual's Title"/>
187
+ NIST Allowed Value
188
+ Required role ID:
189
+  system-owner
190
+ <prop name="mail-stop" value="A-1"/>
191
+ <email-address>name@example.com</email-address>
192
+ <telephone-number>202-000-0000</telephone-number>
193
+ <location-uuid>uuid-of-hq-location</location-uuid>
194
+ <member-of-organization>uuid-of-csp</member-of-organization>
195
+ </party>
196
+
197
+ """
198
+
199
+
200
+ class MetadataPersonPartyIR(XMLIR):
201
+ @XMLIR.from_el(".")
202
+ def uuid(self, v: List[etree._Element], traversal: XMLIRTraversal):
203
+ """The user's uuid"""
204
+ return v[0].get("uuid") if v else None
205
+
206
+ @XMLIR.from_el(".")
207
+ def type(self, v: List[etree._Element], traversal: XMLIRTraversal):
208
+ """The user's type"""
209
+ return v[0].get("type") if v else None
210
+
211
+ @XMLIR.from_el(".//oscal:location-uuid")
212
+ def location_uuids(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
213
+ """The user's location uuid"""
214
+ return [v.text for v in vlist]
215
+
216
+ @XMLIR.from_el(".//oscal:member-of-organization")
217
+ def member_of_organization_uuids(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
218
+ """The user's location uuid"""
219
+ return [v.text for v in vlist]
220
+
221
+ @XMLIR.from_el(".//oscal:name")
222
+ def name(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
223
+ """The user's name"""
224
+ return vlist[0].text if vlist else None
225
+
226
+ @XMLIR.from_el('.//oscal:prop[@name="job-title"]')
227
+ def job_title(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
228
+ """The user's role"""
229
+ return vlist[0].get("value") if vlist else None
230
+
231
+ @XMLIR.from_el('.//oscal:prop[@name="mail-stop"]')
232
+ def mail_stop(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
233
+ """The user's role"""
234
+ return vlist[0].get("value") if vlist else None
235
+
236
+ @XMLIR.from_el(".//oscal:email-address")
237
+ def email_address(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
238
+ """The user's email address"""
239
+ return vlist[0].text if vlist else None
240
+
241
+ @XMLIR.from_el(".//oscal:telephone-number")
242
+ def telephone_number(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
243
+ """The user's telephone number"""
244
+ return vlist[0].text if vlist else None
245
+
246
+
247
+ """
248
+ <responsible-party role-id="system-poc-management">
249
+ <party-uuid>0cec09d9-20c6-470b-9ffc-85763375880b</party-uuid>
250
+ <remarks>
251
+ <p>Exactly one</p>
252
+ </remarks>
253
+ </responsible-party>
254
+ """
255
+
256
+
257
+ class MetadataResponsiblePartyIR(XMLIR):
258
+ @XMLIR.from_el(".")
259
+ def role_id(self, v: List[etree._Element], traversal: XMLIRTraversal):
260
+ """The user's role id"""
261
+ return v[0].get("role-id") if v else None
262
+
263
+ @XMLIR.from_el(".//oscal:party-uuid")
264
+ def party_uuids(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
265
+ """The user's party uuid"""
266
+ return [v.text for v in vlist]
267
+
268
+ @XMLIR.from_el(".//oscal:remarks")
269
+ def remarks(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
270
+ """The text of the remark"""
271
+ text_inside = extract_markup_content(vlist[0]) if vlist else None
272
+
273
+ return text_inside
274
+
275
+
276
+ class MetadataMappingIR(XMLIR):
277
+ # ./ implies current element
278
+ @XMLIR.from_el(".//oscal:role")
279
+ def roles(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
280
+ """The user's role"""
281
+ return [
282
+ MetadataRoleIR().parse(
283
+ XMLIRTraversal(
284
+ namespaces=traversal.namespaces,
285
+ root=traversal.root,
286
+ el=v,
287
+ xpathToThis="...",
288
+ )
289
+ )
290
+ for v in vlist
291
+ ]
292
+
293
+ @XMLIR.from_el(".//oscal:location")
294
+ def locations(self, v: List[etree._Element], traversal: XMLIRTraversal):
295
+ """The user's location"""
296
+ return [
297
+ MetadataLocationIR().parse(
298
+ XMLIRTraversal(
299
+ namespaces=traversal.namespaces,
300
+ root=traversal.root,
301
+ el=v,
302
+ xpathToThis="...",
303
+ )
304
+ )
305
+ for v in v
306
+ ]
307
+
308
+ @XMLIR.from_el(".//oscal:party")
309
+ def parties(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
310
+ """The user's party"""
311
+ return [
312
+ (
313
+ MetadataOrgPartyIR().parse(
314
+ XMLIRTraversal(
315
+ namespaces=traversal.namespaces,
316
+ root=traversal.root,
317
+ el=v,
318
+ xpathToThis="...",
319
+ )
320
+ )
321
+ if v.get("type") == "organization"
322
+ else MetadataPersonPartyIR().parse(
323
+ XMLIRTraversal(
324
+ namespaces=traversal.namespaces,
325
+ root=traversal.root,
326
+ el=v,
327
+ xpathToThis="...",
328
+ )
329
+ )
330
+ )
331
+ for v in vlist
332
+ ]
333
+
334
+ @XMLIR.from_el(".//oscal:responsible-party")
335
+ def responsible_parties(self, vlist: List[etree._Element], traversal: XMLIRTraversal):
336
+ """The user's responsible party"""
337
+ return [
338
+ MetadataResponsiblePartyIR().parse(
339
+ XMLIRTraversal(
340
+ namespaces=traversal.namespaces,
341
+ root=traversal.root,
342
+ el=v,
343
+ xpathToThis="...",
344
+ )
345
+ )
346
+ for v in vlist
347
+ ]
348
+
349
+
350
+ def parse_metadata(trv: FedrampTraversal, app: Application) -> None:
351
+ """This function parses role, location, and party information from metadata. This
352
+
353
+ :param FedrampTraversal trv: The traversal object
354
+ :param Application app: The RegScale CLI application object
355
+ :rtype: None
356
+ """
357
+ api = trv.api
358
+ root = trv.root
359
+ namespaces = trv.namespaces
360
+
361
+ # Extract user nodes
362
+ metadatas = root.xpath(".//oscal:metadata", namespaces=namespaces)
363
+
364
+ if len(metadatas) == 0:
365
+ trv.log_error(
366
+ {
367
+ "model_layer": "system-implementation",
368
+ "record_type": "metadata",
369
+ "event_msg": "No metadata detected.",
370
+ }
371
+ )
372
+
373
+ elif len(metadatas) > 1:
374
+ trv.log_error(
375
+ {
376
+ "model_layer": "system-implementation",
377
+ "record_type": "metadata",
378
+ "event_msg": "Multiple metadatas detected.",
379
+ }
380
+ )
381
+
382
+ else:
383
+ # 1. Get IR
384
+ metadata = metadatas[0]
385
+ metadata_mapping = MetadataMappingIR().parse(
386
+ XMLIRTraversal(
387
+ xpathToThis=".//oscal:metadata",
388
+ el=metadata,
389
+ root=root,
390
+ namespaces=namespaces,
391
+ )
392
+ )
393
+
394
+ #################################
395
+ # 2. Post to API Endpoints
396
+ # roles: list of roles, id, title, description
397
+ # locations: list of locations, uuid, title, address
398
+ # parties: list of parties, uuid, type, name, short-name, links, location-uuids, member-of-organization-uuids, email-address, remarks
399
+ # responsible-parties: list of responsible-parties, role-id, party-uuids, remarks
400
+ #################################
401
+ # 2.1 roles
402
+ roles = metadata_mapping["roles"]
403
+ for role in roles:
404
+ logger.debug(f"role: {role=}")
405
+ try:
406
+ system_role = SystemRole(
407
+ id=0,
408
+ fedrampRoleId=role["id"],
409
+ roleName=role["title"],
410
+ roleType="Internal",
411
+ accessLevel="Non-Privileged",
412
+ sensitivityLevel="Not Applicable",
413
+ privilegeDescription=(
414
+ role["description"]
415
+ if role["description"]
416
+ else "Not Found -imported by CLI-defaulting to Non-Privileged"
417
+ ),
418
+ functions="Not Found",
419
+ securityPlanId=trv.ssp_id,
420
+ isPublic=True,
421
+ assignedUserId=app.config["userId"],
422
+ )
423
+
424
+ server_res = system_role.insert_systemrole(api.app)
425
+ # what do we want to do with the responses?
426
+
427
+ if (server_res is None) or (not server_res):
428
+ trv.log_error(
429
+ {
430
+ "model_layer": "metadata",
431
+ "record_type": "role",
432
+ "event_msg": f"Failed to create role '{role['title'] if 'title' in role else '<UNKNOWN>'}' with role id '{role['id'] if 'id' in role else '<UNKNOWN>'}'",
433
+ }
434
+ )
435
+ else:
436
+ trv.log_info(
437
+ {
438
+ "model_layer": "metadata",
439
+ "record_type": "role",
440
+ "event_msg": f"Created role '{role['title']}' with role id '{role['id']}'",
441
+ }
442
+ )
443
+
444
+ except Exception as e:
445
+ trv.log_error(
446
+ {
447
+ "model_layer": "metadata",
448
+ "record_type": "role",
449
+ "event_msg": f"Failed to create role '{role['title'] if 'title' in role else '<UNKNOWN>'}' with role id '{role['id'] if 'id' in role else '<UNKNOWN>'}' (ERROR: {str(e)})",
450
+ }
451
+ )
452
+ # 2.2 locations
453
+ locations = metadata_mapping["locations"]
454
+ for location in locations:
455
+ """
456
+ Facility object (Regscale Object)
457
+ {
458
+ "id": 0,
459
+ "name": "string",
460
+ "description": "string",
461
+ "address": "string",
462
+ "city": "string",
463
+ "state": "string",
464
+ "zipCode": "string",
465
+ "status": "string",
466
+ "latitude": 0,
467
+ "longitude": 0,
468
+ "createdBy": "string",
469
+ "createdById": "string",
470
+ "dateCreated": "2023-08-30T04:02:03.937Z",
471
+ "lastUpdatedBy": "string",
472
+ "lastUpdatedById": "string",
473
+ "dateLastUpdated": "2023-08-30T04:02:03.937Z"
474
+ }
475
+ """
476
+ try:
477
+ facility = Facility(
478
+ name=location.get("name", ""),
479
+ description=location.get("description", ""),
480
+ address=location.get("address", {}).get("addr_line", ""),
481
+ city=location.get("address", {}).get("city", ""),
482
+ state=location.get("address", {}).get("state", ""),
483
+ zipCode=location.get("address", {}).get("postal_code", ""),
484
+ status=location.get("status", ""),
485
+ latitude=location.get("address", {}).get("latitude", 0),
486
+ longitude=location.get("address", {}).get("longitude", 0),
487
+ createdById=api.config["userId"],
488
+ )
489
+ facility_res = facility.post(api.app)
490
+ trv.log_info(
491
+ {
492
+ "model_layer": "metadata",
493
+ "record_type": "Location",
494
+ "event_msg": f"Created facility '{facility_res['id']}' with description '{facility_res['description']}'",
495
+ }
496
+ )
497
+ except Exception as e:
498
+ trv.log_error(
499
+ {
500
+ "missing_element": location.get("name", ""),
501
+ "model_layer": "metadata",
502
+ "record_type": "Location",
503
+ "event_msg": f"Failed to create facility '{location['title'] if 'title' in location else '<UNKNOWN>'}'"
504
+ f" (ERROR: {str(e)})",
505
+ }
506
+ )
507
+ if facility_res:
508
+ try:
509
+ data_center = DataCenter(
510
+ id=0,
511
+ # uuid=party.get('uuid', ''), # TODO - this should go to FedRAMP ID once exists
512
+ facilityId=facility_res.get("id", ""),
513
+ parentId=trv.ssp_id,
514
+ parentModule="securityplans",
515
+ facility=facility_res.get("name", ""),
516
+ )
517
+ logger.debug(f"{data_center=}")
518
+ data_center_res = data_center.post(api.app)
519
+ logger.debug(f"{data_center_res=}")
520
+
521
+ trv.log_info(
522
+ {
523
+ "model_layer": "metadata",
524
+ "record_type": "Location",
525
+ "event_msg": f"Created DataCenter '{data_center_res['id']}'",
526
+ }
527
+ )
528
+ except Exception as e:
529
+ trv.log_error(
530
+ {
531
+ "model_layer": "metadata",
532
+ "record_type": "Location",
533
+ "event_msg": f"Failed to create DataCenter: (ERROR: {str(e)})",
534
+ }
535
+ )
536
+ else:
537
+ trv.log_error(
538
+ {
539
+ "model_layer": "metadata",
540
+ "record_type": "Location",
541
+ "event_msg": f"Failed to create DataCenter: (ERROR: {str(e)})",
542
+ }
543
+ )
544
+
545
+ # 2.3 parties
546
+ parties = metadata_mapping["parties"]
547
+ for party in parties:
548
+ """
549
+ StakeHolders (Regscale Object)
550
+ {
551
+ "id": 0,
552
+ "type": "string",
553
+ "name": "string",
554
+ "shortname": "string",
555
+ "title": "string",
556
+ "phone": "string",
557
+ "email": "string",
558
+ "address": "string",
559
+ "otherID": "string",
560
+ "notes": "string",
561
+ "parentId": 0,
562
+ "parentModule": "string"
563
+ }
564
+ """
565
+ try:
566
+ stakeholders = StakeHolder(
567
+ id=0,
568
+ type=party.get("type", ""),
569
+ name=party.get("name", ""),
570
+ shortname=party.get("short_name", ""),
571
+ title=party.get("title", ""),
572
+ phone=party.get("phone", ""),
573
+ email=party.get("email_address", ""),
574
+ address=party.get("address", ""),
575
+ # otherID is fedrampId in this case.
576
+ otherID=party.get("uuid", ""),
577
+ notes=party.get("remarks", ""),
578
+ parentId=trv.ssp_id,
579
+ parentModule="securityplans",
580
+ )
581
+ # FIXME how do we handle links and location_uuids?
582
+ stakeholders_res = stakeholders.post(api.app)
583
+ trv.log_info(
584
+ {
585
+ "model_layer": "metadata",
586
+ "record_type": "party",
587
+ "event_msg": f"Created stakeholder '{stakeholders_res['id']}' with name '{stakeholders_res['name']} and otherID: '{stakeholders_res['otherID']}'",
588
+ }
589
+ )
590
+ except Exception as e:
591
+ trv.log_error(
592
+ {
593
+ "model_layer": "metadata",
594
+ "record_type": "party",
595
+ "event_msg": f"Failed to create party: {party.get('shortname', '')} (ERROR: {str(e)})",
596
+ }
597
+ )
598
+
599
+ #########################################################################
600
+ # 2.4 responsible-parties
601
+ responsible_parties = metadata_mapping["responsible_parties"]
602
+
603
+ # For debugging.
604
+ logger.debug(f"stakeholders: {stakeholders=}")
605
+
606
+ for responsible_party in responsible_parties:
607
+ party_uuid = (
608
+ responsible_party["party_uuids"][0]
609
+ if "party_uuids" in responsible_party and len(responsible_party["party_uuids"]) > 0
610
+ else None
611
+ )
612
+
613
+ if (party_uuid is None) or (len(party_uuid) == 0):
614
+ trv.log_error(
615
+ {
616
+ "model_layer": "metadata",
617
+ "record_type": "responsible-party",
618
+ "event_msg": f"Failed to create responsible-party: '{responsible_party.get('role_id', '')}', could not find correspnding party-uuid",
619
+ }
620
+ )
621
+ continue
622
+
623
+ # 1. Stakeholder
624
+ resp_party_stakeholder_id = trv.fedramp_party_to_regscale_stakeholder_id(party_uuid)
625
+
626
+ if resp_party_stakeholder_id is None:
627
+ trv.log_error(
628
+ {
629
+ "model_layer": "metadata",
630
+ "record_type": "responsible-party",
631
+ "event_msg": f"Failed to create responsible-party: '{responsible_party.get('role_id', '')}', could not find corresponding stakeholder in Regscale (did you forget to create a corresponding <party> tag in metadata?).",
632
+ }
633
+ )
634
+ continue
635
+
636
+ # TODO 2. get SystemRole
637
+ fedramp_role_id = responsible_party.get("role_id", "")
638
+
639
+ if fedramp_role_id is None:
640
+ trv.log_error(
641
+ {
642
+ "model_layer": "metadata",
643
+ "record_type": "responsible-party",
644
+ "event_msg": f"Failed to create responsible-party: '{responsible_party.get('role_id', '')}', could not find correspnding role_id in metadata (did you forget to create a corresponding <role> tag in metadata?).",
645
+ }
646
+ )
647
+ continue
648
+
649
+ system_role_id = trv.fedramp_role_id_to_regscale_system_role_id(fedramp_role_id=fedramp_role_id)
650
+
651
+ # For debugging only.
652
+ logger.debug("system_role_id: ", system_role_id)
653
+
654
+ if system_role_id is None:
655
+ trv.log_error(
656
+ {
657
+ "model_layer": "metadata",
658
+ "record_type": "responsible-party",
659
+ "event_msg": f"Failed to create responsible-party: '{responsible_party.get('role_id', '')}', could not find corresponding system role in Regscale (did you forget to create a corresponding <role> tag in metadata?).",
660
+ }
661
+ )
662
+ continue
663
+
664
+ # 3. Create SystemRoleExternalAssignment, joining SystemRole & Stakeholder
665
+ system_role_resp = SystemRoleExternalAssignment(
666
+ roleId=system_role_id,
667
+ stakeholderId=resp_party_stakeholder_id,
668
+ ).post(api.app)
669
+
670
+ # For debugging only.
671
+ logger.debug("system_role_resp: ", system_role_resp)
672
+
673
+ if (system_role_resp is None) or (not system_role_resp):
674
+ trv.log_error(
675
+ {
676
+ "model_layer": "metadata",
677
+ "record_type": "responsible-party",
678
+ "event_msg": f"Failed to create responsible-party: '{responsible_party.get('role_id', '')}' with stakeholder id '{resp_party_stakeholder_id}' and system role id '{system_role_id}'",
679
+ }
680
+ )
681
+
682
+ else:
683
+ trv.log_info(
684
+ {
685
+ "model_layer": "metadata",
686
+ "record_type": "responsible-party",
687
+ "event_msg": f"Created responsible-party: '{responsible_party.get('role_id', '')}' with stakeholder id '{resp_party_stakeholder_id}' and system role id '{system_role_id}'",
688
+ }
689
+ )