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
File without changes
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Enables comparison of catalogs from the master catalog list and the user's RegScale instance"""
4
+ import json
5
+ import logging
6
+ import re
7
+ from urllib.parse import urlparse
8
+
9
+ import requests
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def get_new_catalog(url: str) -> dict:
15
+ """
16
+ Function to download a catalog via API call
17
+
18
+ :param str url: URL to download the catalog from
19
+ :return: Catalog API response as a dictionary
20
+ :rtype: dict
21
+ """
22
+ # make sure url is stripped
23
+ url = url.strip()
24
+ new_catalog = {}
25
+ try:
26
+ # call curl command to download the catalog
27
+ response = requests.get(url, timeout=60)
28
+ # parse into a dictionary
29
+ new_catalog = response.json()
30
+ except (requests.exceptions.MissingSchema, json.JSONDecodeError, requests.exceptions.RequestException) as ex:
31
+ logger.error("Error: %s on Catalog URL: %s", ex, url)
32
+ # return from the function
33
+ return new_catalog
34
+
35
+
36
+ def is_valid_url(url: str) -> bool:
37
+ """
38
+ Function to validate URL
39
+
40
+ :param str url: URL to validate
41
+ :return: Whether the URL is valid
42
+ :rtype: bool
43
+ """
44
+ try:
45
+ result = urlparse(url)
46
+ return all([result.scheme, result.netloc])
47
+ except ValueError:
48
+ return False
49
+
50
+
51
+ def dot_to_parentheses(input_string: str) -> str:
52
+ """
53
+ Converts dot-separated issue identifiers to parentheses format.
54
+
55
+ :param str input_string: The string containing issue identifiers in dot-separated format.
56
+ :return: A string with issue identifiers converted to parentheses format.
57
+ :rtype: str
58
+ """
59
+ return re.sub(r"([A-Z]+-\d+)\.(\d+)", r"\1(\2)", input_string.upper())
60
+
61
+
62
+ def parentheses_to_dot(input_string: str) -> str:
63
+ """
64
+ Converts parentheses-separated issue identifiers back to dot format.
65
+
66
+ :param str input_string: The string containing issue identifiers in parentheses format.
67
+ :return: A string with issue identifiers converted back to dot format.
68
+ :rtype: str
69
+ """
70
+ return re.sub(r"([A-Z]+-\d+)\((\d+)\)", r"\1.\2", input_string.upper()).lower()
71
+
72
+
73
+ def objective_to_control_dot(input_string: str) -> str:
74
+ """
75
+ Converts objective identifiers to control identifiers in dot format.
76
+
77
+ :param str input_string: The string containing objective identifiers.
78
+ :return: A string with objective identifiers converted to control identifiers in dot format.
79
+ :rtype: str
80
+ """
81
+ # Convert the input string to lowercase
82
+ input_string = input_string.lower()
83
+
84
+ # Use regex to find the pattern and extract the desired part
85
+ match = re.match(r"([a-z]+-\d+(\.\d+)?)", input_string)
86
+
87
+ if match:
88
+ return match.group(1)
89
+ else:
90
+ logger.error(f"Failed to convert objective to control: {input_string}")
91
+ return input_string
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Enables comparison of catalogs from the master catalog list and the user's RegScale instance"""
4
+ import logging
5
+
6
+ # Standard Imports
7
+ import operator
8
+
9
+ import click # type: ignore
10
+ import requests # type: ignore
11
+
12
+ from regscale.core.app.api import Api
13
+ from regscale.core.app.logz import create_logger
14
+ from regscale.core.app.utils.app_utils import create_progress_object, error_and_exit
15
+ from regscale.core.app.utils.catalog_utils.common import get_new_catalog
16
+ from regscale.models.app_models.catalog_compare import CatalogCompare
17
+
18
+ # pylint: disable=line-too-long
19
+
20
+
21
+ def display_menu() -> None:
22
+ """
23
+ Start the process of comparing two catalogs, one from the master catalog list
24
+ and one from the user's RegScale instance
25
+
26
+ :rtype: None
27
+ """
28
+ # set environment and application configuration
29
+ api = Api()
30
+ api.timeout = 180
31
+
32
+ # create logger function to log to the console
33
+ job_progress = create_progress_object()
34
+ logger = create_logger()
35
+ menu_counter: list = []
36
+ download_url: str = ""
37
+ new_catalog: dict = {}
38
+ # import master catalog list
39
+ data = CatalogCompare.get_master_catalogs(api=api)
40
+ # sort master catalogue list
41
+ catalogues = data["catalogs"]
42
+ catalogues.sort(key=operator.itemgetter("title"))
43
+ for i, catalog in enumerate(catalogues):
44
+ index = i + 1
45
+ # print each catalog in the master catalog list
46
+ print(f'{index}: {catalog["title"]}')
47
+ menu_counter.append(i)
48
+ # set status to False to run loop
49
+ status: bool = False
50
+ while not status:
51
+ # select catalog to run diagnostic
52
+ value = click.prompt(
53
+ "Please enter the number of the catalog you would like to run diagnostics on",
54
+ type=int,
55
+ )
56
+ # check if value exist that is selected
57
+ if value < min(menu_counter) or value > max(menu_counter):
58
+ print("That is not a valid selection, please try again")
59
+ else:
60
+ status = True
61
+ with job_progress:
62
+ # choose catalog to run diagnostics on
63
+ for i, catalog in enumerate(catalogues):
64
+ index = i + 1
65
+ short_title = catalog["defaultName"]
66
+ if index == value and catalog["downloadURL"]:
67
+ cat_uuid = catalog["uuid"]
68
+ download_url = catalog["downloadURL"]
69
+ break
70
+
71
+ # add task for retrieving new catalog
72
+ retrieving_new_catalog = job_progress.add_task(
73
+ f"[#f8b737]Retrieving selected catalog ({short_title}) from RegScale.com/resources.", total=1
74
+ )
75
+ # retrieve new catalog to run diagnostics on
76
+ new_catalog = get_new_catalog(url=download_url)
77
+ # update the task as complete
78
+ job_progress.update(retrieving_new_catalog, advance=1)
79
+ # add task for retrieving old catalog
80
+ retrieving_old_catalog = job_progress.add_task(
81
+ f"[#f8b737]Retrieving selected catalog ({short_title}) from RegScale application instance.",
82
+ total=1,
83
+ )
84
+ # retrieve old catalog to run diagnostics on
85
+ old_catalog = get_old_catalog(uuid_value=cat_uuid, api=api)
86
+ # update the task as complete
87
+ job_progress.update(retrieving_old_catalog, advance=1)
88
+ # add task to run diagnostics on new catalog
89
+ diagnosing_new_catalog = job_progress.add_task(
90
+ "[#21a5bb]Running diagnostics on catalog from RegScale.com/resources.",
91
+ total=1,
92
+ )
93
+ # run the diagnostics for the new selected catalog
94
+ new_results = CatalogCompare.run_new_diagnostics(new_diagnose_cat=new_catalog)
95
+ # update the task as complete
96
+ job_progress.update(diagnosing_new_catalog, advance=1)
97
+ # add task to run diagnostics on old catalog
98
+ diagnosing_old_catalog = job_progress.add_task(
99
+ "[#21a5bb]Running diagnosing on catalog from RegScale application instance.",
100
+ total=1,
101
+ )
102
+ # run the diagnostics for the old selected catalog
103
+ old_results = CatalogCompare.run_old_diagnostics(old_diagnose_cat=old_catalog)
104
+ # update the task as complete
105
+ job_progress.update(diagnosing_old_catalog, advance=1)
106
+ # add task to compare catalogs
107
+ comparing_catalogs = job_progress.add_task(
108
+ "[#ef5d23]Performing comparison on output of complete catalog diagnostics.",
109
+ total=1,
110
+ )
111
+ # compare catalog results
112
+ compare_dicts_shallow(dict_1=new_results.dict(), dict_2=old_results.dict(), logger=logger)
113
+ # update the task as complete
114
+ job_progress.update(comparing_catalogs, advance=1)
115
+
116
+
117
+ def get_old_catalog(uuid_value: str, api: Api) -> dict:
118
+ """
119
+ Function to retrieve the old catalog from a RegScale instance via API & GraphQL
120
+
121
+ :param str uuid_value: UUID of the catalog to retrieve
122
+ :param Api api: API object
123
+ :return: dictionary of the old catalog
124
+ :rtype: dict
125
+ """
126
+ old_catalog_data = {}
127
+ body = """
128
+ query {
129
+ catalogues(
130
+ skip: 0
131
+ take: 50
132
+ where: { uuid: { eq: "uuid_value" } }
133
+ ) {
134
+ items {
135
+ title
136
+ uuid
137
+ keywords
138
+ securityControls {
139
+ id
140
+ objectives {
141
+ uuid
142
+ }
143
+ parameters {
144
+ uuid
145
+ }
146
+ cci {
147
+ uuid
148
+ }
149
+ tests {
150
+ uuid
151
+ }
152
+ }
153
+ }
154
+ pageInfo {
155
+ hasNextPage
156
+ }
157
+ totalCount
158
+ }
159
+ }
160
+ """.replace(
161
+ "uuid_value", uuid_value
162
+ )
163
+ try:
164
+ old_catalog_data = api.graph(query=body)["catalogues"]["items"][0]
165
+ except (IndexError, KeyError):
166
+ error_and_exit(f"Catalog with UUID: {uuid_value} not found in RegScale instance.")
167
+ return old_catalog_data
168
+
169
+
170
+ def compare_dicts_shallow(dict_1: dict, dict_2: dict, logger: logging.Logger) -> None:
171
+ """
172
+ Function to compare two dictionaries and output the results
173
+
174
+ :param dict dict_1: dictionary to compare
175
+ :param dict dict_2: dictionary to compare
176
+ :param logging.Logger logger: logger to use for console outputs
177
+ :rtype: None
178
+ """
179
+ comparison = {
180
+ "title": "Catalog Titles",
181
+ "uuid": "Catalog UUIDs",
182
+ "keywords": "Catalog Keywords",
183
+ "cci_count": "CCI Counts",
184
+ "objective_count": "Objective Counts",
185
+ "parameter_count": "Parameter Counts",
186
+ "security_control_count": "Security Control Counts",
187
+ "test_count": "Test Counts",
188
+ }
189
+ for key, value in comparison.items():
190
+ if dict_1.get(key) != dict_2.get(key):
191
+ logger.info(f"{value} are not the same.")
192
+ else:
193
+ logger.info(f"{value} match.")
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Add functionality to diagnose catalog via API."""
4
+
5
+ # Standard Imports
6
+ import logging
7
+ import operator
8
+ from typing import Optional
9
+
10
+ import click # type: ignore
11
+ import requests # type: ignore
12
+ from pathlib import Path
13
+
14
+ from regscale.core.app.utils.app_utils import save_data_to
15
+ from regscale.core.app.utils.catalog_utils.common import get_new_catalog
16
+ from regscale.models.app_models.catalog_compare import CatalogCompare
17
+
18
+
19
+ def display_menu() -> None:
20
+ """
21
+ Display menu for catalog diagnostic and start the diagnostic process
22
+
23
+ :rtype: None
24
+ """
25
+ # set environment and application configuration
26
+ from regscale.core.app.api import Api
27
+
28
+ api = Api()
29
+ api.timeout = 180
30
+
31
+ # create logger function to log to the console
32
+ logger = api.logger
33
+ menu_counter: list = []
34
+ download_url: str = ""
35
+ # import master catalog list
36
+ data = CatalogCompare.get_master_catalogs(api=api)
37
+ # sort master catalogue list
38
+ catalogues = data["catalogs"]
39
+ catalogues.sort(key=operator.itemgetter("title"))
40
+ for i, catalog in enumerate(catalogues):
41
+ index = i + 1
42
+ # print each catalog in the master catalog list
43
+ print(f'{index}: {catalog["title"]}')
44
+ menu_counter.append(index)
45
+ # set status to False to run loop
46
+ status: bool = False
47
+ value: Optional[int] = None
48
+ while not status:
49
+ # select catalog to run diagnostic
50
+ value = click.prompt(
51
+ "Please enter the number of the catalog you would like to run diagnostics on",
52
+ type=int,
53
+ )
54
+ # check if value exist that is selected
55
+ if value < min(menu_counter) or value > max(menu_counter):
56
+ print("That is not a valid selection, please try again")
57
+ else:
58
+ status = True
59
+ # choose catalog to run diagnostics on
60
+ for i, catalog in enumerate(catalogues):
61
+ index = i + 1
62
+ if index == value and catalog["downloadURL"]:
63
+ download_url = catalog["downloadURL"]
64
+ break
65
+ # retrieve new catalog to run diagnostics on
66
+ new_catalog = get_new_catalog(url=download_url)
67
+ # run the diagnostic output for the selected catalog
68
+ save_data_to(
69
+ file=Path("diagnostics.json"),
70
+ data=run_diagnostics(diagnose_cat=new_catalog, logger=logger).dict(),
71
+ )
72
+
73
+
74
+ def run_diagnostics(diagnose_cat: dict, logger: logging.Logger) -> CatalogCompare:
75
+ """
76
+ Function to run diagnostics on a catalog
77
+
78
+ :param dict diagnose_cat: dictionary of a catalog to run diagnostics on
79
+ :param logging.Logger logger: Logger to log to the console
80
+ :return: CatalogCompare object
81
+ :rtype: CatalogCompare
82
+ """
83
+ diagnostic_results = CatalogCompare().run_new_diagnostics(diagnose_cat)
84
+
85
+ # print information to the terminal
86
+ logger.info("The catalog you have selected for diagnostics is:")
87
+ logger.info(diagnostic_results.title)
88
+ logger.info("The uuid for this catalog is:")
89
+ logger.info(diagnostic_results.uuid)
90
+ logger.info("The list of contained keywords in this catalog is:")
91
+ logger.info(diagnostic_results.keywords)
92
+ logger.info(f"The number of CCIs in this catalog is: {diagnostic_results.cci_count}")
93
+ logger.info(f"The number of Objectives in this catalog is: {diagnostic_results.objective_count}")
94
+ logger.info(f"The number of Parameters in this catalog is: {diagnostic_results.parameter_count}")
95
+ logger.info(f"The number of Security Controls in this catalog is: {diagnostic_results.security_control_count}")
96
+ logger.info(f"The number of Tests in this catalog is: {diagnostic_results.test_count}")
97
+ return diagnostic_results
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Add functionality to download a catalog via API."""
4
+ import json.decoder
5
+
6
+ # Standard Imports
7
+ import operator
8
+ from pathlib import Path
9
+ from typing import Optional, Tuple
10
+
11
+ import click # type: ignore
12
+ import requests # type: ignore
13
+
14
+ from regscale.core.app.api import Api
15
+ from regscale.core.app.application import Application
16
+ from regscale.core.app.utils.app_utils import save_data_to
17
+ from regscale.core.app.utils.catalog_utils.common import get_new_catalog, is_valid_url
18
+ from regscale.models.app_models.catalog_compare import CatalogCompare
19
+
20
+ MENU_COUNTER: list = []
21
+
22
+
23
+ def pull_catalogs() -> list[dict]:
24
+ """
25
+ Function to pull the master catalogs from the API
26
+
27
+ :rtype: list[dict]
28
+ :return: The list of master catalogs
29
+ """
30
+ api = Api()
31
+ data = CatalogCompare.get_master_catalogs(api=api)
32
+ # sort master catalog list
33
+ catalogues = data["catalogs"]
34
+ catalogues.sort(key=operator.itemgetter("title"))
35
+ return catalogues
36
+
37
+
38
+ def display_menu(show_menu: bool) -> int:
39
+ """
40
+ Function to display the menu for the catalog export and handle exporting the selected catalog
41
+
42
+ :param bool show_menu: Show the menu
43
+ :rtype: int
44
+ :return: The max index + 1 of the menu (one based for real world)
45
+ """
46
+ api = Api()
47
+ catalogues = pull_catalogs()
48
+ # set environment and application configuration
49
+ api.timeout = 180
50
+ # import master catalog list
51
+ for i, catalog in enumerate(catalogues):
52
+ if show_menu:
53
+ print(f'{i + 1}: {catalog["title"]}')
54
+ MENU_COUNTER.append(i)
55
+ return max(MENU_COUNTER)
56
+
57
+
58
+ def select_catalog(catalog_index: int, logging: bool = True) -> Tuple[dict, dict]:
59
+ """
60
+ Function to download the selected catalog
61
+
62
+ :param int catalog_index: Index of the selected catalog
63
+ :param bool logging: Enable logging
64
+ :rtype: Tuple[dict, dict]
65
+ :return: The new catalog as a dictionary and the registry dict of the selected catalog
66
+ """
67
+ catalogues = pull_catalogs()
68
+ new_catalog = None
69
+ registry_item = None
70
+ app = Application()
71
+ logger = app.logger
72
+ status: bool = False
73
+ value: Optional[int] = None
74
+ download_url: str = ""
75
+ catalog_name: str = ""
76
+ while not status:
77
+ if catalog_index == 0:
78
+ value = click.prompt(
79
+ "Please enter the number of the catalog you would like to download",
80
+ type=int,
81
+ )
82
+ else:
83
+ value = catalog_index
84
+ if MENU_COUNTER and value < min(MENU_COUNTER) or MENU_COUNTER and value > max(MENU_COUNTER):
85
+ print("That is not a valid selection, please try again")
86
+ else:
87
+ status = True
88
+ # Choose catalog to export
89
+ for i, catalog in enumerate(catalogues):
90
+ if i + 1 == value and catalog["url"]:
91
+ registry_item = catalog
92
+ download_url = catalog["downloadURL"].strip()
93
+ logger.debug("ix+1: %i, URL: %s", i + 1, download_url)
94
+ catalog_name = catalog["defaultName"].replace(" ", "_")
95
+ break
96
+ if is_valid_url(download_url):
97
+ new_catalog = get_new_catalog(url=download_url)
98
+ save_data_to(
99
+ file=Path(f"{catalog_name}.json"),
100
+ data=new_catalog,
101
+ output_log=logging,
102
+ )
103
+ return new_catalog, registry_item