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,406 @@
1
+ """
2
+ Test the Application class used by the RegScale CLI.
3
+ """
4
+
5
+ import os
6
+ from unittest.mock import patch, MagicMock
7
+
8
+ from requests import Response
9
+
10
+ from regscale.core.app.application import Application
11
+
12
+
13
+ class TestApplication:
14
+ test_config_file = "test_application_config.yaml"
15
+ os.environ["REGSCALE_CONFIG_FILE"] = test_config_file
16
+ app = Application()
17
+ app.config_file = test_config_file
18
+ test_domain = "https://example.com"
19
+ test_token = "Bearer test_token"
20
+
21
+ def teardown_method(self, method):
22
+ """
23
+ Remove the test config file after each test
24
+ """
25
+ if os.path.exists(self.test_config_file):
26
+ os.remove(self.test_config_file)
27
+
28
+ def test_init(self):
29
+ assert isinstance(self.app, Application)
30
+ assert isinstance(self.app, Application)
31
+ assert self.app.config != {}
32
+ assert self.app.local_config is True
33
+ assert self.app.running_in_airflow is False
34
+
35
+ def test_singleton(self):
36
+ test_config = {"key": "value"}
37
+ app2 = Application()
38
+ assert self.app == app2
39
+ app3 = Application(config=test_config)
40
+ assert test_config["key"] == app3["key"]
41
+ assert app3 != self.app
42
+ assert app3 != app2
43
+
44
+ @patch("regscale.core.app.internal.login.parse_user_id_from_jwt")
45
+ @patch("requests.get")
46
+ def test_fetch_config_from_regscale_success(self, mock_get, mock_parse_user_id):
47
+ mock_parse_user_id.return_value = "test_user_id"
48
+ mock_response = MagicMock()
49
+ mock_response.json.return_value = {"cliConfig": "key: value"}
50
+ mock_get.return_value = mock_response
51
+ config = self.app._fetch_config_from_regscale(config=self.app.config)
52
+ assert "domain" in config
53
+ assert config["userId"] == "test_user_id"
54
+ assert config["key"] == "value"
55
+
56
+ @patch("regscale.core.app.internal.login.parse_user_id_from_jwt")
57
+ @patch("requests.get")
58
+ def test_fetch_config_from_regscale_success_with_envars(self, mock_get, mock_parse_user_id):
59
+ mock_parse_user_id.return_value = "test_user_id"
60
+ mock_response = MagicMock()
61
+ mock_response.json.return_value = {"cliConfig": "key: value"}
62
+ mock_get.return_value = mock_response
63
+ os.environ["REGSCALE_DOMAIN"] = self.test_domain
64
+ os.environ["REGSCALE_TOKEN"] = self.test_token
65
+ config = self.app._fetch_config_from_regscale(config={})
66
+ assert config["domain"] == self.test_domain
67
+ assert config["token"] == self.test_token
68
+ assert config["userId"] == "test_user_id"
69
+ assert config["key"] == "value"
70
+
71
+ @patch("requests.get")
72
+ def test_fetch_config_from_regscale_failure(self, mock_get):
73
+ mock_response = MagicMock()
74
+ mock_response.json.return_value = "Not found."
75
+ mock_response.status_code = 404
76
+ mock_get.return_value = mock_response
77
+ os.environ["REGSCALE_DOMAIN"] = self.test_domain
78
+ os.environ["REGSCALE_TOKEN"] = self.test_token
79
+ empty_config = self.app._fetch_config_from_regscale()
80
+ assert empty_config == {}
81
+ with patch.object(self.app.logger, "error") as mock_logger_error:
82
+ config = self.app._fetch_config_from_regscale(config=self.app.config)
83
+ mock_logger_error.assert_called_once()
84
+ assert config == {}
85
+
86
+ def test_gen_config(self):
87
+ self.app.local_config = True
88
+ self.app.config_file = "test_gen_config.yaml"
89
+ config = self.app._gen_config()
90
+ assert "key" not in config
91
+ assert "domain" in config
92
+ assert "token" in config
93
+
94
+ small_config = {"key": "value", "domain": self.test_domain}
95
+ config = self.app._gen_config(small_config)
96
+ assert config["key"] == "value"
97
+ assert config["domain"] == self.test_domain
98
+ os.remove(self.app.config_file)
99
+
100
+ def test_gen_config_airflow(self):
101
+ self.app.running_in_airflow = True
102
+ with patch.object(self.app, "_get_airflow_config", return_value={"key": "value"}):
103
+ config = self.app._gen_config()
104
+ assert config == {"key": "value"}
105
+
106
+ def test_gen_config_with_provided_config(self):
107
+ self.app.local_config = True
108
+ config = {"key": "value"}
109
+ with patch.object(self.app, "_get_env", return_value={"env_key": "env_value"}):
110
+ with patch.object(self.app, "verify_config", return_value={"key": "value", "env_key": "env_value"}):
111
+ with patch.object(self.app, "save_config") as mock_save_config:
112
+ result = self.app._gen_config(config)
113
+ assert result == {"key": "value", "env_key": "env_value"}
114
+ mock_save_config.assert_called_once()
115
+
116
+ def test_gen_config_without_local_config(self):
117
+ self.app.local_config = False
118
+ with patch.object(self.app, "_get_env", return_value={"env_key": "env_value"}):
119
+ with patch.object(self.app, "verify_config", return_value={"env_key": "env_value"}):
120
+ with patch.object(self.app, "save_config") as mock_save_config:
121
+ result = self.app._gen_config()
122
+ assert result == {"env_key": "env_value"}
123
+ mock_save_config.assert_called_once()
124
+
125
+ def test_gen_config_with_file_config(self):
126
+ self.app.local_config = True
127
+ with patch.object(self.app, "_get_conf", return_value={"file_key": "file_value"}):
128
+ with patch.object(self.app, "_get_env", return_value={"env_key": "env_value"}):
129
+ with patch.object(
130
+ self.app, "verify_config", return_value={"file_key": "file_value", "env_key": "env_value"}
131
+ ):
132
+ with patch.object(self.app, "save_config") as mock_save_config:
133
+ result = self.app._gen_config()
134
+ assert result == {"file_key": "file_value", "env_key": "env_value"}
135
+ mock_save_config.assert_called_once()
136
+
137
+ def test_gen_config_scanner_error(self):
138
+ from yaml.scanner import ScannerError
139
+
140
+ self.app.local_config = True
141
+ with patch.object(self.app, "_get_conf", side_effect=ScannerError):
142
+ with patch.object(self.app, "save_config") as mock_save_config:
143
+ result = self.app._gen_config()
144
+ assert result == self.app.template
145
+ # called twice because the first call is to save the default config
146
+ mock_save_config.assert_called_once()
147
+
148
+ def test_get_airflow_config_with_dict(self):
149
+ config = {"key": "value"}
150
+ with patch.object(self.app, "_fetch_config_from_regscale", return_value={"key": "value"}):
151
+ result = self.app._get_airflow_config(config)
152
+ assert result == {"key": "value"}
153
+
154
+ def test_get_airflow_config_with_str(self):
155
+ config = "{'key': 'value'}"
156
+ with patch.object(self.app, "_fetch_config_from_regscale", return_value={"key": "value"}):
157
+ result = self.app._get_airflow_config(config)
158
+ assert result == {"key": "value"}
159
+
160
+ def test_get_airflow_config_with_env_vars(self):
161
+ os.environ["REGSCALE_TOKEN"] = self.test_token
162
+ os.environ["REGSCALE_DOMAIN"] = self.test_domain
163
+ with patch.object(self.app, "_fetch_config_from_regscale", return_value={"key": "value"}):
164
+ result = self.app._get_airflow_config()
165
+ assert result == {"key": "value"}
166
+
167
+ def test_get_airflow_config_no_config(self):
168
+ os.environ["REGSCALE_TOKEN"] = ""
169
+ os.environ["REGSCALE_DOMAIN"] = ""
170
+ result = self.app._get_airflow_config()
171
+ assert result is None
172
+
173
+ os.environ["REGSCALE_TOKEN"] = self.test_token
174
+ os.environ["REGSCALE_DOMAIN"] = self.test_domain
175
+ with patch.object(
176
+ self.app, "_fetch_config_from_regscale", return_value={"token": self.test_token, "domain": self.test_domain}
177
+ ):
178
+ result = self.app._get_airflow_config()
179
+ assert result["token"] == self.test_token
180
+ assert result["domain"] == self.test_domain
181
+
182
+ def test_get_airflow_config_invalid_json(self):
183
+ config = "{'key': 'value'"
184
+ with patch.object(self.app.logger, "debug") as mock_logger_debug:
185
+ result = self.app._get_airflow_config(config)
186
+ assert result is None
187
+ mock_logger_debug.assert_called()
188
+
189
+ def test_get_env_with_matching_keys(self):
190
+ with patch.object(self.app, "template", {"key1": "value1", "key2": "value2"}):
191
+ with patch.dict(os.environ, {"key1": "env_value1", "key2": "env_value2"}):
192
+ result = self.app._get_env()
193
+ assert result == {"key1": "env_value1", "key2": "env_value2"}
194
+
195
+ def test_get_env_with_no_matching_keys(self):
196
+ with patch.object(self.app, "template", {"key1": "value1", "key2": "value2"}):
197
+ with patch.dict(os.environ, {"key3": "env_value3"}):
198
+ result = self.app._get_env()
199
+ assert result == {"key1": "value1", "key2": "value2"}
200
+
201
+ def test_get_env_with_key_error(self):
202
+ with patch.object(self.app, "template", {"key1": "value1", "key2": "value2"}):
203
+ with patch.dict(os.environ, {"key1": "env_value1"}):
204
+ with patch.object(self.app.logger, "error") as mock_logger_error:
205
+ result = self.app._get_env()
206
+ assert result == {"key1": "env_value1", "key2": "value2"}
207
+ mock_logger_error.assert_not_called()
208
+
209
+ def test_get_env_with_template_match(self):
210
+ with patch.object(self.app, "template", {"key1": "value1", "key2": "value2"}):
211
+ with patch.dict(os.environ, {"key1": "value1", "key2": "value2"}):
212
+ result = self.app._get_env()
213
+ assert result == {"key1": "value1", "key2": "value2"}
214
+ assert self.app.templated is True
215
+
216
+ def test_get_env_without_template_match(self):
217
+ with patch.object(self.app, "template", {"key1": "value1", "key2": "value2"}):
218
+ with patch.dict(os.environ, {"key1": "env_value1"}):
219
+ result = self.app._get_env()
220
+ assert result == {"key1": "env_value1", "key2": "value2"}
221
+ assert self.app.templated is False
222
+
223
+ def test_get_conf(self):
224
+ self.app.config_file = self.test_config_file
225
+ self.app = Application(config={"key": "value"})
226
+ with patch("yaml.safe_load", return_value={"key": "value"}):
227
+ config = self.app._get_conf()
228
+ assert config == {"key": "value"}
229
+ with patch("yaml.safe_load", side_effect=FileNotFoundError):
230
+ config = self.app._get_conf()
231
+ assert config is None
232
+
233
+ def test_save_config(self):
234
+ from regscale.core.app.utils.api_handler import APIHandler
235
+
236
+ self.app.config_file = "test_save_config.yaml"
237
+ test_config = {"key": "value"}
238
+ with patch.object(self.app, "running_in_airflow", True):
239
+ self.app.save_config(test_config)
240
+ config = self.app.load_config()
241
+ assert "key" not in config
242
+
243
+ self.app.running_in_airflow = False
244
+ self.app.save_config(test_config)
245
+ config = self.app.load_config()
246
+ assert config is not None
247
+ assert config["key"] == "value"
248
+ assert "domain" not in config
249
+
250
+ test_api_handler = APIHandler()
251
+ self.app.api_handler = test_api_handler
252
+ test_config = {"api_handler": "testing_api_handler", "domain": self.test_domain}
253
+ self.app.save_config(test_config)
254
+ config = self.app.load_config()
255
+ assert config["api_handler"] == "testing_api_handler"
256
+ assert test_api_handler.domain == self.test_domain
257
+ assert test_api_handler.config == test_config
258
+
259
+ with patch.object(self.app.logger, "error") as mock_logger_error:
260
+ with patch("yaml.dump", side_effect=OSError):
261
+ self.app.save_config({})
262
+ mock_logger_error.assert_called_once()
263
+
264
+ os.remove(self.app.config_file)
265
+
266
+ def test_get_regscale_license(self):
267
+ with patch("requests.get"):
268
+ regscale_license = self.app.get_regscale_license(MagicMock())
269
+ assert isinstance(regscale_license, MagicMock)
270
+
271
+ def test_load_config(self):
272
+ self.app.config_file = self.test_config_file
273
+ with patch("yaml.safe_load", side_effect=FileNotFoundError):
274
+ config = self.app.load_config()
275
+ assert config == {}
276
+
277
+ self.app.save_config({"key": "value"})
278
+ config = self.app.load_config()
279
+ assert config == {"key": "value"}
280
+
281
+ def test_get_regscale_license_with_config(self):
282
+ api = MagicMock()
283
+ api.config = {"domain": self.test_domain}
284
+ api.get.return_value = Response()
285
+ self.app.config = api.config
286
+
287
+ with patch.object(self.app, "retrieve_domain", return_value=self.test_domain):
288
+ response = self.app.get_regscale_license(api)
289
+ api.get.assert_called_once_with(url="https://example.com/api/config/getlicense")
290
+ assert isinstance(response, Response)
291
+
292
+ def test_get_regscale_license_without_config(self):
293
+ api = MagicMock()
294
+ api.config = {"domain": self.test_domain}
295
+ api.get.return_value = Response()
296
+ self.app.config = None
297
+
298
+ with patch.object(self.app, "_gen_config", return_value={"domain": self.test_domain}):
299
+ with patch.object(self.app, "retrieve_domain", return_value=self.test_domain):
300
+ response = self.app.get_regscale_license(api)
301
+ api.get.assert_called_once_with(url="https://example.com/api/config/getlicense")
302
+ assert isinstance(response, Response)
303
+
304
+ def test_get_regscale_license_with_airflow_config(self):
305
+ api = MagicMock()
306
+ api.config = None
307
+ api.get.return_value = Response()
308
+ self.app.config = None
309
+ self.app.running_in_airflow = True
310
+
311
+ with patch.object(self.app, "_get_airflow_config", return_value={"domain": self.test_domain}):
312
+ with patch.object(self.app, "retrieve_domain", return_value=self.test_domain):
313
+ response = self.app.get_regscale_license(api)
314
+ api.get.assert_called_once_with(url="https://example.com/api/config/getlicense")
315
+ assert isinstance(response, Response)
316
+
317
+ def test_get_regscale_license_with_suppressed_exception(self):
318
+ import requests
319
+
320
+ api = MagicMock()
321
+ api.config = {"domain": self.test_domain}
322
+ api.get.side_effect = requests.RequestException
323
+ self.app.config = {"domain": self.test_domain}
324
+
325
+ with patch.object(self.app, "retrieve_domain", return_value=self.test_domain):
326
+ response = self.app.get_regscale_license(api)
327
+ api.get.assert_called_once_with(url="https://example.com/api/config/getlicense")
328
+ assert response is None
329
+
330
+ def test_retrieve_domain(self):
331
+ possible_envars = ["REGSCALE_DOMAIN", "PLATFORM_HOST", "domain"]
332
+ for envar in possible_envars:
333
+ with patch("os.environ", {envar: self.test_domain}):
334
+ domain = self.app.retrieve_domain()
335
+ assert domain == self.test_domain
336
+ with patch("os.environ", {envar: "www.example.com"}):
337
+ domain = self.app.retrieve_domain()
338
+ assert domain == self.app.template["domain"]
339
+
340
+ def test_verify_config(self):
341
+ template = {"key": "value"}
342
+ config = {"key": "other_value"}
343
+ updated_config = self.app.verify_config(template, config)
344
+ assert updated_config == {"key": "other_value"}
345
+
346
+ def test_verify_config_with_missing_keys(self):
347
+ template = {"key1": "value1", "key2": "value2"}
348
+ config = {"key1": "value1"}
349
+ expected_config = {"key1": "value1", "key2": "value2"}
350
+ updated_config = self.app.verify_config(template, config)
351
+ assert updated_config == expected_config
352
+
353
+ def test_verify_config_with_type_mismatch(self):
354
+ template = {"key1": "value1", "key2": 2}
355
+ config = {"key1": "value1", "key2": "wrong_type"}
356
+ expected_config = {"key1": "value1", "key2": 2}
357
+ updated_config = self.app.verify_config(template, config)
358
+ assert updated_config == expected_config
359
+
360
+ def test_verify_config_with_nested_dict(self):
361
+ template = {"key1": "value1", "key2": {"subkey1": "subvalue1"}}
362
+ config = {"key1": "value1", "key2": {"subkey1": "wrong_value"}}
363
+ expected_config = {"key1": "value1", "key2": {"subkey1": "wrong_value"}}
364
+ updated_config = self.app.verify_config(template, config)
365
+ assert updated_config == expected_config
366
+
367
+ def test_verify_config_with_additional_keys(self):
368
+ template = {"key1": "value1"}
369
+ config = {"key1": "value1", "key2": "value2"}
370
+ expected_config = {"key1": "value1", "key2": "value2"}
371
+ updated_config = self.app.verify_config(template, config)
372
+ assert updated_config == expected_config
373
+
374
+ def test_verify_config_with_empty_config(self):
375
+ template = {"key1": "value1", "key2": "value2"}
376
+ config = {}
377
+ expected_config = {"key1": "value1", "key2": "value2"}
378
+ updated_config = self.app.verify_config(template, config)
379
+ assert updated_config == expected_config
380
+
381
+ def test_getitem(self):
382
+ self.app.config = {"key": "value"}
383
+ assert self.app["key"] == "value"
384
+
385
+ def test_setitem(self):
386
+ self.app.config = {}
387
+ self.app["key"] = "value"
388
+ assert self.app.config == {"key": "value"}
389
+
390
+ def test_delitem(self):
391
+ self.app.config = {"key": "value"}
392
+ del self.app["key"]
393
+ assert self.app.config == {}
394
+
395
+ def test_iter(self):
396
+ self.app.config = {"key1": "value1", "key2": "value2"}
397
+ assert list(self.app) == ["key1", "key2"]
398
+
399
+ def test_len(self):
400
+ self.app.config = {"key1": "value1", "key2": "value2"}
401
+ assert len(self.app) == 2
402
+
403
+ def test_contains(self):
404
+ self.app.config = {"key": "value"}
405
+ assert "key" in self.app
406
+ assert "nonexistent_key" not in self.app
@@ -0,0 +1,37 @@
1
+ """Test the login module."""
2
+
3
+ from unittest.mock import patch
4
+
5
+ from regscale.core.login import get_regscale_token
6
+ from regscale.core.app.api import Api
7
+ from regscale.core.app.application import Application
8
+
9
+
10
+ @patch("regscale.core.login.Api.post")
11
+ @patch.dict("os.environ", {"REGSCALE_DOMAIN": "example_value"})
12
+ def test_get_regscale_token(mock_post):
13
+ api = Api()
14
+ mock_response = mock_post.return_value
15
+ mock_response.status_code = 200
16
+ mock_response.json.return_value = {
17
+ "id": "example_id",
18
+ "auth_token": "example_token",
19
+ }
20
+ result = get_regscale_token(api=api, username="example_user", password="example_password")
21
+ result2 = get_regscale_token(
22
+ api=api,
23
+ username="example_user",
24
+ password="example_password",
25
+ domain="example2_domain",
26
+ )
27
+ result3 = get_regscale_token(
28
+ api=api,
29
+ username="example_user",
30
+ password="example_password",
31
+ domain="example3_domain",
32
+ mfa_token="123456",
33
+ )
34
+
35
+ assert result == ("example_id", "example_token")
36
+ assert result2 == ("example_id", "example_token")
37
+ assert result3 == ("example_id", "example_token")
@@ -0,0 +1,66 @@
1
+ import logging
2
+ import os
3
+ from unittest import mock
4
+ from rich.logging import RichHandler
5
+ from regscale.core.app.logz import create_logger
6
+
7
+
8
+ def test_create_logger_creates_logger_with_default_settings():
9
+ logger = create_logger()
10
+ assert logger.name == "regscale"
11
+ assert logger.level == logging.INFO
12
+
13
+
14
+ def test_create_logger_respects_propagate_parameter():
15
+ logger = create_logger(propagate=True)
16
+ assert logger.propagate is True
17
+
18
+
19
+ def test_create_logger_adds_custom_handler():
20
+ custom_handler = logging.StreamHandler()
21
+ logger = create_logger(custom_handler=custom_handler)
22
+ assert any(isinstance(handler, logging.StreamHandler) for handler in logger.handlers)
23
+
24
+
25
+ def test_create_logger_creates_file_handler_when_not_in_container():
26
+ with mock.patch.dict(os.environ, {"REGSCALE_ECS": "False"}):
27
+ logger = create_logger()
28
+ assert any(isinstance(handler, logging.handlers.TimedRotatingFileHandler) for handler in logger.handlers)
29
+
30
+
31
+ def test_create_logger_does_not_create_file_handler_when_in_container():
32
+ with mock.patch.dict(os.environ, {"REGSCALE_ECS": "True"}):
33
+ logger = create_logger()
34
+ assert not any(isinstance(handler, logging.handlers.TimedRotatingFileHandler) for handler in logger.handlers)
35
+
36
+
37
+ def test_create_logger_uses_custom_log_level():
38
+ with mock.patch.dict(os.environ, {"LOGLEVEL": "DEBUG"}):
39
+ logger = create_logger()
40
+ assert logger.level == logging.DEBUG
41
+
42
+
43
+ def test_create_logger_uses_custom_log_width():
44
+ with mock.patch.dict(os.environ, {"REGSCALE_LOG_WIDTH": "100"}):
45
+ logger = create_logger()
46
+ assert any(
47
+ getattr(handler.console, "width", None) == 100
48
+ for handler in logger.handlers
49
+ if isinstance(handler, RichHandler)
50
+ )
51
+
52
+
53
+ def test_create_logger_handles_invalid_log_width():
54
+ with mock.patch.dict(os.environ, {"REGSCALE_LOG_WIDTH": "invalid"}):
55
+ logger = create_logger()
56
+ assert any(
57
+ getattr(handler.console, "width", None) is not None
58
+ for handler in logger.handlers
59
+ if isinstance(handler, RichHandler)
60
+ )
61
+
62
+
63
+ def test_getting_regscale_logger():
64
+ logger = logging.getLogger("regscale")
65
+ assert logger.name == "regscale"
66
+ assert len(logger.handlers) > 0
@@ -0,0 +1,87 @@
1
+ import logging
2
+ from unittest.mock import Mock
3
+
4
+ from regscale.models.integration_models.sbom.cyclone_dx import CycloneDXJsonGenerator
5
+
6
+
7
+ def test_initialization():
8
+ device = {"deviceName": "test-device", "manufacturer": "Test Corp"}
9
+ generator = CycloneDXJsonGenerator(device)
10
+
11
+ assert generator.device == device
12
+ assert isinstance(generator.logger, logging.Logger)
13
+ assert generator.device_info.name == "test-device"
14
+ assert generator.device_info.manufacturer == "Test Corp"
15
+
16
+
17
+ def test_initialization_custom_logger():
18
+ logger = Mock()
19
+ generator = CycloneDXJsonGenerator({}, logger)
20
+ assert generator.logger == logger
21
+
22
+
23
+ def test_device_description_generation():
24
+ device = {"manufacturer": "Test Corp", "model": "Model X", "deviceType": "Router"}
25
+ generator = CycloneDXJsonGenerator(device)
26
+ description = generator.generate_device_description()
27
+ assert description == "Test Corp Model X Router"
28
+
29
+
30
+ def test_device_description_partial_info():
31
+ device = {"model": "Model X"}
32
+ generator = CycloneDXJsonGenerator(device)
33
+ description = generator.generate_device_description()
34
+ assert description == "Model X"
35
+
36
+
37
+ def test_device_description_empty():
38
+ generator = CycloneDXJsonGenerator({})
39
+ description = generator.generate_device_description()
40
+ assert description == "Unknown Device"
41
+
42
+
43
+ def test_component_validation():
44
+ generator = CycloneDXJsonGenerator({})
45
+ valid_component = {"type": "library", "name": "test-lib"}
46
+ invalid_type = {"type": "invalid", "name": "test"}
47
+ missing_field = {"type": "library"}
48
+
49
+ assert generator.validate(valid_component)
50
+ assert not generator.validate(invalid_type)
51
+ assert not generator.validate(missing_field)
52
+
53
+
54
+ def test_generate_sbom():
55
+ device = {"deviceName": "test-device", "manufacturer": "Test Corp", "easDeviceId": "device-123"}
56
+ components = [{"type": "library", "name": "lib1"}, {"type": "framework", "name": "framework1"}]
57
+
58
+ generator = CycloneDXJsonGenerator(device)
59
+ sbom = generator.generate_sbom(components)
60
+
61
+ assert sbom["bomFormat"] == "CycloneDX"
62
+ assert sbom["specVersion"] == "1.4"
63
+ assert len(sbom["components"]) == 3 # device + 2 components
64
+ assert len(sbom["dependencies"]) == 1
65
+ assert sbom["dependencies"][0]["ref"] == "device-123"
66
+ assert len(sbom["dependencies"][0]["dependsOn"]) == 2
67
+
68
+
69
+ def test_generate_sbom_invalid_components():
70
+ device = {"deviceName": "test-device"}
71
+ components = [
72
+ {"type": "library", "name": "lib1"},
73
+ {"type": "invalid", "name": "invalid1"},
74
+ {"name": "missing-type"},
75
+ ]
76
+
77
+ generator = CycloneDXJsonGenerator(device)
78
+ sbom = generator.generate_sbom(components)
79
+
80
+ assert len(sbom["components"]) == 2 # device + 1 valid component
81
+
82
+
83
+ def test_sbom_metadata():
84
+ generator = CycloneDXJsonGenerator({})
85
+ sbom = generator.generate_sbom([])
86
+
87
+ assert sbom["metadata"]["tools"][0]["name"] == "RegScale CLI"