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,492 @@
1
+ """Code generation to build automation manager jobs for the platform and click commands for the RegScale CLI"""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
7
+
8
+ from regscale.models.integration_models.synqly_models.connector_types import ConnectorType
9
+ from regscale.models.integration_models.synqly_models.param import Param
10
+
11
+ SUPPORTED_CONNECTORS = [ConnectorType.Ticketing, ConnectorType.Vulnerabilities, ConnectorType.Assets]
12
+
13
+
14
+ def generate_dags() -> None:
15
+ """Generate Airflow DAGs for the platform"""
16
+ from regscale.core.app.utils.app_utils import check_file_path
17
+ from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
18
+
19
+ model = SynqlyModel()
20
+ configs = model._get_integrations_and_secrets(True)
21
+ # iterate through connectors and generate DAGs
22
+ for connector in SUPPORTED_CONNECTORS:
23
+ connector_configs = {
24
+ integration: configs[integration] for integration in configs if connector in integration.lower()
25
+ }
26
+ # sort the connector configs by the key for repeatability
27
+ connector_configs = dict(sorted(connector_configs.items()))
28
+ description = _build_description(configs=connector_configs, connector=connector)
29
+ # check airflow/dags for existing DAGs and skip them
30
+ for integration, config in connector_configs.items():
31
+ save_dir = f"airflow/dags/{integration.split('_')[0].lower()}"
32
+ integration_name = integration[integration.find("_") + 1 :]
33
+ # check if the directory exists, if not create it
34
+ check_file_path(save_dir)
35
+ _create_and_save_dag(
36
+ model=model,
37
+ integration=integration,
38
+ config=config,
39
+ integration_name=integration_name,
40
+ description=description,
41
+ save_dir=save_dir,
42
+ )
43
+
44
+
45
+ def _create_and_save_dag(
46
+ model: "SynqlyModel", integration: str, config: dict, integration_name: str, description: str, save_dir: str
47
+ ) -> None:
48
+ """
49
+ Create and save a DAG for the given integration
50
+
51
+ :param SynqlyModel model: The model to use for the DAG
52
+ :param str integration: The integration to create the DAG for
53
+ :param dict config: The config for the integration
54
+ :param str integration_name: The name of the integration
55
+ :param str description: The description for the DAG
56
+ :param str save_dir: The directory to save the DAG to
57
+ :rtype: None
58
+ """
59
+ import re
60
+
61
+ capabilities = config.get("capabilities", [])
62
+ op_kwargs = ""
63
+ doc_string = f"{description}\nimage: {integration.split('_')[0]}.jpg\ndocs: None\n"
64
+ # replace the integration config with a flattened version
65
+ config = model._flatten_secrets(integration=integration, return_secrets=True)
66
+ for param_type in ["expected_params", "optional_params", "required_secrets"]:
67
+ op_kwargs, doc_string = _build_op_kwargs_and_docstring(
68
+ config=config,
69
+ integration=integration,
70
+ param_type=param_type,
71
+ op_kwargs=op_kwargs,
72
+ doc_string=doc_string,
73
+ capabilities=capabilities,
74
+ )
75
+ # add config to op_kwargs
76
+ op_kwargs += '\n "config": "{{ dag_run.conf }}",'
77
+ # this indent is important to keep the code valid python
78
+ dag_code = f"""
79
+ from airflow import DAG
80
+
81
+ from regscale.airflow.config import DEFAULT_ARGS, yesterday
82
+ from regscale.airflow.hierarchy import AIRFLOW_CLICK_OPERATORS as OPERATORS
83
+ from regscale.airflow.tasks.groups import email_on_fail_operator
84
+
85
+ DAG_NAME = "{integration}"
86
+
87
+ dag = DAG(
88
+ DAG_NAME,
89
+ default_args=DEFAULT_ARGS,
90
+ schedule_interval=None,
91
+ start_date=yesterday(),
92
+ description=__doc__,
93
+ is_paused_upon_creation=False,
94
+ render_template_as_native_obj=True,
95
+ )
96
+
97
+ integration_operator = OPERATORS["{integration.split('_')[0].lower()}__sync_{integration_name.lower()}"]["lambda"](
98
+ dag=dag,
99
+ suffix=DAG_NAME,
100
+ op_kwargs={{{op_kwargs}\n }},
101
+ )
102
+
103
+ email = email_on_fail_operator(dag, email_tag=DAG_NAME)
104
+
105
+ integration_operator >> email
106
+ """
107
+ with open(f"{save_dir}/{integration_name.lower()}.py", "w") as f:
108
+ f.write("# flake8: noqa E501\n# pylint: disable=line-too-long\n")
109
+ f.write('"""')
110
+ # replace all instances of "synqly" with the integration name
111
+ f.write(re.sub(r"(?i)synqly", integration_name, doc_string))
112
+ f.write('"""\n')
113
+ f.write("# pylint: enable=line-too-long\n")
114
+ # replace all instances of "synqly" with the integration name
115
+ f.write(re.sub(r"(?i)synqly", integration_name, dag_code))
116
+ print(f"Generated DAG for {integration_name}.")
117
+
118
+
119
+ def _build_description(configs: dict[str, dict], connector: str) -> str:
120
+ """
121
+ Build the description for the DAG
122
+
123
+ :param dict[str, dict] configs: The configs for the integrations
124
+ :return: The description for the DAG
125
+ :rtype: str
126
+ """
127
+ sync_attachments = []
128
+ integrations = []
129
+ for integration, config in configs.items():
130
+ integration_name = integration.replace(f"{connector.lower()}_", "").replace("_", " ").title()
131
+ integrations.append(integration_name)
132
+ capabilities = config.get("capabilities", [])
133
+ if (
134
+ connector == ConnectorType.Ticketing
135
+ and "create_attachment" in capabilities
136
+ and "download_attachment" in capabilities
137
+ ):
138
+ sync_attachments.append(integration_name)
139
+ description = f"Sync {connector.capitalize()} data between {', '.join(integrations)} and RegScale data."
140
+ if sync_attachments:
141
+ description += f" You are also able to sync attachments between {', '.join(sync_attachments)} and RegScale."
142
+ return description
143
+
144
+
145
+ def _build_op_kwargs_and_docstring(
146
+ config: dict, integration: str, param_type: str, op_kwargs: str, doc_string: str, capabilities: list[str]
147
+ ) -> tuple[str, str]:
148
+ """
149
+ Build the op_kwargs and docstring for the DAG
150
+
151
+ :param dict config: The config for the integration
152
+ :param str integration: The name of the integration, typically connector_integration
153
+ :param str param_type: The type of parameter to build
154
+ :param str op_kwargs: The op_kwargs to add to the DAG
155
+ :param str doc_string: The docstring to add to the DAG
156
+ :param list[str] capabilities: The capabilities of the integration
157
+ :return: The op_kwargs and docstring
158
+ :rtype: tuple[str, str]
159
+ """
160
+ proper_type = param_type.replace("_", " ").title()
161
+ op_kwargs, doc_string = _build_expected_params(
162
+ param_type=param_type,
163
+ integration=integration,
164
+ op_kwargs=op_kwargs,
165
+ doc_string=doc_string,
166
+ capabilities=capabilities,
167
+ )
168
+
169
+ if ConnectorType.Vulnerabilities.lower() in integration and param_type == "optional_params":
170
+ if param_type == "optional_params" and ConnectorType.Vulnerabilities in integration:
171
+ vuln_params: dict[str, Param] = {
172
+ "vuln_filter": Param(
173
+ name="vuln_filter",
174
+ type="choice",
175
+ description="Filter the vulnerabilities for the selected severity. (Options: critical, high, medium, low, info)",
176
+ default=None,
177
+ ),
178
+ "scan_date": Param(
179
+ name="scan_date",
180
+ type="string",
181
+ description="The date of the scan to sync vulnerabilities into RegScale.",
182
+ default="Critical",
183
+ ),
184
+ "all_scans": Param(
185
+ name="all_scans",
186
+ type="boolean",
187
+ description="Whether to sync all vulnerabilities into RegScale.",
188
+ default=False,
189
+ ),
190
+ }
191
+ config[param_type] = {**config[param_type], **vuln_params}
192
+ if config.get(param_type):
193
+ if proper_type not in doc_string:
194
+ doc_string += f"{proper_type}:\n"
195
+ for param in config[param_type]:
196
+ op_kwargs, doc_string = _build_other_params(
197
+ config=config,
198
+ param=param,
199
+ param_type=param_type,
200
+ proper_type=proper_type,
201
+ integration=integration,
202
+ op_kwargs=op_kwargs,
203
+ doc_string=doc_string,
204
+ )
205
+ return op_kwargs, doc_string
206
+
207
+
208
+ def _build_expected_params(
209
+ param_type: str, integration: str, op_kwargs: str, doc_string: str, capabilities: list[str]
210
+ ) -> tuple[str, str]:
211
+ """
212
+ Build the expected params for the DAG and add them to the op_kwargs and docstring
213
+
214
+ :param str param_type: The type of parameter to build
215
+ :param str integration: The name of the integration, typically connector_integration
216
+ :param str op_kwargs: The op_kwargs to add to the DAG
217
+ :param str doc_string: The docstring to add to the DAG
218
+ :param list[str] capabilities: The capabilities of the integration
219
+ :return: The op_kwargs and docstring
220
+ :rtype: tuple[str, str]
221
+ """
222
+ if param_type == "expected_params" and ConnectorType.Ticketing in integration:
223
+ regscale_id_jinja = "'regscale_id'"
224
+ regscale_module_jinja = "'regscale_module'"
225
+ op_kwargs += f'\n "regscale_id": "{{{{ dag_run.conf[{regscale_id_jinja}] }}}}",'
226
+ op_kwargs += f'\n "regscale_module": "{{{{ dag_run.conf[{regscale_module_jinja}] }}}}",'
227
+ doc_string += "Expected Params:\n"
228
+ doc_string += " regscale_id: INTEGER ID from RegScale of the RegScale object\n"
229
+ doc_string += " regscale_module: STRING name of the RegScale module to use with the provided ID\n"
230
+ op_kwargs, doc_string = add_connector_specific_params(capabilities, integration, op_kwargs, doc_string)
231
+ elif param_type == "expected_params":
232
+ regscale_ssp_id_jinja = "'regscale_ssp_id'"
233
+ op_kwargs += f'\n "regscale_ssp_id": "{{{{ dag_run.conf[{regscale_ssp_id_jinja}] }}}}",'
234
+ doc_string += "Expected Params:\n"
235
+ doc_string += " regscale_ssp_id: INTEGER ID from RegScale of the System Security Plan\n"
236
+ op_kwargs, doc_string = add_connector_specific_params(capabilities, integration, op_kwargs, doc_string)
237
+ return op_kwargs, doc_string
238
+
239
+
240
+ def _build_other_params(
241
+ config: dict, param: str, param_type: str, proper_type: str, integration: str, op_kwargs: str, doc_string: str
242
+ ) -> tuple[str, str]:
243
+ """
244
+ Build the other params for the DAG by adding them to the op_kwargs and docstring
245
+
246
+ :param str param_type: The type of parameter to build
247
+ :param str integration: The name of the integration, typically connector_integration
248
+ :param str op_kwargs: The op_kwargs to add to the DAG
249
+ :param str doc_string: The docstring to add to the DAG
250
+ :return: The op_kwargs and docstring
251
+ :rtype: tuple[str, str]
252
+ """
253
+ param_obj: Param = config[param_type][param]
254
+ param_name = f"{integration.lower()}_{param}" if param_type == "required_secrets" else param
255
+ jinja_key = f"'{param_name}'"
256
+ if default := param_obj.default:
257
+ if param_obj.data_type.lower() == "str":
258
+ jinja_default = f"'{default}'"
259
+ else:
260
+ jinja_default = default
261
+ else:
262
+ jinja_default = None
263
+ if param_type == "optional_params":
264
+ op_kwargs += f'\n "{param_name}": "{{{{ dag_run.conf[{jinja_key}] if {jinja_key} in dag_run.conf else {jinja_default} }}}}",'
265
+ doc_string += f" {param_name}: {param_obj.expected_type.upper()} {param_obj.description} {f'(Default: {param_obj.default})' if 'Options' not in param_obj.description else ''}\n"
266
+ else:
267
+ op_kwargs += f'\n "{param_name}": "{{{{ dag_run.conf[{jinja_key}] }}}}",'
268
+ doc_string += f" {param_name}: {param_obj.expected_type.upper()} {param_obj.description or proper_type}\n"
269
+ return op_kwargs, doc_string
270
+
271
+
272
+ def add_connector_specific_params(
273
+ capabilities: list[str], integration: str, op_kwargs: str, doc_string: str
274
+ ) -> tuple[str, str]:
275
+ """
276
+ Updated the op_kwargs and docstring for the DAG to include specific params for the connector based on capabilities
277
+
278
+ :param list[str] capabilities: The capabilities of the integration
279
+ :param str integration: The name of the integration, typically connector_integration
280
+ :param str op_kwargs: The op_kwargs to add to the DAG
281
+ :param str doc_string: The docstring to add to the DAG
282
+ :return: The updated op_kwargs and docstring
283
+ :rtype: tuple[str, str]
284
+ """
285
+ if (
286
+ ConnectorType.Ticketing in integration
287
+ and "create_attachment" in capabilities
288
+ and "download_attachment" in capabilities
289
+ ):
290
+ sync_attachments_jinja = "'sync_attachments'"
291
+ op_kwargs += f'\n "sync_attachments": "{{{{ dag_run.conf[{sync_attachments_jinja}] if {sync_attachments_jinja} in dag_run.conf else False }}}}",'
292
+ doc_string += " sync_attachments: BOOLEAN Whether to sync attachments between integration and RegScale\n"
293
+ return op_kwargs, doc_string
294
+
295
+
296
+ def generate_click_connectors() -> None:
297
+ """Generate Click Connectors for the RegScale CLI"""
298
+ from regscale.core.app.utils.app_utils import check_file_path
299
+ from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
300
+
301
+ model = SynqlyModel()
302
+ configs = model._get_integrations_and_secrets(True)
303
+ # iterate through connectors and generate DAGs
304
+ for connector in SUPPORTED_CONNECTORS:
305
+ save_dir = "regscale/integrations/commercial/synqly"
306
+ check_file_path(save_dir)
307
+ connector_configs = {
308
+ integration: configs[integration] for integration in configs if connector in integration.lower()
309
+ }
310
+ # sort the connector configs by the key for repeatability
311
+ connector_configs = dict(sorted(connector_configs.items()))
312
+ # check airflow/dags for existing DAGs and skip them
313
+ _create_and_save_click_command(
314
+ model=model,
315
+ connector=connector,
316
+ integration_configs=connector_configs,
317
+ save_dir=save_dir,
318
+ )
319
+ # add the new click group to regscale.py
320
+ _add_command_to_regscale(connector)
321
+
322
+
323
+ def _create_and_save_click_command(
324
+ model: "SynqlyModel", connector: str, integration_configs: dict[str, dict], save_dir: str
325
+ ) -> None:
326
+ """
327
+ Create and save a click command for the given integration and connector
328
+
329
+ :param SynqlyModel model: The model to use for the DAG
330
+ :param str connector: The connector type to create click commands for
331
+ :param dict[str, dict] integration_configs: Dictionary containing the integration configs for the given connector
332
+ :param str save_dir: The directory to save the DAG to
333
+ :rtype: None
334
+ """
335
+ integrations_count = 0
336
+ doc_string = f"{connector.capitalize()} connector commands for the RegScale CLI"
337
+ if connector == ConnectorType.Ticketing:
338
+ import_command = "from regscale.models import regscale_id, regscale_module"
339
+ elif connector == ConnectorType.Vulnerabilities:
340
+ import_command = "from datetime import datetime\nfrom regscale.models import regscale_ssp_id"
341
+ else:
342
+ import_command = "from regscale.models import regscale_ssp_id"
343
+ # this indent is important to keep the code valid python
344
+ cli_code = f"""
345
+ \"\"\"{doc_string}\"\"\"\n
346
+ import click
347
+ {import_command}
348
+
349
+
350
+ @click.group()
351
+ def {connector}() -> None:
352
+ \"\"\"{doc_string}\"\"\"
353
+ pass
354
+ """
355
+
356
+ # replace the integration config with a flattened version
357
+ for integration, config in integration_configs.items():
358
+ capabilities = config.get("capabilities", [])
359
+ integration_name = integration[integration.find("_") + 1 :]
360
+ config = model._flatten_secrets(integration=integration, return_secrets=True)
361
+ click_options_and_command = _build_click_options_and_command(
362
+ config=config,
363
+ connector=connector,
364
+ integration_name=integration_name,
365
+ capabilities=capabilities,
366
+ )
367
+ cli_code += f"\n\n{click_options_and_command}"
368
+ integrations_count += 1
369
+
370
+ with open(f"{save_dir}/{connector.lower()}.py", "w") as f:
371
+ f.write("# flake8: noqa E501\n# pylint: disable=line-too-long\n")
372
+ f.write(cli_code)
373
+ f.write("# pylint: enable=line-too-long\n")
374
+ print(f"Generated click commands for {integrations_count} {connector} connector(s).")
375
+
376
+
377
+ def _build_all_params(integration_name: str, connector: str) -> tuple[list[str], list[str], list[str]]:
378
+ """
379
+ Function to build the click options, function params, and function kwargs for the integration
380
+
381
+ :param str integration_name: The name of the integration
382
+ :param str connector: The connector type
383
+ :return: The click options, function params, and function kwargs
384
+ :rtype: tuple[list[str], list[str], list[str]]
385
+ """
386
+ if connector == ConnectorType.Vulnerabilities:
387
+ vuln_filter_option = "@click.option(\n '--vuln_filter',\n help='Filter the vulnerabilities for the selected severity. (Options: critical, high, medium, low, info)',\n required=False,\n type=click.Choice(['critical', 'high', 'medium', 'low', 'info']),\n default=None)\n"
388
+ scan_date_option = f"@click.option(\n '--scan_date',\n help='The date of the scan to sync vulnerabilities from {integration_name}',\n required=False,\n type=click.DateTime(formats=['%Y-%m-%d']),\n default=None)\n"
389
+ all_vulns_flag = f"@click.option(\n '--all_scans',\n help='Whether to sync all vulnerabilities from {integration_name}',\n required=False,\n is_flag=True,\n default=False)\n"
390
+ click_options = ["@regscale_ssp_id()", vuln_filter_option, scan_date_option, all_vulns_flag]
391
+ function_params = ["regscale_ssp_id: int", "vuln_filter: str", "scan_date: datetime", "all_scans: bool"]
392
+ function_kwargs = [
393
+ "regscale_ssp_id=regscale_ssp_id",
394
+ "vuln_filter=vuln_filter",
395
+ "scan_date=scan_date",
396
+ "all_scans=all_scans",
397
+ ]
398
+ elif connector == ConnectorType.Assets:
399
+ click_options = ["@regscale_ssp_id()"]
400
+ function_params = ["regscale_ssp_id: int"]
401
+ function_kwargs = ["regscale_ssp_id=regscale_ssp_id"]
402
+ else:
403
+ click_options = ["@regscale_id()", "@regscale_module()"]
404
+ function_params = ["regscale_id: int", "regscale_module: str"]
405
+ function_kwargs = ["regscale_id=regscale_id", "regscale_module=regscale_module"]
406
+ return click_options, function_params, function_kwargs
407
+
408
+
409
+ def _build_click_options_and_command(
410
+ config: dict, connector: str, integration_name: str, capabilities: list[str]
411
+ ) -> str:
412
+ """
413
+ Function to use the config to build the click options and command for the integration
414
+
415
+ :param dict config: The config for the integration
416
+ :param str connector: The connector type
417
+ :param str integration_name: The name of the integration
418
+ :param list[str] capabilities: The capabilities of the integration
419
+ :return: The click options as a string
420
+ :rtype: str
421
+ """
422
+ doc_string_name = integration_name.replace("_", " ").title()
423
+ # add regscale_ssp_id as a default option
424
+ click_options, function_params, function_kwargs = _build_all_params(doc_string_name, connector)
425
+ for param_type in ["expected_params", "optional_params"]:
426
+ for param in config.get(param_type, []):
427
+ param_data = config[param_type][param]
428
+ if not param_data.click_type:
429
+ continue
430
+ # indentation is important to keep the code valid python
431
+ click_option = f"""@click.option(
432
+ '--{param}',
433
+ type={param_data.click_type},
434
+ help='{config[param_type][param].description}',
435
+ required={not param_data.optional},
436
+ {"prompt='" + config[param_type][param].description + "'," if not param_data.optional else ""}
437
+ )"""
438
+ function_params.append(f"{param}: {param_data.data_type}")
439
+ function_kwargs.append(f"{param}={param}")
440
+ click_options.append(click_option)
441
+ if (
442
+ ConnectorType.Ticketing == connector
443
+ and "create_attachment" in capabilities
444
+ and "download_attachment" in capabilities
445
+ ):
446
+ click_options.append(
447
+ f"""@click.option(
448
+ '--sync_attachments',
449
+ type=click.BOOL,
450
+ help='Whether to sync attachments between {doc_string_name} and RegScale',
451
+ required=False,
452
+ default=True,
453
+ )"""
454
+ )
455
+ function_params.append("sync_attachments: bool")
456
+ function_kwargs.append("sync_attachments=sync_attachments")
457
+ click_options = "\n".join(click_options)
458
+ function_params = ", ".join(function_params)
459
+ # indentation is important to keep the code valid python
460
+ click_command = f"""@{connector}.command(name="sync_{integration_name}")
461
+ {click_options}
462
+ def sync_{integration_name}({function_params}) -> None:
463
+ \"\"\"Sync {connector.title()} {"data between" if connector == ConnectorType.Ticketing else "from"} {doc_string_name} {"and" if connector == ConnectorType.Ticketing else "to"} RegScale.\"\"\"
464
+ from regscale.models.integration_models.synqly_models.connectors import {connector.title()}
465
+ {connector}_{integration_name} = {connector.title()}('{integration_name}')
466
+ {connector}_{integration_name}.run_sync({', '.join(function_kwargs)})
467
+ """
468
+ return click_command
469
+
470
+
471
+ def _add_command_to_regscale(connector: str) -> None:
472
+ """
473
+ Add the new click group and command to the regscale.py file
474
+
475
+ :param str connector: The connector type
476
+ :rtype: None
477
+ """
478
+ import_section = 'burp = import_command_with_timing(COMMERCIAL, "burp")'
479
+ command_section = "cli.add_command(burp) # add Burp File Integration"
480
+ with open("regscale/regscale.py", "r") as f:
481
+ regscale_code = f.read()
482
+ if f"{connector} =" in regscale_code:
483
+ print(f"{connector.title()} click commands already exists in regscale.py.")
484
+ return
485
+ import_line = f'{connector} = import_command_with_timing("regscale.integrations.commercial.synqly.{connector}", "{connector}")'
486
+ regscale_code = regscale_code.replace(import_section, f"{import_section}\n{import_line}")
487
+ regscale_code = regscale_code.replace(
488
+ command_section, f"{command_section}\ncli.add_command({connector}) # add {connector.capitalize()} connector"
489
+ )
490
+ with open("regscale/regscale.py", "w") as f:
491
+ f.write(regscale_code)
492
+ print(f"Added {connector} click group to regscale.py.")
regscale/dev/dirs.py ADDED
@@ -0,0 +1,69 @@
1
+ """Directory paths for regscale package."""
2
+
3
+ import contextlib
4
+ import os
5
+ from pathlib import Path
6
+ from typing import Union, List
7
+ import statistics
8
+
9
+ PROFILING_DIRS = [
10
+ "python3.8",
11
+ "python3.9",
12
+ "python3.10",
13
+ "python3.11",
14
+ "regscale-cli",
15
+ "site-packages",
16
+ ]
17
+
18
+
19
+ def get_regscale_root(file_path: str) -> str:
20
+ """Get the root directory of the regscale directory
21
+
22
+ :param str file_path: Path to a file in the regscale directory
23
+ :return: Path to the root directory of the regscale directory
24
+ :rtype: str
25
+ """
26
+ current_file_path = os.path.abspath(file_path)
27
+ # start climbing the directory tree
28
+ current_dir_path = os.path.dirname(current_file_path)
29
+ # keep climbing until we find the regscale directory
30
+ while True:
31
+ last_part = os.path.basename(current_dir_path)
32
+ if last_part == "regscale":
33
+ # we found the regscale folder, get its parent
34
+ root_dir = os.path.dirname(current_dir_path)
35
+ break
36
+ current_dir_path = os.path.dirname(current_dir_path)
37
+ return root_dir
38
+
39
+
40
+ def trim_relative_subpath(
41
+ path: Union[str, Path] = os.getcwd(),
42
+ target_paths: List[Union[str, Path]] = PROFILING_DIRS,
43
+ ) -> str:
44
+ """Trim the relative subpath from the path
45
+
46
+ :param Union[str, Path] path: The path to trim
47
+ :param List[Union[str, Path]] target_paths: The relative subpaths to trim
48
+ :return: The trimmed path
49
+ :rtype: str
50
+ """
51
+ try:
52
+ path = Path(path)
53
+ except Exception:
54
+ return str(path)
55
+ if not path.is_absolute():
56
+ return str(path)
57
+ path_parts = path.parts
58
+ last_found_index = -1
59
+ for target_path in target_paths:
60
+ if isinstance(target_path, str):
61
+ target_path = Path(target_path)
62
+ target_parts = target_path.parts
63
+ for i, part in enumerate(path_parts):
64
+ if part in target_parts:
65
+ last_found_index = i
66
+ if last_found_index == -1:
67
+ return str(path)
68
+ else:
69
+ return str(Path(*path_parts[last_found_index + 1 :]))