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,632 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Module to allow user to make changes to issues in an excel spreadsheet for user friendly experience"""
4
+
5
+ # standard python imports
6
+ import os
7
+ import shutil
8
+ from typing import Any
9
+
10
+ import click
11
+ from openpyxl import Workbook, load_workbook
12
+ from openpyxl.styles import Protection, NamedStyle
13
+ from openpyxl.worksheet.datavalidation import DataValidation
14
+ from pathlib import Path
15
+ from rich.console import Console
16
+ from rich.table import Table
17
+
18
+ from regscale.core.app.logz import create_logger
19
+ from regscale.core.app.utils.app_utils import (
20
+ check_file_path,
21
+ error_and_exit,
22
+ reformat_str_date,
23
+ get_current_datetime,
24
+ get_user_names,
25
+ check_empty_nan,
26
+ )
27
+ from regscale.models.app_models.click import regscale_id, regscale_module
28
+ from regscale.models.regscale_models.issue import Issue
29
+
30
+ logger = create_logger()
31
+
32
+
33
+ @click.group(name="issues")
34
+ def issues():
35
+ """
36
+ Performs actions on POAM CLI Feature to update issues to RegScale.
37
+ """
38
+
39
+
40
+ @issues.command(name="generate")
41
+ @regscale_id()
42
+ @regscale_module()
43
+ @click.option(
44
+ "--path",
45
+ type=click.Path(exists=False, dir_okay=True, path_type=Path),
46
+ help="Provide the desired path for excel files to be generated into.",
47
+ default=os.path.join(os.getcwd(), "artifacts"),
48
+ required=True,
49
+ )
50
+ def generate_all_issues(regscale_id: int, regscale_module: str, path: Path):
51
+ """
52
+ This function will build and populate a spreadsheet of all issues
53
+ with the selected RegScale Parent Id and RegScale Module for users to make any neccessary edits.
54
+
55
+ """
56
+ all_issues(regscale_id=regscale_id, regscale_module=regscale_module, path=path)
57
+
58
+
59
+ def all_issues(regscale_id: int, regscale_module: str, path: Path) -> None:
60
+ """Function to build excel spreadsheet with all issues matching organizer records given.
61
+
62
+ :param int regscale_id: RegScale Parent Id
63
+ :param str regscale_module: RegScale Parent Module
64
+ :param Path path: directory of file location
65
+ :rtype: None
66
+ """
67
+ # see if provided RegScale Module is an accepted option in Organizer Modules list
68
+ import pandas as pd # Optimize import performance
69
+ from regscale.core.app.api import Api
70
+
71
+ api = Api()
72
+ verify_organizer_module(regscale_module)
73
+
74
+ body = """
75
+ query {
76
+ issues (skip: 0, take: 50, where: {parentId: {eq: parent_id} parentModule: {eq: "parent_module"}}) {
77
+ items {
78
+ id
79
+ issueOwnerId
80
+ issueOwner {
81
+ firstName
82
+ lastName
83
+ userName
84
+ }
85
+ title
86
+ dateCreated
87
+ description
88
+ severityLevel
89
+ costEstimate
90
+ levelOfEffort
91
+ dueDate
92
+ identification
93
+ status
94
+ dateCompleted
95
+ activitiesObserved
96
+ failuresObserved
97
+ requirementsViolated
98
+ safetyImpact
99
+ securityImpact
100
+ qualityImpact
101
+ securityChecks
102
+ recommendedActions
103
+ parentId
104
+ parentModule
105
+ }
106
+ totalCount
107
+ pageInfo {
108
+ hasNextPage
109
+ }
110
+ }
111
+ }
112
+ """.replace(
113
+ "parent_module", regscale_module
114
+ ).replace(
115
+ "parent_id", str(regscale_id)
116
+ )
117
+ existing_issue_data = api.graph(query=body)
118
+
119
+ if (
120
+ existing_issue_data["issues"]["totalCount"] > 0
121
+ ): # Checking to see if assessment exists for selected RegScale Id and RegScale Module.
122
+ check_file_path(path)
123
+
124
+ # Loading data from db into two workbooks.
125
+
126
+ workbook = Workbook()
127
+ worksheet = workbook.active
128
+ worksheet.title = f"Issues({regscale_id}_{regscale_module})"
129
+ workbook.save(filename=os.path.join(path, "all_issues.xlsx"))
130
+ shutil.copy(
131
+ os.path.join(path, "all_issues.xlsx"),
132
+ os.path.join(path, "old_issues.xlsx"),
133
+ )
134
+
135
+ raw_data = existing_issue_data["issues"]["items"]
136
+ issues_data = []
137
+ for a in raw_data:
138
+ issue_id = a["id"]
139
+ issue_owner = (
140
+ (
141
+ str(a["issueOwner"]["lastName"]).strip()
142
+ + ", "
143
+ + str(a["issueOwner"]["firstName"]).strip()
144
+ + " ("
145
+ + str(a["issueOwner"]["userName"]).strip()
146
+ + ")"
147
+ )
148
+ if a["issueOwner"]
149
+ else "None"
150
+ )
151
+ title = a["title"]
152
+ date_created = reformat_str_date(a["dateCreated"])
153
+ description = a["description"] if a["description"] else "None"
154
+ severity_level = a["severityLevel"]
155
+ cost_estimate = a["costEstimate"] if a["costEstimate"] and a["costEstimate"] != "None" else 0.00
156
+ level_of_effort = a["levelOfEffort"] if a["levelOfEffort"] and a["levelOfEffort"] != "None" else 0
157
+ due_date = reformat_str_date(a["dueDate"])
158
+ identification = a["identification"] if a["identification"] else "None"
159
+ status = a["status"] if a["status"] else "None"
160
+ date_completed = reformat_str_date(a["dateCompleted"]) if a["dateCompleted"] else ""
161
+ activities_observed = a["activitiesObserved"] or ""
162
+ failures_observed = a["failuresObserved"] or ""
163
+ requirements_violated = a["requirementsViolated"] or ""
164
+ safety_impact = a["safetyImpact"] or ""
165
+ security_impact = a["securityImpact"] or ""
166
+ quality_impact = a["qualityImpact"] or ""
167
+ security_checks = a["securityChecks"] or ""
168
+ recommended_actions = a["recommendedActions"] or ""
169
+ issues_data.append(
170
+ [
171
+ issue_id,
172
+ issue_owner,
173
+ title,
174
+ date_created,
175
+ description,
176
+ severity_level,
177
+ cost_estimate,
178
+ level_of_effort,
179
+ due_date,
180
+ identification,
181
+ status,
182
+ date_completed,
183
+ activities_observed,
184
+ failures_observed,
185
+ requirements_violated,
186
+ safety_impact,
187
+ security_impact,
188
+ quality_impact,
189
+ security_checks,
190
+ recommended_actions,
191
+ ]
192
+ )
193
+
194
+ all_ass_df = pd.DataFrame(
195
+ issues_data,
196
+ columns=[
197
+ "Id",
198
+ "IssueOwner",
199
+ "Title",
200
+ "DateCreated",
201
+ "Description",
202
+ "SeverityLevel",
203
+ "CostEstimate",
204
+ "LevelOfEffort",
205
+ "DueDate",
206
+ "Identification",
207
+ "Status",
208
+ "DateCompleted",
209
+ "ActivitiesObserved",
210
+ "FailuresObserved",
211
+ "RequirementsViolated",
212
+ "SafetyImpact",
213
+ "SecurityImpact",
214
+ "QualityImpact",
215
+ "SecurityChecks",
216
+ "RecommendedActions",
217
+ ],
218
+ )
219
+
220
+ with pd.ExcelWriter(
221
+ os.path.join(path, "all_issues.xlsx"),
222
+ mode="a",
223
+ engine="openpyxl",
224
+ if_sheet_exists="overlay",
225
+ ) as writer:
226
+ all_ass_df.to_excel(
227
+ writer,
228
+ sheet_name=f"Issues({regscale_id}_{regscale_module})",
229
+ index=False,
230
+ )
231
+ with pd.ExcelWriter(
232
+ os.path.join(path, "old_issues.xlsx"),
233
+ mode="a",
234
+ engine="openpyxl",
235
+ if_sheet_exists="overlay",
236
+ ) as writer:
237
+ all_ass_df.to_excel(
238
+ writer,
239
+ sheet_name=f"Issues({regscale_id}_{regscale_module})",
240
+ index=False,
241
+ )
242
+
243
+ # Pulling in Account Users into Excel Spreasheet to create drop down.
244
+
245
+ with pd.ExcelWriter(
246
+ os.path.join(path, "all_issues.xlsx"),
247
+ mode="a",
248
+ engine="openpyxl",
249
+ if_sheet_exists="overlay",
250
+ ) as writer:
251
+ get_user_names().to_excel(
252
+ writer,
253
+ sheet_name="Accounts",
254
+ index=False,
255
+ )
256
+
257
+ # Pulling in Identifications into separate Excel Spreadsheet to create drop down. (Over 256 character Limit)
258
+
259
+ identification_list = [
260
+ "A-123 Review",
261
+ "Assessment/Audit (External)",
262
+ "Assessment/Audit (Internal)",
263
+ "Critical Control Review",
264
+ "FDCC/USGCB",
265
+ "GAO Audit",
266
+ "IG Audit",
267
+ "Incidnet Response Lessons Learned",
268
+ "ITAR",
269
+ "Other",
270
+ "Penetration Test",
271
+ "Risk Assessment",
272
+ "Security Authorization",
273
+ "Security Control Assessment",
274
+ "Vulnerability Assessment",
275
+ ]
276
+
277
+ identifications = pd.DataFrame({"IdentificationOptions": identification_list})
278
+
279
+ with pd.ExcelWriter(
280
+ os.path.join(path, "all_issues.xlsx"),
281
+ mode="a",
282
+ engine="openpyxl",
283
+ if_sheet_exists="overlay",
284
+ ) as writer:
285
+ identifications.to_excel(
286
+ writer,
287
+ sheet_name="Identifications",
288
+ index=False,
289
+ )
290
+
291
+ # Adding protection to "old_issues.xlsx" file that will be used as reference.
292
+
293
+ workbook2 = load_workbook(os.path.join(path, "old_issues.xlsx"))
294
+ worksheet2 = workbook2.active
295
+ worksheet2.protection.sheet = True
296
+ workbook2.save(filename=os.path.join(path, "old_issues.xlsx"))
297
+
298
+ # Adding Data Validation to "all_issues.xlsx" file to be adjusted internally.
299
+
300
+ workbook = load_workbook(os.path.join(path, "all_issues.xlsx"))
301
+ worksheet = workbook.active
302
+ accounts_worksheet = workbook["Accounts"]
303
+ identifications_worksheet = workbook["Identifications"]
304
+
305
+ accounts_worksheet.protection.sheet = True
306
+ worksheet.protection.sheet = True
307
+ identifications_worksheet.protection.sheet = True
308
+
309
+ # Adding DropDown Menu to Columns to Match RegScale options for fields
310
+
311
+ severitylevels = '"I - High - Signficant Deficiency, II - Moderate - Reportable Condition, III - Low - Other Weakness, IV - Not Asssigned"'
312
+ statuses = '"Closed, Draft, Open, Pending Decommission, Supply Chain/Procurement Dependency, Vendor Dependency for Fix, Delayed, Cancelled, Exception/Waiver"'
313
+
314
+ dv1 = DataValidation(
315
+ type="list",
316
+ formula1="=Accounts!$A$2:$A$" + str(get_maximum_rows(sheet_object=workbook["Accounts"])),
317
+ allow_blank=False,
318
+ showDropDown=False,
319
+ error="Your entry is not one of the available options",
320
+ errorTitle="Invalid Entry",
321
+ prompt="Please select from the list",
322
+ )
323
+ dv2 = DataValidation(
324
+ type="list",
325
+ formula1=severitylevels,
326
+ allow_blank=False,
327
+ showDropDown=False,
328
+ error="Your entry is not one of the available options",
329
+ errorTitle="Invalid Entry",
330
+ prompt="Please select from the list",
331
+ )
332
+ dv3 = DataValidation(
333
+ type="list",
334
+ formula1=statuses,
335
+ allow_blank=True,
336
+ showDropDown=False,
337
+ error="Your entry is not one of the available options",
338
+ errorTitle="Invalid Entry",
339
+ prompt="Please select from the list",
340
+ )
341
+ dv4 = DataValidation(
342
+ type="list",
343
+ formula1="=Identifications!$A$2:$A$" + str(get_maximum_rows(sheet_object=workbook["Identifications"])),
344
+ allow_blank=False,
345
+ showDropDown=False,
346
+ error="Your entry is not one of the available options",
347
+ errorTitle="Invalid Entry",
348
+ prompt="Please select from the list",
349
+ )
350
+
351
+ # Adding Date Style to Worksheet
352
+
353
+ date_style = NamedStyle(name="date_style", number_format="mm/dd/yyyy")
354
+ workbook.add_named_style(date_style)
355
+ currency = '"$"* #,##0.00_);("$"* #,##0.00);"$"* #,##0.00_);'
356
+
357
+ for col in ["D", "G", "I", "L"]:
358
+ for cell in worksheet[col]:
359
+ if col != "G" and cell.row > 1:
360
+ cell.style = date_style
361
+ elif col == "G" and cell.row > 1:
362
+ cell.number_format = currency
363
+
364
+ # Adding data validation to avoid manual error on entry columns
365
+
366
+ dv5 = DataValidation(
367
+ type="date",
368
+ allow_blank=False,
369
+ showErrorMessage=True,
370
+ showInputMessage=True,
371
+ showDropDown=False,
372
+ error="Your entry is not a valid option",
373
+ errorTitle="Invalid Entry",
374
+ prompt="Please enter valid date mm/dd/yyyy",
375
+ )
376
+ dv6 = DataValidation(
377
+ type="date",
378
+ allow_blank=True,
379
+ showErrorMessage=True,
380
+ showInputMessage=True,
381
+ showDropDown=False,
382
+ error="Your entry is not a valid option",
383
+ errorTitle="Invalid Entry",
384
+ prompt="Please enter valid date mm/dd/yyyy",
385
+ )
386
+ dv7 = DataValidation(
387
+ type="whole",
388
+ operator="greaterThanOrEqual",
389
+ formula1=0,
390
+ allow_blank=False,
391
+ showErrorMessage=True,
392
+ showInputMessage=True,
393
+ showDropDown=False,
394
+ error="Your entry is not a valid option",
395
+ errorTitle="Invalid Entry",
396
+ prompt="Please enter valid whole number denoting number of hours.",
397
+ )
398
+ worksheet.add_data_validation(dv1)
399
+ worksheet.add_data_validation(dv2)
400
+ worksheet.add_data_validation(dv3)
401
+ worksheet.add_data_validation(dv4)
402
+ worksheet.add_data_validation(dv5)
403
+ worksheet.add_data_validation(dv6)
404
+ worksheet.add_data_validation(dv7)
405
+ dv1.add("B2:B1048576")
406
+ dv2.add("F2:F1048576")
407
+ dv3.add("K2:K1048576")
408
+ dv4.add("J2:J1048576")
409
+ dv5.add("I2:I1048576")
410
+ dv6.add("D2:D1048576")
411
+ dv6.add("L2:L1048576")
412
+ dv7.add("H2:H1048576")
413
+
414
+ for col in worksheet.columns:
415
+ max_length = 0
416
+ column = col[0].column_letter # Get the column name
417
+ for cell in col:
418
+ if len(str(cell.value)) > max_length:
419
+ max_length = len(str(cell.value))
420
+
421
+ adjusted_width = (max_length + 2) * 1.2
422
+ worksheet.column_dimensions[column].width = adjusted_width
423
+
424
+ # Unlocking cells that can be edited in each Issue.
425
+
426
+ for col in [
427
+ "B",
428
+ "E",
429
+ "F",
430
+ "G",
431
+ "H",
432
+ "I",
433
+ "J",
434
+ "K",
435
+ "L",
436
+ "M",
437
+ "N",
438
+ "O",
439
+ "P",
440
+ "Q",
441
+ "R",
442
+ "S",
443
+ "T",
444
+ ]: # Columns to edit.
445
+ for cell in worksheet[col]:
446
+ cell.protection = Protection(locked=False)
447
+
448
+ workbook.save(filename=os.path.join(path, "all_issues.xlsx"))
449
+
450
+ else:
451
+ logger.info("No Issues exist. Please check your selections for RegScale Id and RegScale Module and try again.")
452
+ error_and_exit("There was an error creating your workbook for the given RegScale Id and RegScale Module.")
453
+
454
+ logger.info(
455
+ "Your data has beeen loaded. Please open the all_issues workbook and make your desired changes %s. " % path
456
+ )
457
+ return None
458
+
459
+
460
+ @issues.command(name="load")
461
+ @click.option(
462
+ "--path",
463
+ type=click.Path(exists=False, dir_okay=True, path_type=Path),
464
+ help="Provide the desired path of excel workbook locations.",
465
+ default=os.path.join(os.getcwd(), "artifacts"),
466
+ required=True,
467
+ )
468
+ def generate_upload_data(path: Path):
469
+ """This function uploads updated issues to the RegScale from the Excel files that users have edited."""
470
+ upload_data(path)
471
+
472
+
473
+ def upload_data(path: Path) -> None:
474
+ """
475
+ This function uploads updated issues to the RegScale.
476
+
477
+ :param Path path: directory of file location
478
+ :rtype: None
479
+ """
480
+ import pandas as pd # Optimize import performance
481
+ import numpy as np # Optimize import performance
482
+
483
+ # Checking all_issues file for differences before updating database
484
+ workbook = load_workbook(os.path.join(path, "all_issues.xlsx"))
485
+ sheet_name = workbook.sheetnames[0]
486
+ sheet_name = sheet_name[sheet_name.find("(") + 1 : sheet_name.find(")")].split("_")
487
+
488
+ # set the variables to the correct values
489
+ for item in set(sheet_name):
490
+ try:
491
+ regscale_parent_id = int(item)
492
+ except ValueError:
493
+ regscale_module = item
494
+
495
+ df1 = pd.read_excel(os.path.join(path, "old_issues.xlsx"), sheet_name=0, index_col="Id")
496
+
497
+ df2 = pd.read_excel(os.path.join(path, "all_issues.xlsx"), sheet_name=0, index_col="Id")
498
+
499
+ if df1.equals(df2):
500
+ logger.info("No differences detected.")
501
+ error_and_exit("No changes were made to the all_issues.xlsx file. Thank you!")
502
+ else:
503
+ logger.warning("*** WARNING *** Differences Found")
504
+
505
+ diff_mask = (df1 != df2) & ~(df1.isnull() & df2.isnull())
506
+ ne_stacked = diff_mask.stack()
507
+ changed = ne_stacked[ne_stacked]
508
+ changed.index.names = ["Id", "Column"]
509
+ difference_locations = np.where(diff_mask)
510
+ changed_to = df1.values[difference_locations]
511
+ changed_from = df2.values[difference_locations]
512
+ changes = pd.DataFrame({"From": changed_from, "To": changed_to}, index=changed.index)
513
+ changes.to_csv(
514
+ os.path.join(path, "differences.txt"),
515
+ header=True,
516
+ index=True,
517
+ sep=" ",
518
+ mode="a",
519
+ )
520
+
521
+ diff = pd.read_csv(os.path.join(path, "differences.txt"), header=0, sep=" ", index_col=None)
522
+ ids = []
523
+ for i, row in diff.iterrows():
524
+ ids.append(row["Id"])
525
+
526
+ id_df = pd.DataFrame(ids, index=None, columns=["Id"])
527
+ id_df2 = id_df.drop_duplicates()
528
+ updated_file = os.path.join(path, "all_issues.xlsx")
529
+
530
+ reader = pd.read_excel(updated_file)
531
+ updated = reader[reader["Id"].isin(id_df2["Id"])]
532
+
533
+ accounts = pd.read_excel(updated_file, sheet_name="Accounts")
534
+ accounts = accounts.rename(columns={"User": "IssueOwner", "UserId": "IssueOwnerId"})
535
+ updated = updated.merge(accounts, how="left", on="IssueOwner")
536
+ updated = updated.T.to_dict()
537
+ updated_issues = [
538
+ Issue(
539
+ id=value["Id"],
540
+ issueOwnerId=value["IssueOwnerId"],
541
+ title=value["Title"],
542
+ dateCreated=value["DateCreated"],
543
+ description=value["Description"],
544
+ severityLevel=value["SeverityLevel"],
545
+ costEstimate=value["CostEstimate"],
546
+ levelOfEffort=value["LevelOfEffort"],
547
+ dueDate=value["DueDate"],
548
+ identification=check_empty_nan(value["Identification"], "Other"),
549
+ status=value["Status"],
550
+ dateCompleted=check_empty_nan(value["DateCompleted"], ""),
551
+ activitiesObserved=check_empty_nan(value["ActivitiesObserved"]),
552
+ failuresObserved=check_empty_nan(value["FailuresObserved"]),
553
+ requirementsViolated=check_empty_nan(value["RequirementsViolated"]),
554
+ safetyImpact=check_empty_nan(value["SafetyImpact"]),
555
+ securityImpact=check_empty_nan(value["SecurityImpact"]),
556
+ qualityImpact=check_empty_nan(value["QualityImpact"]),
557
+ securityChecks=check_empty_nan(value["SecurityChecks"]),
558
+ recommendedActions=check_empty_nan(value["RecommendedActions"]),
559
+ dateLastUpdated=get_current_datetime(),
560
+ parentModule=regscale_module,
561
+ parentId=regscale_parent_id,
562
+ )
563
+ for value in updated.values()
564
+ ]
565
+ Issue.batch_update(updated_issues)
566
+ logger.info("Changes made to existing files can be seen in differences.txt file. Thank you! %s" % path)
567
+ return None
568
+
569
+
570
+ @issues.command(name="delete_files")
571
+ @click.option(
572
+ "--path",
573
+ type=click.Path(exists=False, dir_okay=True, path_type=Path),
574
+ help="Provide the desired path of excel workbook locations.",
575
+ default=os.path.join(os.getcwd(), "artifacts"),
576
+ required=True,
577
+ )
578
+ def generate_delete_file(path: Path):
579
+ """This function deletes files used during the POAM Editor process."""
580
+ delete_file(path)
581
+
582
+
583
+ def delete_file(path: Path) -> None:
584
+ """
585
+ Deletes files used during the process.
586
+
587
+ :param Path path: Path for artifacts folder or location of excel files
588
+ :rtype: None
589
+ """
590
+ os.remove(os.path.join(path, "all_issues.xlsx"))
591
+ os.remove(os.path.join(path, "old_issues.xlsx"))
592
+ if os.path.isfile(os.path.join(path, "differences.txt")):
593
+ os.remove(os.path.join(path, "differences.txt"))
594
+ else:
595
+ pass
596
+ logger.info("Files have been deleted. Thank you.")
597
+ return None
598
+
599
+
600
+ def get_maximum_rows(*, sheet_object: Any) -> int:
601
+ """This function finds the last row containing data in a spreadsheet
602
+
603
+ :param Any sheet_object: excel worksheet to be referenced
604
+ :return: integer representing last row with data in spreadsheet
605
+ :rtype: int
606
+ """
607
+ return sum(any(col.value is not None for col in row) for max_row, row in enumerate(sheet_object, 1))
608
+
609
+
610
+ def verify_organizer_module(module: str) -> None:
611
+ """
612
+ Function to check the provided module is a valid RegScale Organizer Module and will display the acceptable RegScale modules
613
+
614
+ :param str module: desired module
615
+ :rtype: None
616
+ """
617
+
618
+ # create console and table objects
619
+ console = Console()
620
+ table = Table("RegScale Module", "Accepted Value", title="RegScale Modules", safe_box=True)
621
+
622
+ # list of RegScaleOrganizer Modules
623
+ organizers = ["components", "policies", "projects", "securityplans", "supplychain"]
624
+
625
+ # iterate through items and add them to table object
626
+ for i in range(len(organizers)):
627
+ table.add_row(organizers[i], organizers[i])
628
+
629
+ if module not in organizers:
630
+ # print the table object in console
631
+ console.print(table)
632
+ error_and_exit("Please provide an option from the Accepted Value column.")