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,128 @@
1
+ {% extends "base.html" %}
2
+ {% block content %}
3
+ <style>
4
+ .level-info {
5
+ color: forestgreen;
6
+ }
7
+
8
+ .level-warning {
9
+ color: yellow
10
+ }
11
+
12
+ .level-error {
13
+ color: red
14
+ }
15
+
16
+ ul {
17
+ list-style-type: none;
18
+ padding: 0;
19
+ margin: 0;
20
+ }
21
+
22
+ li {
23
+ display: flex;
24
+ align-items: baseline;
25
+ }
26
+
27
+ li .number {
28
+ width: 50px;
29
+ text-align: right;
30
+ font-family: monospace;
31
+ padding-right: 10px;
32
+ }
33
+
34
+ li .text {
35
+ flex: 1;
36
+ }
37
+
38
+ .event-text {
39
+ word-wrap: break-word;
40
+ word-break: break-all;
41
+ }
42
+
43
+ .event-text-word-break {
44
+ word-wrap: break-word;
45
+ word-break: break-word;
46
+ }
47
+ </style>
48
+ <div class="row">
49
+ <div class="col-md-12">
50
+ <div style="padding: '10px'; display: 'grid'; justify-items: 'center'; align-items: 'center'; width: '100%';">
51
+ <div style="display: grid; justify-items: center; align-items: center;">
52
+ <h2>Security Plan Processing Results for Source Document "{{ filename }}"</h2>
53
+ <br>
54
+ <h1>System Security Plan Created!</h1>
55
+ <h3 style="padding: 5px;"><i>"{{result_output.ssp_title}}" (# {{ result_output.ssp_id }}) in
56
+ RegScale</i></h3>
57
+ <br>
58
+ <a href="{{ site_info.domain }}/form/securityplans/{{ result_output.ssp_id }}"
59
+ target="_blank"
60
+ style="text-align: center;"
61
+ rel="noopener"
62
+ >
63
+ <button type="button" class="btn btn-primary" target="_blank">
64
+ View Security Plan In RegScale &#x2197;
65
+ </button>
66
+ </a>
67
+ </div>
68
+ <p>&nbsp;</p>
69
+ <div class="col-md-12 border bg-light" style="padding: 20px; border-radius: 10px;">
70
+ <h2 class="level-info">Summary</h2>
71
+ <div style="padding: 10px; border-radius: 10px;">
72
+ <h2><b>{{ results.Info + results.Error }}</b> Items in source document processed</h2>
73
+ <ul style="font-size: 1.25em;">
74
+ <li><span class="number"><b>{{ results.Info }}</b></span><span class="text">Items successfully mapped to created Security Plan</span></li>
75
+ <li><span class="number"><b>{{ results.Error }}</b></span><span class="text">Items failed to map to created Security Plan</span></li>
76
+ <li><span class="number"><b>{{ result_output.implementations_loaded }}</b></span><span class="text">Control items successfully mapped to created Security Plan<span class="text"></li>
77
+ </ul>
78
+ <hr>
79
+ <h3>{{ (results.Info / (results.Info + results.Error) *
80
+ 100)|round(1)}}% <i>Item processing success rate</i>
81
+ </h3>
82
+ </div>
83
+ </div>
84
+ <p>&nbsp;</p>
85
+ <div class="col-md-12 border bg-light" style="padding: 20px; border-radius: 10px;">
86
+ <h2 class="level-info">Items by Category</h2>
87
+ <ul>
88
+ {% for item in category_counts.items() %}
89
+ <li><span class="number">{{ item[1] }}</span><span class="text">{{ item[0] }}</span></li>
90
+ {% endfor %}
91
+ </ul>
92
+ <br>
93
+
94
+ </div>
95
+ </div>
96
+ <p>&nbsp;</p>
97
+ <div class="col-md-12">
98
+ <div class="p-12 border bg-light" style="padding: 10px; border-radius: 10px;">
99
+
100
+ {% for level, rows in csv_data_grouped.items()%}
101
+ <h2 class="level-{{ level|lower }}">{{ level }} Results</h2>
102
+ <caption><i>The {{ level|lower }} statements found processing source document.</i></caption>
103
+ <table style="table-layout: fixed; width: 100%;">
104
+ <thead>
105
+ <tr style="text-align: left;">
106
+ <th class="event-text-word-break" style="width: 20%;">NIST Model Layer Item</th>
107
+ <th style="width: 20%;">Record Type</th>
108
+ <th style="width: 60%;">Event</th>
109
+ </tr>
110
+ </thead>
111
+ <tbody>
112
+ {% for row in rows %}
113
+ <tr>
114
+ <td class="event-text-word-break">{{ row['model_layer'] }}</td>
115
+ <td class="event-text-word-break">{{ row['record_type'] }}</td>
116
+ <td class="event-text">{{ row['event'] }}</td>
117
+ </tr>
118
+ {% endfor %}
119
+ </tbody>
120
+ </table>
121
+ {% endfor %}
122
+
123
+ </div>
124
+ </div>
125
+
126
+ </div>
127
+
128
+ {% endblock %}
File without changes
@@ -0,0 +1,14 @@
1
+ """Compiled Regexes for use."""
2
+
3
+ import re
4
+
5
+
6
+ URL_REGEX = re.compile(
7
+ r"^(?:http)s?://" # http:// or https://
8
+ r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" # domain...
9
+ r"localhost|" # localhost...
10
+ r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip
11
+ r"(?::\d+)?" # optional port
12
+ r"(?:/?|[/?]\S+)$",
13
+ re.IGNORECASE,
14
+ )
@@ -0,0 +1,117 @@
1
+ """Utility functions for the application"""
2
+
3
+ from typing import Union, Optional
4
+
5
+ UDP = "UDP"
6
+ TCP = "TCP"
7
+ TCP_UDP = "TCP/UDP"
8
+
9
+
10
+ def snakify(name: str) -> str:
11
+ """
12
+ Convert a string to snake_case
13
+
14
+ :param str name: String to convert
15
+ :returns: String in snake_case
16
+ :rtype: str
17
+ """
18
+ return name.lower().replace(" ", "_")
19
+
20
+
21
+ def get_protocol_from_port(port: Union[int, str]) -> Optional[str]:
22
+ """
23
+ Determines the protocol from a port number for well known ports
24
+
25
+ :param Union[int, str] port: Port number (int or str)
26
+ :returns: Protocol name or None if not found
27
+ :rtype: Optional[str]
28
+ """
29
+ port_to_protocol = {
30
+ 20: "FTP", # File Transfer Protocol (FTP) Data Transfer
31
+ 21: "FTP", # File Transfer Protocol (FTP) Command Control
32
+ 22: "SSH", # Secure Shell (SSH)
33
+ 23: "Telnet", # Telnet protocol
34
+ 25: "SMTP", # Simple Mail Transfer Protocol (SMTP)
35
+ 53: "DNS", # Domain Name System (DNS)
36
+ 67: "DHCP", # Dynamic Host Configuration Protocol (DHCP) Server
37
+ 68: "DHCP", # Dynamic Host Configuration Protocol (DHCP) Client
38
+ 80: "HTTP", # Hypertext Transfer Protocol (HTTP)
39
+ 110: "POP3", # Post Office Protocol v3 (POP3)
40
+ 123: "NTP", # Network Time Protocol (NTP)
41
+ 143: "IMAP", # Internet Message Access Protocol (IMAP)
42
+ 161: "SNMP", # Simple Network Management Protocol (SNMP)
43
+ 162: "SNMP", # Simple Network Management Protocol (SNMP) Trap
44
+ 443: "HTTPS", # Hypertext Transfer Protocol Secure (HTTPS)
45
+ 445: "SMB", # Server Message Block (SMB)
46
+ 465: "SMTPS", # Simple Mail Transfer Protocol Secure (SMTPS)
47
+ 993: "IMAPS", # Internet Message Access Protocol Secure (IMAPS)
48
+ 995: "POP3S", # Post Office Protocol 3 Secure (POP3S)
49
+ 1433: "MSSQL", # Microsoft SQL Server
50
+ 3306: "MySQL", # MySQL Database Service
51
+ 3389: "RDP", # Remote Desktop Protocol (RDP)
52
+ 5432: "PostgreSQL", # PostgreSQL Database
53
+ 5672: "AMQP", # Advanced Message Queuing Protocol (AMQP)
54
+ 5900: "VNC", # Virtual Network Computing (VNC)
55
+ 6379: "Redis", # Redis Key-Value Store
56
+ 8080: "HTTP-ALT", # Alternative HTTP
57
+ 8443: "HTTPS-ALT", # Alternative HTTPS
58
+ 27017: "MongoDB", # MongoDB Database
59
+ }
60
+
61
+ port = int(port) # Ensure port is an integer
62
+
63
+ return port_to_protocol.get(port, None)
64
+
65
+
66
+ def get_base_protocol_from_port(port: Union[int, str]) -> str:
67
+ """
68
+ Returns the well-known base protocol for a port such as TCP, UDP, both TCP/UDP, or other based on the port number
69
+ :param Union[int, str] port: Port number
70
+ :returns: Protocol category
71
+ :rtype: str
72
+ """
73
+ port = int(port) # Ensure port is an integer
74
+
75
+ both_tcp_udp_ports = [
76
+ 20,
77
+ 21,
78
+ 22,
79
+ 23,
80
+ 25,
81
+ 53,
82
+ 80,
83
+ 110,
84
+ 123,
85
+ 143,
86
+ 161,
87
+ 162,
88
+ 443,
89
+ 465,
90
+ 993,
91
+ 995,
92
+ 1433,
93
+ 3306,
94
+ 3389,
95
+ 5432,
96
+ 5672,
97
+ 5900,
98
+ 6379,
99
+ 8080,
100
+ 8443,
101
+ 27017,
102
+ ]
103
+ well_known_udp_ports = [7, 9, 19, 49, 67, 68, 69, 123, 161, 162, 514]
104
+ well_known_tcp_ports = list(set(range(0, 1024)) - set(well_known_udp_ports) - set(both_tcp_udp_ports))
105
+
106
+ if port in well_known_udp_ports:
107
+ return UDP # Well-known ports for UDP
108
+ elif port in both_tcp_udp_ports:
109
+ return TCP_UDP # Ports used for both TCP and UDP
110
+ elif port in well_known_tcp_ports:
111
+ return TCP # Well-known ports for TCP
112
+ elif 1024 <= port <= 49151:
113
+ return TCP_UDP # Registered ports for both TCP and UDP
114
+ elif 49152 <= port <= 65535:
115
+ return TCP_UDP # Dynamic or private ports for both TCP and UDP
116
+ else:
117
+ return "Other" # Ports that don't fit into the standard categories
@@ -0,0 +1,13 @@
1
+ """Use the click methods to generate an importable click hierarchy."""
2
+
3
+ from regscale.regscale import cli
4
+ from regscale.utils.click_utils import process_click_group
5
+
6
+ REGSCALE_CLI = process_click_group(group=cli, prefix="regscale")
7
+
8
+ REGSCALE_CLI_SERIALIZABLE = process_click_group(group=cli)
9
+
10
+ if __name__ == "__main__":
11
+ from pprint import pprint
12
+
13
+ pprint(REGSCALE_CLI)
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Utility functions for handling date and datetime conversions"""
4
+
5
+ import datetime
6
+ import logging
7
+ from typing import List, Union, Optional
8
+
9
+ from pandas import Timestamp
10
+ from dateutil.parser import parse, ParserError
11
+
12
+
13
+ logger = logging.getLogger("regscale")
14
+ default_date_format = "%Y-%m-%dT%H:%M:%S%z"
15
+
16
+
17
+ def date_str(date_object: Union[str, datetime.datetime, datetime.date, None], date_format: Optional[str] = None) -> str:
18
+ """
19
+ Convert a date/datetime object to a date string.
20
+
21
+ :param Union[str, datetime.datetime, datetime.date, None] date_object: The date/datetime object to convert.
22
+ :param Optional[str] date_format: The format to use for the date string.
23
+ :return: The date as a string.
24
+ """
25
+ if isinstance(date_object, str):
26
+ date_object = date_obj(date_object)
27
+ if isinstance(date_object, datetime.datetime):
28
+ if date_format:
29
+ return date_object.strftime(date_format)
30
+ return date_object.date().isoformat()
31
+ if isinstance(date_object, datetime.date):
32
+ if date_format:
33
+ return date_object.strftime(date_format)
34
+ return date_object.isoformat()
35
+ if isinstance(date_object, Timestamp):
36
+ return date_object.date().isoformat()
37
+ return ""
38
+
39
+
40
+ def datetime_str(
41
+ date_object: Union[str, datetime.datetime, datetime.date, None], date_format: Optional[str] = None
42
+ ) -> str:
43
+ """
44
+ Convert a date/datetime object to a datetime string.
45
+
46
+ :param Union[str, datetime.datetime, datetime.date, None] date_object: The date/datetime object to convert.
47
+ :param Optional[str] date_format: The format to use for the datetime string.
48
+ :return: The datetime as a string.
49
+ """
50
+ if not date_format:
51
+ date_format = default_date_format
52
+ if isinstance(date_object, str):
53
+ date_object = datetime_obj(date_object)
54
+ if isinstance(date_object, datetime.datetime):
55
+ return date_object.strftime(date_format)
56
+ if isinstance(date_object, datetime.date):
57
+ return date_object.strftime(date_format)
58
+ return ""
59
+
60
+
61
+ def date_obj(date_str: Union[str, datetime.datetime, datetime.date, int, None]) -> Optional[datetime.date]:
62
+ """
63
+ Convert a string, datetime, date, or integer to a date object.
64
+
65
+ :param Union[str, datetime.datetime, datetime.date, int] date_str: The value to convert.
66
+ :return: The date object.
67
+ """
68
+ if isinstance(date_str, (str, int)):
69
+ dt_obj = datetime_obj(date_str)
70
+ return dt_obj.date() if dt_obj else None
71
+ if isinstance(date_str, datetime.datetime):
72
+ return date_str.date()
73
+ if isinstance(date_str, datetime.date):
74
+ return date_str
75
+ return None
76
+
77
+
78
+ def datetime_obj(date_str: Union[str, datetime.datetime, datetime.date, int, None]) -> Optional[datetime.datetime]:
79
+ """
80
+ Convert a string, datetime, date, integer, or timestamp string to a datetime object.
81
+
82
+ :param Union[str, datetime.datetime, datetime.date, int, None] date_str: The value to convert.
83
+ :return: The datetime object.
84
+ """
85
+ if isinstance(date_str, str):
86
+ # Check if the string looks like a timestamp integer
87
+ if date_str.isdigit():
88
+ return datetime.datetime.fromtimestamp(int(date_str))
89
+ try:
90
+ return parse(date_str)
91
+ except ParserError as e:
92
+ if date_str and str(date_str).lower() not in ["n/a", "none"]:
93
+ logger.warning(f"Warning could not parse date string: {date_str}\n{e}")
94
+ return None
95
+ if isinstance(date_str, datetime.datetime):
96
+ return date_str
97
+ if isinstance(date_str, datetime.date):
98
+ return datetime.datetime.combine(date_str, datetime.datetime.min.time())
99
+ if isinstance(date_str, int):
100
+ return datetime.datetime.fromtimestamp(date_str)
101
+ return None
102
+
103
+
104
+ def time_str(time_obj: Union[str, datetime.datetime, datetime.time]) -> str:
105
+ """
106
+ Convert a datetime/time object to a string.
107
+
108
+ :param Union[str, datetime.datetime, datetime.time] time_obj: The datetime/time object to convert.
109
+ :return: The time as a string.
110
+ """
111
+ if isinstance(time_obj, str):
112
+ return time_obj
113
+ if isinstance(time_obj, datetime.datetime):
114
+ time_obj = time_obj.time()
115
+ if isinstance(time_obj, datetime.time):
116
+ return time_obj.__format__("%-I:%M%p")
117
+ return ""
118
+
119
+
120
+ def time_widget_str(time_obj: Union[str, datetime.datetime, datetime.time]) -> str:
121
+ """
122
+ Convert a time object to a string for a widget.
123
+
124
+ :param Union[str, datetime.datetime, datetime.time] time_obj: The time object to convert.
125
+ :return: The time as a string for a widget.
126
+ """
127
+ if isinstance(time_obj, str):
128
+ return time_obj
129
+ if isinstance(time_obj, datetime.datetime):
130
+ time_obj = time_obj.time()
131
+ if isinstance(time_obj, datetime.time):
132
+ return time_obj.__format__("%-I:%M ") + time_obj.__format__("%p").lower()
133
+ return ""
134
+
135
+
136
+ def parse_time(time_str: str) -> datetime.time:
137
+ """
138
+ Parse a time string.
139
+
140
+ :param str time_str: The time string to parse.
141
+ :return: The parsed time.
142
+ :rtype: datetime.time
143
+ """
144
+ try:
145
+ return parse(f"1/1/2011 {time_str.zfill(4)}").time()
146
+ except ValueError:
147
+ return parse(f"1/1/2011 {time_str.zfill(len(time_str) + 1)}").time()
148
+
149
+
150
+ def is_weekday(date_obj: datetime.date) -> bool:
151
+ """
152
+ Check if a date is a weekday.
153
+
154
+ :param datetime.date date_obj: The date to check.
155
+ :return: True if the date is a weekday, False otherwise.
156
+ :rtype: bool
157
+ """
158
+ return date_obj.weekday() < 5
159
+
160
+
161
+ def days_between(
162
+ start: Union[str, datetime.datetime, datetime.date],
163
+ end: Union[str, datetime.datetime, datetime.date],
164
+ ) -> List[str]:
165
+ """
166
+ Get the days between two dates.
167
+
168
+ :param Union[str, datetime.datetime, datetime.date] start: The start date.
169
+ :param Union[str, datetime.datetime, datetime.date] end: The end date.
170
+ :return: A list of dates between the start and end dates.
171
+ """
172
+ delta = date_obj(end) - date_obj(start)
173
+ return [(date_obj(start) + datetime.timedelta(days=i)).strftime("%Y/%m/%d") for i in range(delta.days + 1)]
174
+
175
+
176
+ def weekend_days_between(
177
+ start: Union[str, datetime.datetime, datetime.date],
178
+ end: Union[str, datetime.datetime, datetime.date],
179
+ ) -> List[str]:
180
+ """
181
+ Get the weekend days between two dates.
182
+
183
+ :param Union[str, datetime.datetime, datetime.date] start: The start date.
184
+ :param Union[str, datetime.datetime, datetime.date] end: The end date.
185
+ :return: A list of weekend dates between the start and end dates.
186
+ """
187
+ return [day for day in days_between(start, end) if not is_weekday(date_obj(day))]
188
+
189
+
190
+ def days_from_today(i: int) -> datetime.date:
191
+ """
192
+ Get the date a certain number of days from today.
193
+
194
+ :param int i: The number of days from today.
195
+ :return: The date i days from today.
196
+ :rtype: datetime.date
197
+ """
198
+ return datetime.date.today() + datetime.timedelta(days=i)
199
+
200
+
201
+ def get_day_increment(
202
+ start: Union[str, datetime.datetime, datetime.date],
203
+ days: int,
204
+ excluded_dates: Optional[List[Union[str, datetime.datetime, datetime.date]]] = None,
205
+ ) -> datetime.date:
206
+ """
207
+ Get the date a certain number of days from a start date, excluding certain dates.
208
+
209
+ :param Union[str, datetime.datetime, datetime.date] start: The start date.
210
+ :param int days: The number of days from the start date.
211
+ :param Optional[List[Union[str, datetime.datetime, datetime.date]]] excluded_dates: A list of dates to exclude.
212
+ :return: The date days days from the start date, excluding the excluded dates.
213
+ """
214
+ start = date_obj(start)
215
+ end = start + datetime.timedelta(days=days)
216
+ if excluded_dates:
217
+ for excluded_date in sorted([date_obj(x) for x in excluded_dates]):
218
+ if start <= excluded_date <= end:
219
+ end += datetime.timedelta(days=1)
220
+ return end
221
+
222
+
223
+ def normalize_date(dt: str, fmt: str) -> str:
224
+ """
225
+ Normalize string date to a standard format, if possible.
226
+
227
+ :param str dt: Date to normalize
228
+ :param str fmt: Format of the date
229
+ :return: Normalized Date
230
+ :rtype: str
231
+ """
232
+ if isinstance(dt, str):
233
+ try:
234
+ new_dt = datetime.datetime.strptime(dt, fmt)
235
+ return new_dt.strftime("%Y-%m-%d %H:%M:%S")
236
+ except ValueError:
237
+ return dt
238
+ return dt