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,637 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ RegScale DuroSuite Package
5
+
6
+ This module provides functionality for integrating DuroSuite with RegScale,
7
+ including syncing findings, assets, and performing scans.
8
+ """
9
+ import enum
10
+ import logging
11
+ import re
12
+ import tempfile
13
+ import time
14
+ from typing import Optional, List, Dict, Tuple
15
+
16
+ import click
17
+ from rich.progress import Progress
18
+
19
+ from regscale.core.lazy_group import LazyGroup
20
+ from regscale.integrations.commercial.durosuite import api
21
+ from regscale.integrations.commercial.durosuite.variables import DuroSuiteVariables
22
+ from regscale.integrations.commercial.stigv2.stig_integration import StigIntegration
23
+ from regscale.models import regscale_ssp_id
24
+
25
+ logger = logging.getLogger("regscale")
26
+
27
+
28
+ class DuroSuiteOS(enum.IntEnum):
29
+ """
30
+ Enum for Operating Systems
31
+ """
32
+
33
+ UBUNTU_20 = 7
34
+ PALO_ALTO = 8
35
+
36
+
37
+ @click.group(
38
+ cls=LazyGroup,
39
+ lazy_subcommands={
40
+ "scan": "regscale.integrations.commercial.durosuite.scanner.scan",
41
+ "import_audit": "regscale.integrations.commercial.durosuite.scanner.cli_import_audit",
42
+ },
43
+ name="durosuite",
44
+ )
45
+ def durosuite():
46
+ """
47
+ DuroSuite Integrations
48
+ """
49
+ logging.basicConfig(
50
+ level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", stream=sys.stderr
51
+ )
52
+
53
+
54
+ @durosuite.command(name="scan")
55
+ @regscale_ssp_id()
56
+ @click.option(
57
+ "--ansible_user",
58
+ type=str,
59
+ required=True,
60
+ help="Remote user name for device connection",
61
+ )
62
+ @click.option(
63
+ "--ansible_ssh_pass",
64
+ type=str,
65
+ required=True,
66
+ help="Remote user password for device connection",
67
+ )
68
+ @click.option(
69
+ "--ansible_become_pass",
70
+ type=str,
71
+ required=True,
72
+ help="Password for privilege escalation",
73
+ )
74
+ @click.option(
75
+ "--device_name",
76
+ type=str,
77
+ default="Ubuntu Server",
78
+ help="Name of the device to scan",
79
+ )
80
+ @click.option(
81
+ "--os_id",
82
+ type=int,
83
+ default=7,
84
+ help="ID of the operating system",
85
+ )
86
+ @click.option(
87
+ "--log_level",
88
+ type=str,
89
+ default="INFO",
90
+ help="Log level for the scan",
91
+ )
92
+ def scan(
93
+ regscale_ssp_id: int,
94
+ ansible_user: str,
95
+ ansible_ssh_pass: str,
96
+ ansible_become_pass: str,
97
+ device_name: str,
98
+ os_id: int,
99
+ log_level: str,
100
+ ):
101
+ """
102
+ Scan DuroSuite.
103
+
104
+ This function initiates a scan in DuroSuite and syncs the results to RegScale.
105
+ """
106
+ import logging
107
+ import sys
108
+
109
+ logging.basicConfig(
110
+ level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", stream=sys.stderr
111
+ )
112
+
113
+ # Call durosuite_scan with the provided arguments
114
+ durosuite_scan(
115
+ host=device_name,
116
+ os_id=os_id,
117
+ regscale_ssp_id=regscale_ssp_id,
118
+ ansible_user=ansible_user,
119
+ ansible_ssh_pass=ansible_ssh_pass,
120
+ ansible_become_pass=ansible_become_pass,
121
+ )
122
+
123
+
124
+ @durosuite.command(name="import_audit")
125
+ @regscale_ssp_id()
126
+ @click.option(
127
+ "-a",
128
+ "--audit_id",
129
+ type=click.INT,
130
+ help="The ID of the DuroSuite audit to import",
131
+ prompt="Enter DuroSuite Audit ID",
132
+ required=True,
133
+ )
134
+ def cli_import_audit(audit_id: int, regscale_ssp_id: int) -> None:
135
+ """
136
+ Import a specific DuroSuite audit and sync it to RegScale.
137
+
138
+ This function imports a specific audit from DuroSuite and syncs it to RegScale.
139
+
140
+ :param int audit_id: The ID of the DuroSuite audit to import.
141
+ :param int regscale_ssp_id: RegScale System Security Plan ID.
142
+ """
143
+ import_audit(audit_id, regscale_ssp_id)
144
+
145
+
146
+ def get_or_create_group(ds: api.DuroSuite, os_id: int, group_name: str = None) -> api.Group:
147
+ """
148
+ Get an existing group for the OS or create a new one.
149
+
150
+ :param api.DuroSuite ds: DuroSuite client
151
+ :param int os_id: Operating system ID
152
+ :param str group_name: Optional group name, will be generated if not provided
153
+ :return: Group object
154
+ :rtype: api.Group
155
+ :raises ValueError: If group creation fails
156
+ """
157
+ groups = [group for group in ds.get_groups() if group.os_id == os_id]
158
+ if any(groups):
159
+ return groups[0]
160
+
161
+ if not group_name:
162
+ # Get OS name from supported systems
163
+ os_list = ds.get_supported_operating_systems()
164
+ os_name = next((os["operating_system"] for os in os_list if os["id"] == os_id), f"OS-{os_id}")
165
+ group_name = f"{os_name} Group"
166
+
167
+ # Set required variables based on OS
168
+ variables = {}
169
+ if os_id == 7: # Ubuntu 20.XX
170
+ variables = {
171
+ "ansible_user": DuroSuiteVariables.duroSuiteUser,
172
+ "ansible_ssh_pass": DuroSuiteVariables.duroSuitePassword,
173
+ # "ansible_become_pass": "",
174
+ # "remote_server_variable": "",
175
+ # "require_disk_encryption": False,
176
+ # "space_left_variable": 250000,
177
+ # "time_zone_variable": "UTC",
178
+ }
179
+
180
+ response = ds.add_new_group({"group_name": group_name, "os_id": os_id, "variables": variables})
181
+ if not response:
182
+ raise ValueError(f"Failed to create group for OS {os_id}")
183
+
184
+ # Get the newly created group
185
+ groups = [group for group in ds.get_groups() if group.os_id == os_id]
186
+ if not any(groups):
187
+ raise ValueError(f"Group was created but not found for OS {os_id}")
188
+ return groups[0]
189
+
190
+
191
+ def get_or_create_template(ds: api.DuroSuite, playbook_id: int, os_id: int, group_id: int) -> api.Template:
192
+ """
193
+ Get an existing template for the OS or create a new one.
194
+
195
+ :param api.DuroSuite ds: DuroSuite client
196
+ :param int playbook_id: ID of the playbook
197
+ :param int os_id: Operating system ID
198
+ :param int group_id: Group ID
199
+ :return: Template object
200
+ :rtype: api.Template
201
+ :raises ValueError: If template creation fails
202
+ """
203
+ try:
204
+ # Get templates for the group
205
+ templates = ds.get_template_ids_by_group(group_id)
206
+
207
+ # Look for an existing template that matches our criteria
208
+ for template in templates:
209
+ if template.os_id == os_id and template.playbook_id == playbook_id:
210
+ return template
211
+
212
+ # If no matching template exists, create a new one
213
+ template_name = f"Template_{playbook_id}_{time.strftime('%Y%m%d_%H%M%S')}"
214
+ template = ds.create_template(name=template_name, os_id=os_id, playbook_id=playbook_id, group_id=group_id)
215
+ if template:
216
+ return template
217
+
218
+ raise ValueError("Failed to create template")
219
+ except Exception as e:
220
+ raise ValueError(f"Failed to create template: {e}")
221
+
222
+
223
+ def _get_device_vars_for_os(
224
+ os_id: int, host: str, ansible_user: str, ansible_ssh_pass: str, ansible_become_pass: Optional[str] = None
225
+ ) -> List[Dict[str, str]]:
226
+ """
227
+ Get device variables based on OS type.
228
+
229
+ :param int os_id: Operating system ID
230
+ :param str host: Host IP or hostname
231
+ :param str ansible_user: Remote user name
232
+ :param str ansible_ssh_pass: Remote user password
233
+ :param Optional[str] ansible_become_pass: Privilege escalation password
234
+ :return: List of device variables
235
+ :rtype: List[Dict[str, str]]
236
+ """
237
+ if os_id == DuroSuiteOS.UBUNTU_20:
238
+ return [
239
+ {"var_name": "ansible_host", "var_value": host},
240
+ {"var_name": "ansible_user", "var_value": ansible_user},
241
+ {"var_name": "ansible_ssh_pass", "var_value": ansible_ssh_pass},
242
+ {"var_name": "ansible_become_pass", "var_value": ansible_become_pass},
243
+ ]
244
+ elif os_id == DuroSuiteOS.PALO_ALTO:
245
+ return [
246
+ {"var_name": "ansible_host", "var_value": host},
247
+ {"var_name": "pan_username", "var_value": ansible_user},
248
+ {"var_name": "pan_password", "var_value": ansible_ssh_pass},
249
+ ]
250
+ return []
251
+
252
+
253
+ def _needs_device_update(
254
+ device: api.Device, os_id: int, host: str, ansible_user: str, ansible_ssh_pass: str, ansible_become_pass: str
255
+ ) -> Tuple[bool, List[Dict[str, str]]]:
256
+ """
257
+ Check if device needs variable updates.
258
+
259
+ :param api.Device device: Device to check
260
+ :param int os_id: Operating system ID
261
+ :param str host: Host IP or hostname
262
+ :param str ansible_user: Remote user name
263
+ :param str ansible_ssh_pass: Remote user password
264
+ :param str ansible_become_pass: Privilege escalation password
265
+ :return: Tuple of (needs_update, vars_to_update)
266
+ :rtype: Tuple[bool, List[Dict[str, str]]]
267
+ """
268
+ device_vars = {var.name: var.value for var in device.device_vars} if device.device_vars else {}
269
+
270
+ if os_id == DuroSuiteOS.UBUNTU_20:
271
+ if (
272
+ device_vars.get("ansible_host") != host
273
+ or device_vars.get("ansible_user") != ansible_user
274
+ or device_vars.get("ansible_ssh_pass") != ansible_ssh_pass
275
+ or device_vars.get("ansible_become_pass") != ansible_become_pass
276
+ ):
277
+ return True, _get_device_vars_for_os(os_id, host, ansible_user, ansible_ssh_pass, ansible_become_pass)
278
+ elif os_id == DuroSuiteOS.PALO_ALTO:
279
+ if (
280
+ device_vars.get("ansible_host") != host
281
+ or device_vars.get("pan_username") != ansible_user
282
+ or device_vars.get("pan_password") != ansible_ssh_pass
283
+ ):
284
+ return True, _get_device_vars_for_os(os_id, host, ansible_user, ansible_ssh_pass)
285
+
286
+ return False, []
287
+
288
+
289
+ def _find_matching_device(
290
+ devices: List[api.Device], device_name: str, os_id: int, group_id: int
291
+ ) -> Optional[api.Device]:
292
+ """
293
+ Find a matching device from the list.
294
+
295
+ :param List[api.Device] devices: List of devices to search
296
+ :param str device_name: Name of the device to find
297
+ :param int os_id: Operating system ID
298
+ :param int group_id: Group ID
299
+ :return: Matching device or None
300
+ :rtype: Optional[api.Device]
301
+ """
302
+ for device in devices:
303
+ if device.name == device_name and device.os_id == os_id and any(g.id == group_id for g in device.groups):
304
+ return device
305
+ return None
306
+
307
+
308
+ def get_or_create_device(
309
+ ds: api.DuroSuite,
310
+ device_name: str,
311
+ os_id: int,
312
+ group_id: int,
313
+ host: str,
314
+ ansible_user: str,
315
+ ansible_ssh_pass: str,
316
+ ansible_become_pass: str,
317
+ ) -> api.Device:
318
+ """
319
+ Get an existing device or create a new one.
320
+
321
+ :param api.DuroSuite ds: DuroSuite client
322
+ :param str device_name: Name of the device
323
+ :param int os_id: Operating system ID
324
+ :param int group_id: Group ID
325
+ :param str host: Host IP or hostname
326
+ :param str ansible_user: Remote user name
327
+ :param str ansible_ssh_pass: Remote user password
328
+ :param str ansible_become_pass: Privilege escalation password
329
+ :return: Device object
330
+ :rtype: api.Device
331
+ :raises ValueError: If device creation fails
332
+ """
333
+ # First try to find an existing device
334
+ devices = ds.get_devices()
335
+ if devices:
336
+ if device := _find_matching_device(devices, device_name, os_id, group_id):
337
+ # Check if device needs updates
338
+ needs_update, vars_to_update = _needs_device_update(
339
+ device, os_id, host, ansible_user, ansible_ssh_pass, ansible_become_pass
340
+ )
341
+ if needs_update:
342
+ ds.update_device_vars(device.id, vars_to_update)
343
+ return device
344
+
345
+ # If no device exists, create a new one
346
+ try:
347
+ device_vars = _get_device_vars_for_os(os_id, host, ansible_user, ansible_ssh_pass, ansible_become_pass)
348
+ device_data = {"name": device_name, "os_id": os_id, "group_id": group_id, "device_vars": device_vars}
349
+ device = ds.add_new_device(device_data)
350
+ if device:
351
+ return device
352
+ except Exception as e:
353
+ logger.error(f"Failed to create device: {e}")
354
+ raise ValueError(f"Failed to create device: {e}")
355
+
356
+ raise ValueError("Failed to create device")
357
+
358
+
359
+ def get_stigs(ds: api.DuroSuite, os_id: int) -> list:
360
+ """
361
+ Get STIGs for the given OS.
362
+
363
+ :param DuroSuite ds: DuroSuite API client.
364
+ :param int os_id: ID of the operating system.
365
+
366
+ :return: List of STIGs.
367
+ :rtype: list
368
+ """
369
+ try:
370
+ stigs = ds.get_stigs_by_os_id(os_id=os_id)
371
+ return stigs
372
+ except Exception as e:
373
+ logger.error(f"Failed to get STIGs: {e}")
374
+ raise ValueError(f"Failed to get STIGs: {e}")
375
+
376
+
377
+ def _wait_for_audit_completion(ds: api.DuroSuite, audit_id: int) -> None:
378
+ """
379
+ Wait for an audit to complete or fail.
380
+
381
+ :param api.DuroSuite ds: DuroSuite client
382
+ :param int audit_id: ID of the audit to monitor
383
+ :raises ValueError: If audit fails or is cancelled
384
+ :raises TimeoutError: If audit times out
385
+ """
386
+ max_retries = 30 # 5 minutes total
387
+ retry_count = 0
388
+ while retry_count < max_retries:
389
+ audit_status = ds.get_audit_status(audit_id)
390
+ if not audit_status:
391
+ logger.error("Failed to get audit status")
392
+ break
393
+
394
+ status = audit_status.status.lower() if audit_status.status else "unknown"
395
+ logger.info(f"Audit status: {status}")
396
+
397
+ if status.startswith("complete"):
398
+ logger.info("Audit completed successfully")
399
+ return
400
+ elif status.startswith("fail"):
401
+ error_msg = audit_status.error_message or "Unknown error"
402
+ logger.error(f"Audit failed: {error_msg}")
403
+ raise ValueError(f"Audit failed: {error_msg}")
404
+ elif status.startswith("cancel"):
405
+ logger.error("Audit was cancelled")
406
+ raise ValueError("Audit was cancelled")
407
+
408
+ time.sleep(10) # Wait 10 seconds before checking again
409
+ retry_count += 1
410
+
411
+ if retry_count >= max_retries:
412
+ raise TimeoutError("Audit timed out")
413
+
414
+
415
+ def durosuite_scan(
416
+ host: str,
417
+ os_id: int,
418
+ regscale_ssp_id: int,
419
+ ansible_user: str,
420
+ ansible_ssh_pass: str,
421
+ ansible_become_pass: str,
422
+ device_name: Optional[str] = None,
423
+ progress: Optional[Progress] = None,
424
+ ) -> None:
425
+ """
426
+ Perform a DuroSuite scan and import the results to RegScale.
427
+
428
+ :param str host: Name of the device to scan
429
+ :param int os_id: ID of the operating system
430
+ :param int regscale_ssp_id: RegScale System Security Plan ID
431
+ :param str ansible_user: Remote user name for device connection
432
+ :param str ansible_ssh_pass: Remote user password for device connection
433
+ :param str ansible_become_pass: Password for privilege escalation
434
+ :param Optional[str] device_name: Optional name of the device
435
+ :param Optional[Progress] progress: Optional progress object to use instead of creating a new one
436
+ """
437
+ # Get DuroSuite variables from init.yaml
438
+ base_url = DuroSuiteVariables.duroSuiteURL
439
+ username = DuroSuiteVariables.duroSuiteUser
440
+ password = DuroSuiteVariables.duroSuitePassword
441
+
442
+ # Determine if the host is an IP address or a FQDN
443
+ if re.match(r"^\d{1,3}(\.\d{1,3}){3}$", host):
444
+ device_ip = host
445
+ else:
446
+ device_ip = None
447
+ device_name = host
448
+
449
+ # Initialize DuroSuite API client with DuroSuite API credentials
450
+ ds = api.DuroSuite(base_url, username, password)
451
+
452
+ try:
453
+ # Initialize DuroSuite client
454
+ ds.login(username, password)
455
+ logger.debug("DuroSuite API client initialized")
456
+
457
+ # Get or create group
458
+ group = get_or_create_group(ds, os_id)
459
+ if not group:
460
+ logger.error("Failed to get or create group")
461
+ raise ValueError("Failed to get or create group")
462
+
463
+ logger.info(f"Using group: {group}")
464
+
465
+ # Create device
466
+ device = get_or_create_device(
467
+ ds,
468
+ host,
469
+ os_id,
470
+ group.id,
471
+ host,
472
+ ansible_user,
473
+ ansible_ssh_pass,
474
+ ansible_become_pass,
475
+ )
476
+ logger.info(f"Device created: {host}")
477
+
478
+ # Get STIG
479
+ stigs = get_stigs(ds, os_id)
480
+
481
+ # Get or create template
482
+ template = get_or_create_template(ds, stigs[0].id, os_id, group.id)
483
+ if not template:
484
+ logger.error("Failed to get or create template")
485
+ raise ValueError("Failed to get or create template")
486
+ logger.info(f"Template: {template}")
487
+
488
+ # Start audit
489
+ audit = ds.audit_device(device.id, group.id, stigs[0].id, template.id)
490
+ if not audit:
491
+ logger.error("Failed to start audit")
492
+ raise ValueError("Failed to start audit")
493
+ logger.info(f"Started audit: {audit}")
494
+
495
+ # Wait for audit completion and import results
496
+ try:
497
+ _wait_for_audit_completion(ds, audit.audit_id)
498
+ import_audit(
499
+ audit.audit_id, regscale_ssp_id, progress=progress, device_name=device_name, device_ip=device_ip
500
+ )
501
+ logger.info(f"Successfully imported audit {audit.audit_id} to RegScale SSP {regscale_ssp_id}")
502
+ except Exception as e:
503
+ logger.error(f"Failed to import audit results: {e}")
504
+ raise
505
+
506
+ except Exception as e:
507
+ logger.error(f"Failed to scan device: {e}")
508
+ raise
509
+
510
+
511
+ def _wait_for_audit_completion_and_checklist(ds: api.DuroSuite, audit_id: int) -> str:
512
+ """
513
+ Wait for audit completion and retrieve the checklist file.
514
+
515
+ :param api.DuroSuite ds: DuroSuite client
516
+ :param int audit_id: The ID of the audit
517
+ :return: The checklist file content
518
+ :rtype: str
519
+ :raises TimeoutError: If waiting for checklist times out
520
+ """
521
+ # Wait for the audit to complete
522
+ finished = False
523
+ while not finished:
524
+ response = ds.get_audit_record(audit_id=audit_id)
525
+ if response:
526
+ logger.info(f"Audit Status for {audit_id}: {response['status']}")
527
+ if response["status"].lower() == "complete":
528
+ finished = True
529
+ time.sleep(5)
530
+
531
+ # Retrieve the checklist file
532
+ checklist_file: Optional[str] = None
533
+ attempts = 0
534
+ max_attempts = 12 # 1 minute total wait time
535
+ while not checklist_file and attempts < max_attempts:
536
+ logger.info(f"Waiting for checklist file for {audit_id}")
537
+ checklist_file = ds.get_checklist_file_by_audit_id(audit_id)
538
+ time.sleep(5)
539
+ attempts += 1
540
+
541
+ if not checklist_file:
542
+ raise TimeoutError(f"Timed out waiting for checklist file for audit {audit_id}")
543
+
544
+ return checklist_file
545
+
546
+
547
+ def _update_xml_element(asset: "ET.Element", element_name: str, value: str) -> None:
548
+ """
549
+ Update or create an XML element with the given value.
550
+
551
+ :param ET.Element asset: The asset element to update
552
+ :param str element_name: Name of the element to update
553
+ :param str value: Value to set
554
+ """
555
+ element = asset.find(element_name)
556
+ if element is not None:
557
+ if not element.text:
558
+ element.text = value
559
+ else:
560
+ element = ET.SubElement(asset, element_name)
561
+ element.text = value
562
+
563
+
564
+ def _update_checklist_device_info(checklist_content: str, device_name: Optional[str], device_ip: Optional[str]) -> str:
565
+ """
566
+ Update the checklist XML with device information.
567
+
568
+ :param str checklist_content: Original checklist content
569
+ :param Optional[str] device_name: Device name to add
570
+ :param Optional[str] device_ip: Device IP to add
571
+ :return: Updated checklist content
572
+ :rtype: str
573
+ """
574
+ if not (device_name or device_ip):
575
+ return checklist_content
576
+
577
+ import xml.etree.ElementTree as ET
578
+
579
+ root = ET.fromstring(checklist_content)
580
+ asset = root.find(".//ASSET")
581
+
582
+ if asset is not None:
583
+ if device_name:
584
+ _update_xml_element(asset, "HOST_NAME", device_name)
585
+
586
+ if device_ip:
587
+ _update_xml_element(asset, "HOST_IP", device_ip)
588
+ # If no FQDN is set, generate one from the IP
589
+ _update_xml_element(asset, "HOST_FQDN", device_ip)
590
+
591
+ return ET.tostring(root, encoding="unicode")
592
+
593
+
594
+ def import_audit(
595
+ audit_id: int,
596
+ regscale_ssp_id: int,
597
+ progress: Optional[Progress] = None,
598
+ device_name: Optional[str] = None,
599
+ device_ip: Optional[str] = None,
600
+ ) -> None:
601
+ """
602
+ Import a DuroSuite audit and sync it to RegScale.
603
+
604
+ :param int audit_id: The ID of the audit to import.
605
+ :param int regscale_ssp_id: The ID of the RegScale SSP.
606
+ :param Optional[Progress] progress: Optional progress object to use instead of creating a new one
607
+ :param Optional[str] device_name: The name of the device
608
+ :param Optional[str] device_ip: The IP address of the device
609
+ """
610
+ # Get DuroSuite credentials from init.yaml
611
+ base_url = DuroSuiteVariables.duroSuiteURL
612
+ username = DuroSuiteVariables.duroSuiteUser
613
+ password = DuroSuiteVariables.duroSuitePassword
614
+
615
+ ds = api.DuroSuite(base_url, username, password)
616
+
617
+ try:
618
+ # Wait for audit completion and get checklist
619
+ checklist_content = _wait_for_audit_completion_and_checklist(ds, audit_id)
620
+
621
+ # Update checklist with device information if provided
622
+ checklist_content = _update_checklist_device_info(checklist_content, device_name, device_ip)
623
+
624
+ logger.info(f"Processed checklist file for audit {audit_id}")
625
+
626
+ # Process the checklist file
627
+ with tempfile.NamedTemporaryFile(mode="w+", suffix=".ckl", delete=True) as tmp_file:
628
+ tmp_file.write(checklist_content)
629
+ tmp_file_path = tmp_file.name
630
+
631
+ # Sync the assets and findings
632
+ StigIntegration.sync_assets(plan_id=regscale_ssp_id, path=tmp_file_path, progress=progress) # type: ignore
633
+ StigIntegration.sync_findings(plan_id=regscale_ssp_id, path=tmp_file_path, progress=progress) # type: ignore
634
+
635
+ except Exception as e:
636
+ logger.error(f"Failed to import audit: {e}")
637
+ raise
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """DuroSuite Variables"""
4
+
5
+ from regscale.core.app.utils.variables import RsVariableType, RsVariablesMeta
6
+
7
+
8
+ class DuroSuiteVariables(metaclass=RsVariablesMeta):
9
+ """
10
+ DuroSuite Variables class to define class-level attributes with type annotations and examples
11
+ """
12
+
13
+ # Define class-level attributes with type annotations and examples
14
+ duroSuiteURL: RsVariableType(str, "https://example.com") # type: ignore # noqa: F722
15
+ duroSuiteUser: RsVariableType(str, "user") # type: ignore # noqa: F722,F821
16
+ duroSuitePassword: RsVariableType(str, "password", sensitive=True) # type: ignore # noqa: F722,F821
17
+ duroSuiteDemoHost: RsVariableType(str, "ip_address") # type: ignore # noqa: F722,F821
18
+ # Palo Alto device credentials
19
+ duroSuitePaloAltoUser: RsVariableType(str, "admin", required=False) # type: ignore # noqa: F722,F821
20
+ duroSuitePaloAltoPassword: RsVariableType(str, "password", sensitive=True, required=False) # type: ignore # noqa: F722,F821
21
+ duroSuiteEnabled: RsVariableType(bool, "true", default=False) # type: ignore # noqa: F722,F821