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,495 @@
1
+ #!/usr/bin/python
2
+ """Script to parse a .xlsx file and load the inventory into RegScale as assets"""
3
+
4
+ import json
5
+ import os
6
+ import re
7
+ from datetime import datetime
8
+ from json import JSONDecodeError
9
+ from typing import Any, Dict, List, Optional, Union, Literal
10
+
11
+ import rich.progress
12
+
13
+ from regscale.core.app.api import Api
14
+ from regscale.core.app.utils.app_utils import create_logger, create_progress_object, check_file_path
15
+ from regscale.core.utils.date import date_str
16
+ from regscale.models import Asset, ImportValidater, Property
17
+
18
+ api = Api()
19
+ config = api.config
20
+ SOFTWARE_VENDOR = "Software/ Database Vendor"
21
+ SOFTWARE_NAME = "Software/ Database Name & Version"
22
+ PATCH_LEVEL = "Patch Level"
23
+ HARDWARE_MAKE = "Hardware Make/Model"
24
+ MAC_ADDRESS = "MAC Address"
25
+ OS_NAME = "OS Name and Version"
26
+ fmt = "%Y-%m-%d %H:%M:%S"
27
+ UNIQUE_ASSET_IDENTIFIER = "UNIQUE ASSET IDENTIFIER"
28
+ NETBIOS_NAME = "NetBIOS Name"
29
+ BASELINE_CONFIGURATION_NAME = "Baseline Configuration Name"
30
+ SERIAL_NUMBER = "Serial #/Asset Tag#"
31
+ DNS_NAME = "DNS Name or URL"
32
+ AUTHENTICATED_SCAN = "Authenticated Scan"
33
+ IN_LATEST_SCAN = "In Latest Scan"
34
+ IPV4_OR_IPV6_ADDRESS = "IPv4 or IPv6\nAddress"
35
+ ASSET_TYPE = "Asset Type"
36
+ VLAN_NETWORK_ID = "VLAN/\nNetwork ID"
37
+ FUNCTION = "Function"
38
+
39
+
40
+ def check_text(text: Optional[str] = None) -> str:
41
+ """
42
+ Check for NULL values and return empty string if NULL
43
+ :param Optional[str] text: string to check if it is NULL, defaults to None
44
+ :return: empty string if NULL, otherwise the string
45
+ :rtype: str
46
+ """
47
+ return str(text or "")
48
+
49
+
50
+ def save_to_json(file_name: str, data: Any) -> None:
51
+ """
52
+ Save the data to a JSON file
53
+ :param str file_name: name of the file to save
54
+ :param Any data: data to save to the file
55
+ :rtype: None
56
+ """
57
+ if not data:
58
+ return
59
+ if isinstance(data, list) and isinstance(data[0], Asset):
60
+ lst = []
61
+ for item in data:
62
+ lst.append(item.dict())
63
+ data = lst
64
+
65
+ elif not isinstance(data, str):
66
+ lst = []
67
+ for key, value in data.items():
68
+ lst.append(data[key]["asset"].dict())
69
+ data = lst
70
+
71
+ if file_name.endswith(".json"):
72
+ file_name = file_name[:-5]
73
+ with open(f"{file_name}.json", "w") as outfile:
74
+ outfile.write(json.dumps(data, indent=4))
75
+
76
+
77
+ def map_str_to_bool(value: Optional[Union[bool, str]] = None) -> bool:
78
+ """
79
+ Map a string to a boolean value
80
+ :param Optional[Union[bool, str]] value: string or bool value to map to a bool, defaults to False
81
+ :return: boolean value
82
+ :rtype: bool
83
+ """
84
+ import math
85
+
86
+ if isinstance(value, bool):
87
+ return value
88
+ if isinstance(value, float) and math.isnan(value):
89
+ return False
90
+ if value.lower() in ["yes", "true"]:
91
+ return True
92
+ elif value.lower() in ["no", "false"]:
93
+ return False
94
+ else:
95
+ return False
96
+
97
+
98
+ def determine_ip_address_version(ip_address: Optional[str] = None) -> Optional[str]:
99
+ """
100
+ Determine if the IP address is IPv4 or IPv6
101
+ :param Optional[str] ip_address: IP address to check, defaults to None
102
+ :return: Key for the IP address version in the asset object
103
+ :rtype: Optional[str]
104
+ """
105
+ if not isinstance(ip_address, str) or not ip_address:
106
+ return None
107
+ ip_address = ip_address.strip()
108
+
109
+ # IPv4 pattern - matches numbers 1-255 for first octet and 0-255 for remaining octets
110
+ ipv4_pattern = (
111
+ r"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\." # First octet: 1-255
112
+ r"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\." # Second octet: 0-255
113
+ r"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\." # Third octet: 0-255
114
+ r"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$" # Fourth octet: 0-255
115
+ )
116
+
117
+ # IPv6 pattern - handles all valid IPv6 formats including compressed notation
118
+ ipv6_pattern = (
119
+ r"^(?:"
120
+ r"(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|"
121
+ r"(?:[0-9a-fA-F]{1,4}:){1,7}:|"
122
+ r"(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"
123
+ r"(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|"
124
+ r"(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|"
125
+ r"(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|"
126
+ r"(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|"
127
+ r"[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|"
128
+ r":(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|"
129
+ r"fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|"
130
+ r"::(?:ffff(?::0{1,4})?:)?(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
131
+ r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
132
+ r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
133
+ r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)|"
134
+ r"(?:[0-9a-fA-F]{1,4}:){1,4}:"
135
+ r"(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
136
+ r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
137
+ r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
138
+ r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
139
+ r")$"
140
+ )
141
+
142
+ # Check for IPv4
143
+ try:
144
+ if re.fullmatch(ipv4_pattern, ip_address):
145
+ return "ipAddress"
146
+ # Check for IPv6
147
+ elif re.fullmatch(ipv6_pattern, ip_address):
148
+ return "iPv6Address"
149
+ else:
150
+ return None
151
+ except Exception:
152
+ return None
153
+
154
+
155
+ def determine_asset_category(inventory: dict, mapping: "ImportValidater.mapping") -> str:
156
+ """
157
+ Determine the asset category based on the inventory item
158
+ :param dict inventory: inventory item to parse & determine the asset category
159
+ :param ImportValidater.mapping mapping: Mapping object to use for mapping
160
+ :return: asset category of Hardware, Software, or Unknown
161
+ :rtype: str
162
+ """
163
+ software_fields = [
164
+ check_text(mapping.get_value(inventory, SOFTWARE_VENDOR)),
165
+ check_text(mapping.get_value(inventory, SOFTWARE_NAME)),
166
+ check_text(mapping.get_value(inventory, PATCH_LEVEL)),
167
+ ]
168
+ hardware_fields = [
169
+ check_text(mapping.get_value(inventory, HARDWARE_MAKE)),
170
+ check_text(mapping.get_value(inventory, MAC_ADDRESS)),
171
+ check_text(mapping.get_value(inventory, OS_NAME)),
172
+ ]
173
+ software_set = set(software_fields)
174
+ hardware_set = set(hardware_fields)
175
+ if len(hardware_set) > len(software_set):
176
+ return "Hardware"
177
+ if len(software_set) > len(hardware_set):
178
+ return "Software"
179
+ return "Unknown"
180
+
181
+
182
+ def map_inventory_to_asset(
183
+ inventory: dict, parent_id: int, parent_module: str, mapping: "ImportValidater.mapping"
184
+ ) -> Optional[Asset]:
185
+ """
186
+ Map the inventory to a RegScale asset
187
+ :param dict inventory: inventory item to map to a RegScale asset
188
+ :param int parent_id: RegScale Record ID to use as parentId
189
+ :param str parent_module: RegScale Module to use as parentModule
190
+ :param ImportValidater.mapping mapping: Mapping object to use for mapping
191
+ :return: RegScale asset, if it has a unique identifier or DNS name
192
+ :rtype: Optional[Asset]
193
+ """
194
+ # create a new asset
195
+ asset_category = determine_asset_category(inventory, mapping)
196
+ if asset_name := check_text(mapping.get_value(inventory, UNIQUE_ASSET_IDENTIFIER)) or check_text(
197
+ mapping.get_value(inventory, DNS_NAME)
198
+ ):
199
+ new_asset = {
200
+ "id": 0,
201
+ "isPublic": True,
202
+ "uuid": "",
203
+ "name": asset_name,
204
+ "otherTrackingNumber": "",
205
+ "serialNumber": check_text(mapping.get_value(inventory, SERIAL_NUMBER)),
206
+ "macAddress": check_text(mapping.get_value(inventory, MAC_ADDRESS)),
207
+ "manufacturer": "",
208
+ "model": check_text(mapping.get_value(inventory, HARDWARE_MAKE)),
209
+ "assetOwnerId": config["userId"],
210
+ "systemAdministratorId": None,
211
+ "operatingSystem": "",
212
+ "osVersion": check_text(mapping.get_value(inventory, OS_NAME)),
213
+ "assetType": check_text(mapping.get_value(inventory, ASSET_TYPE) or "Unknown"),
214
+ "location": check_text(mapping.get_value(inventory, "Location")),
215
+ "cmmcAssetType": "",
216
+ "cpu": 0,
217
+ "ram": 0,
218
+ "diskStorage": 0,
219
+ "description": "",
220
+ "endOfLifeDate": date_str(mapping.get_value(inventory, "End-of-Life ", "", warnings=False)),
221
+ "purchaseDate": None,
222
+ "status": "Active (On Network)",
223
+ "wizId": "",
224
+ "wizInfo": "",
225
+ "notes": check_text(mapping.get_value(inventory, "Comments")),
226
+ "softwareVendor": check_text(mapping.get_value(inventory, SOFTWARE_VENDOR)),
227
+ "softwareVersion": check_text(mapping.get_value(inventory, SOFTWARE_NAME)),
228
+ "softwareFunction": check_text(mapping.get_value(inventory, FUNCTION)),
229
+ "patchLevel": check_text(mapping.get_value(inventory, PATCH_LEVEL)),
230
+ "assetCategory": asset_category,
231
+ "bVirtual": map_str_to_bool(mapping.get_value(inventory, "Virtual")),
232
+ "bPublicFacing": map_str_to_bool(mapping.get_value(inventory, "Public")),
233
+ "bAuthenticatedScan": map_str_to_bool(mapping.get_value(inventory, AUTHENTICATED_SCAN)),
234
+ "bLatestScan": map_str_to_bool(mapping.get_value(inventory, IN_LATEST_SCAN)),
235
+ "netBIOS": check_text(mapping.get_value(inventory, NETBIOS_NAME)),
236
+ "baselineConfiguration": check_text(mapping.get_value(inventory, BASELINE_CONFIGURATION_NAME)),
237
+ "fqdn": check_text(mapping.get_value(inventory, DNS_NAME)),
238
+ "assetTagNumber": "",
239
+ "vlanId": check_text(mapping.get_value(inventory, VLAN_NETWORK_ID)),
240
+ "facilityId": None,
241
+ "orgId": None,
242
+ "parentId": parent_id,
243
+ "parentModule": parent_module,
244
+ "createdById": config["userId"],
245
+ "dateCreated": datetime.now().strftime(fmt),
246
+ "lastUpdatedById": config["userId"],
247
+ "dateLastUpdated": datetime.now().strftime(fmt),
248
+ }
249
+ else:
250
+ return None
251
+ _update_ip_addresses(new_asset, inventory, mapping)
252
+ if asset_category == "Hardware":
253
+ new_asset["purpose"] = check_text(mapping.get_value(inventory, FUNCTION))
254
+ elif asset_category == "Software":
255
+ new_asset["softwareFunction"] = check_text(mapping.get_value(inventory, FUNCTION))
256
+ return Asset(**new_asset)
257
+
258
+
259
+ def _update_ip_addresses(asset: dict, inventory: dict, mapping: "ImportValidater.mapping") -> None:
260
+ """
261
+ Update the IPv4 and IPv6 address fields for the provided asset
262
+
263
+ :param dict asset: Asset to update
264
+ :param dict inventory: Inventory item to parse
265
+ :param ImportValidater.mapping mapping: Mapping object to use for mapping
266
+ :rtype: None
267
+ """
268
+ if ip_address_data := check_text(mapping.get_value(inventory, IPV4_OR_IPV6_ADDRESS)):
269
+ v6_addresses = []
270
+ v4_addresses = []
271
+ for ip_address in [addr.strip() for addr in re.split(r"\s*[;,]\s*|\n", ip_address_data) if addr.strip()]:
272
+ if ipaddress_key := determine_ip_address_version(ip_address):
273
+ if ipaddress_key == "iPv6Address":
274
+ v6_addresses.append(ip_address)
275
+ else:
276
+ v4_addresses.append(ip_address)
277
+ asset["ipAddress"] = ", ".join(v4_addresses) if v4_addresses else None
278
+ asset["iPv6Address"] = ", ".join(v6_addresses) if v6_addresses else None
279
+
280
+
281
+ def create_properties(data: dict, parent_id: int, parent_module: str, progress: rich.progress.Progress) -> bool:
282
+ """
283
+ Create a list of properties and upload them to RegScale for the provided asset
284
+ :param dict data: Dictionary of data to parse and create properties from
285
+ :param int parent_id: ID to create properties for
286
+ :param str parent_module: Parent module to create properties for
287
+ :param rich.progress.Progress progress: Progress object used for batch creation
288
+ :return: If batch update was successful
289
+ :rtype: bool
290
+ """
291
+ import numpy as np # Optimize import performance
292
+
293
+ properties: list = []
294
+ for key, value in data.items():
295
+ # skip the item if the key is id or contains unnamed
296
+ if "unnamed" in key.lower():
297
+ continue
298
+ # see if the value is datetime
299
+ elif isinstance(value, datetime):
300
+ value = value.strftime("%b %d, %Y")
301
+ # see if the value is a boolean
302
+ elif isinstance(value, np.bool_):
303
+ value = str(value).title()
304
+ regscale_property = Property(
305
+ createdById=config["userId"],
306
+ lastUpdatedById=config["userId"],
307
+ key=key,
308
+ value=value,
309
+ parentId=parent_id,
310
+ parentModule=parent_module,
311
+ )
312
+ properties.append(regscale_property)
313
+ new_props = Property.batch_create(properties, progress_context=progress, remove_progress=True)
314
+ create_logger().debug(f"Created {len(new_props)}/{len(properties)} properties for asset #{parent_id}")
315
+ return new_props is not None
316
+
317
+
318
+ def validate_columns(file_path: str, version: Literal["rev4", "rev5", "4", "5"], sheet_name: str) -> ImportValidater:
319
+ """
320
+ Validate the columns in the inventory
321
+
322
+ :param str file_path: path to the inventory .xlsx file
323
+ :param Literal["rev4", "rev5", "4", "5"] version: FedRAMP version to import
324
+ :param str sheet_name: sheet name in the inventory .xlsx file to validate
325
+ :return: Import validator to facilitate header validation and custom mappings
326
+ :rtype: ImportValidater
327
+ """
328
+ if "5" in version:
329
+ expected_cols = [
330
+ UNIQUE_ASSET_IDENTIFIER,
331
+ IPV4_OR_IPV6_ADDRESS,
332
+ "Virtual",
333
+ "Public",
334
+ DNS_NAME,
335
+ NETBIOS_NAME,
336
+ MAC_ADDRESS,
337
+ AUTHENTICATED_SCAN,
338
+ BASELINE_CONFIGURATION_NAME,
339
+ OS_NAME,
340
+ "Location",
341
+ ASSET_TYPE,
342
+ HARDWARE_MAKE,
343
+ IN_LATEST_SCAN,
344
+ SOFTWARE_VENDOR,
345
+ SOFTWARE_NAME,
346
+ PATCH_LEVEL,
347
+ "Diagram Label",
348
+ "Comments",
349
+ SERIAL_NUMBER,
350
+ VLAN_NETWORK_ID,
351
+ "System Administrator/ Owner",
352
+ "Application Administrator/ Owner",
353
+ FUNCTION,
354
+ ]
355
+ mapping_dir = os.path.join("./", "mappings", "fedramp_inventory_rev5")
356
+ else:
357
+ expected_cols = [
358
+ UNIQUE_ASSET_IDENTIFIER,
359
+ IPV4_OR_IPV6_ADDRESS,
360
+ "Virtual",
361
+ "Public",
362
+ DNS_NAME,
363
+ NETBIOS_NAME,
364
+ MAC_ADDRESS,
365
+ AUTHENTICATED_SCAN,
366
+ BASELINE_CONFIGURATION_NAME,
367
+ OS_NAME,
368
+ "Location",
369
+ ASSET_TYPE,
370
+ HARDWARE_MAKE,
371
+ IN_LATEST_SCAN,
372
+ SOFTWARE_VENDOR,
373
+ SOFTWARE_NAME,
374
+ PATCH_LEVEL,
375
+ FUNCTION,
376
+ "Comments",
377
+ SERIAL_NUMBER,
378
+ VLAN_NETWORK_ID,
379
+ "System Administrator/ Owner",
380
+ "Application Administrator/ Owner",
381
+ ]
382
+ mapping_dir = os.path.join("./", "mappings", "fedramp_inventory_rev4")
383
+ return ImportValidater(
384
+ required_headers=expected_cols,
385
+ file_path=file_path,
386
+ mapping_file_path=mapping_dir,
387
+ disable_mapping=False,
388
+ worksheet_name=sheet_name,
389
+ skip_rows=2,
390
+ )
391
+
392
+
393
+ def upload(
394
+ inventory: str,
395
+ record_id: int,
396
+ module: str,
397
+ version: Literal["rev4", "rev5", "4", "5"],
398
+ sheet_name: str = "Inventory",
399
+ ) -> None:
400
+ """
401
+ Main function to parse the inventory and load into RegScale
402
+ :param str inventory: path to the inventory .xlsx file
403
+ :param int record_id: RegScale Record ID to update
404
+ :param str module: RegScale Module for the provided ID
405
+ :param Literal["rev4", "rev5", "4", "5"] version: FedRAMP version to import
406
+ :param str sheet_name: sheet name in the inventory .xlsx file to parse, defaults to "Inventory"
407
+ :rtype: None
408
+ """
409
+ from regscale.exceptions.validation_exception import ValidationException
410
+
411
+ logger = create_logger()
412
+
413
+ try:
414
+ import_validator = validate_columns(inventory, version, sheet_name)
415
+ df = import_validator.data
416
+ except FileNotFoundError:
417
+ logger.error(f"[red]File not found: {inventory}")
418
+ return
419
+ except (ValueError, ValidationException) as e:
420
+ logger.error(
421
+ "There is an issue with the file: %s, please check the file and try again. Error: %s. Skipping...",
422
+ inventory,
423
+ e,
424
+ )
425
+ return
426
+
427
+ # convert into dictionary
428
+ inventory_json = df.to_json(orient="records")
429
+ inventory_list = df.to_dict(orient="records")
430
+
431
+ # save locally
432
+ save_to_json("inventory.json", inventory_json)
433
+ logger.info(f"[yellow]{len(inventory_list)} total inventory item(s) saved to inventory.json")
434
+
435
+ # process the inventory
436
+ inventory: Dict[int, Dict[str, Asset]] = {}
437
+ existing_assets = Asset.get_all_by_parent(parent_id=record_id, parent_module=module)
438
+ already_inserted: List[Asset] = []
439
+ job_progress = create_progress_object()
440
+ with job_progress as progress:
441
+ process_task = progress.add_task("Processing inventory...", total=len(inventory_list))
442
+ for inv in range(len(inventory_list)):
443
+ asset = map_inventory_to_asset(inventory_list[inv], record_id, module, import_validator.mapping)
444
+ if not asset:
445
+ progress.update(process_task, advance=1)
446
+ logger.warning(
447
+ f"[yellow]Skipping {inventory_list[inv]}, unable to determine Asset name from"
448
+ f" {UNIQUE_ASSET_IDENTIFIER} and {DNS_NAME}."
449
+ )
450
+ continue
451
+ if asset not in existing_assets:
452
+ inventory[inv] = {}
453
+ inventory[inv]["asset"] = asset
454
+ inventory[inv]["raw_data"] = inventory_list[inv] # noqa
455
+ else:
456
+ already_inserted.append(asset)
457
+ progress.update(process_task, advance=1)
458
+ # reindex dict
459
+ reindexed_dict = {new_index: inventory[old_index] for new_index, old_index in enumerate(inventory)}
460
+ # print new objectives
461
+ save_to_json("regscale-inventory", reindexed_dict)
462
+
463
+ if not reindexed_dict:
464
+ logger.warning("[yellow]No new inventory items to load, exiting...")
465
+ return
466
+ logger.info(
467
+ f"[yellow]{len(reindexed_dict)} total inventory item(s) ready to load ({len(already_inserted)} "
468
+ f"already exist(s)) Saved to regscale-inventory.json"
469
+ )
470
+ # loop through each asset in the inventory list
471
+ processed = []
472
+ failed = []
473
+ with job_progress as progress:
474
+ loading_task = progress.add_task("Loading inventory into RegScale...", total=len(reindexed_dict))
475
+ for inv in reindexed_dict.values():
476
+ try:
477
+ res_data = inv["asset"].create() # noqa
478
+ processed.append(res_data)
479
+ if not create_properties(inv["raw_data"], res_data["id"], "assets", progress): # noqa
480
+ logger.error(
481
+ f"[red]Failed to create properties for asset #{res_data['id']}: {inv['asset']['name']}" # noqa
482
+ )
483
+ except JSONDecodeError:
484
+ failed.append(inv)
485
+ continue
486
+ progress.update(loading_task, advance=1)
487
+
488
+ if failed:
489
+ save_to_json("failed-inventory", failed)
490
+ logger.error(f"[red]{len(failed)} total inventory item(s) failed to load. Saved to failed-inventory.json")
491
+ # print new objectives
492
+ save_to_json("processed-inventory", processed)
493
+ logger.info(
494
+ f"[yellow]{len(processed)} total RegScale inventory successfully uploaded. Saved to processed-inventory.json"
495
+ )