regscale-cli 6.21.2.0__py3-none-any.whl → 6.28.2.1__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.
Files changed (314) hide show
  1. regscale/_version.py +1 -1
  2. regscale/airflow/hierarchy.py +2 -2
  3. regscale/core/app/api.py +5 -2
  4. regscale/core/app/application.py +36 -6
  5. regscale/core/app/internal/control_editor.py +73 -21
  6. regscale/core/app/internal/evidence.py +727 -204
  7. regscale/core/app/internal/login.py +4 -2
  8. regscale/core/app/internal/model_editor.py +219 -64
  9. regscale/core/app/utils/app_utils.py +86 -12
  10. regscale/core/app/utils/catalog_utils/common.py +1 -1
  11. regscale/core/login.py +21 -4
  12. regscale/core/utils/async_graphql_client.py +363 -0
  13. regscale/core/utils/date.py +77 -1
  14. regscale/dev/cli.py +26 -0
  15. regscale/dev/code_gen.py +109 -24
  16. regscale/dev/version.py +72 -0
  17. regscale/integrations/commercial/__init__.py +30 -2
  18. regscale/integrations/commercial/aws/audit_manager_compliance.py +3908 -0
  19. regscale/integrations/commercial/aws/cli.py +3107 -54
  20. regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
  21. regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
  22. regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
  23. regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
  24. regscale/integrations/commercial/{amazon → aws}/common.py +71 -19
  25. regscale/integrations/commercial/aws/config_compliance.py +914 -0
  26. regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
  27. regscale/integrations/commercial/aws/control_compliance_analyzer.py +439 -0
  28. regscale/integrations/commercial/aws/evidence_generator.py +283 -0
  29. regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
  30. regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
  31. regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
  32. regscale/integrations/commercial/aws/iam_evidence.py +574 -0
  33. regscale/integrations/commercial/aws/inventory/__init__.py +338 -22
  34. regscale/integrations/commercial/aws/inventory/base.py +107 -5
  35. regscale/integrations/commercial/aws/inventory/resources/analytics.py +390 -0
  36. regscale/integrations/commercial/aws/inventory/resources/applications.py +234 -0
  37. regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
  38. regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
  39. regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
  40. regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
  41. regscale/integrations/commercial/aws/inventory/resources/compute.py +328 -9
  42. regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
  43. regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
  44. regscale/integrations/commercial/aws/inventory/resources/database.py +481 -31
  45. regscale/integrations/commercial/aws/inventory/resources/developer_tools.py +253 -0
  46. regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
  47. regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
  48. regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
  49. regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
  50. regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
  51. regscale/integrations/commercial/aws/inventory/resources/machine_learning.py +358 -0
  52. regscale/integrations/commercial/aws/inventory/resources/networking.py +390 -67
  53. regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
  54. regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
  55. regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
  56. regscale/integrations/commercial/aws/inventory/resources/storage.py +288 -29
  57. regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
  58. regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
  59. regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
  60. regscale/integrations/commercial/aws/kms_evidence.py +879 -0
  61. regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
  62. regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
  63. regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
  64. regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
  65. regscale/integrations/commercial/aws/org_evidence.py +666 -0
  66. regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
  67. regscale/integrations/commercial/aws/s3_evidence.py +632 -0
  68. regscale/integrations/commercial/aws/scanner.py +1072 -205
  69. regscale/integrations/commercial/aws/security_hub.py +319 -0
  70. regscale/integrations/commercial/aws/session_manager.py +282 -0
  71. regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
  72. regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
  73. regscale/integrations/commercial/jira.py +489 -153
  74. regscale/integrations/commercial/microsoft_defender/defender.py +326 -5
  75. regscale/integrations/commercial/microsoft_defender/defender_api.py +348 -14
  76. regscale/integrations/commercial/microsoft_defender/defender_constants.py +157 -0
  77. regscale/integrations/commercial/qualys/__init__.py +167 -68
  78. regscale/integrations/commercial/qualys/scanner.py +305 -39
  79. regscale/integrations/commercial/sarif/sairf_importer.py +432 -0
  80. regscale/integrations/commercial/sarif/sarif_converter.py +67 -0
  81. regscale/integrations/commercial/sicura/api.py +79 -42
  82. regscale/integrations/commercial/sicura/commands.py +8 -2
  83. regscale/integrations/commercial/sicura/scanner.py +83 -44
  84. regscale/integrations/commercial/stigv2/ckl_parser.py +5 -5
  85. regscale/integrations/commercial/synqly/assets.py +133 -16
  86. regscale/integrations/commercial/synqly/edr.py +2 -8
  87. regscale/integrations/commercial/synqly/query_builder.py +536 -0
  88. regscale/integrations/commercial/synqly/ticketing.py +27 -0
  89. regscale/integrations/commercial/synqly/vulnerabilities.py +165 -28
  90. regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
  91. regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
  92. regscale/integrations/commercial/tenablev2/commands.py +146 -5
  93. regscale/integrations/commercial/tenablev2/scanner.py +1 -3
  94. regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
  95. regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
  96. regscale/integrations/commercial/wizv2/click.py +191 -76
  97. regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
  98. regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
  99. regscale/integrations/commercial/wizv2/compliance_report.py +1592 -0
  100. regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
  101. regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +7 -3
  102. regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +92 -89
  103. regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
  104. regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
  105. regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +66 -9
  106. regscale/integrations/commercial/wizv2/file_cleanup.py +104 -0
  107. regscale/integrations/commercial/wizv2/issue.py +776 -28
  108. regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
  109. regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
  110. regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
  111. regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
  112. regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
  113. regscale/integrations/commercial/wizv2/reports.py +243 -0
  114. regscale/integrations/commercial/wizv2/sbom.py +1 -1
  115. regscale/integrations/commercial/wizv2/scanner.py +1031 -441
  116. regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
  117. regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
  118. regscale/integrations/commercial/wizv2/variables.py +89 -3
  119. regscale/integrations/compliance_integration.py +1036 -151
  120. regscale/integrations/control_matcher.py +432 -0
  121. regscale/integrations/due_date_handler.py +333 -0
  122. regscale/integrations/milestone_manager.py +291 -0
  123. regscale/integrations/public/__init__.py +14 -0
  124. regscale/integrations/public/cci_importer.py +834 -0
  125. regscale/integrations/public/csam/__init__.py +0 -0
  126. regscale/integrations/public/csam/csam.py +938 -0
  127. regscale/integrations/public/csam/csam_agency_defined.py +179 -0
  128. regscale/integrations/public/csam/csam_common.py +154 -0
  129. regscale/integrations/public/csam/csam_controls.py +432 -0
  130. regscale/integrations/public/csam/csam_poam.py +124 -0
  131. regscale/integrations/public/fedramp/click.py +77 -6
  132. regscale/integrations/public/fedramp/docx_parser.py +10 -1
  133. regscale/integrations/public/fedramp/fedramp_cis_crm.py +675 -289
  134. regscale/integrations/public/fedramp/fedramp_five.py +1 -1
  135. regscale/integrations/public/fedramp/poam/scanner.py +75 -7
  136. regscale/integrations/public/fedramp/poam_export_v5.py +888 -0
  137. regscale/integrations/scanner_integration.py +1961 -430
  138. regscale/models/integration_models/CCI_List.xml +1 -0
  139. regscale/models/integration_models/aqua.py +2 -2
  140. regscale/models/integration_models/cisa_kev_data.json +805 -11
  141. regscale/models/integration_models/flat_file_importer/__init__.py +5 -8
  142. regscale/models/integration_models/nexpose.py +36 -10
  143. regscale/models/integration_models/qualys.py +3 -4
  144. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  145. regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +87 -18
  146. regscale/models/integration_models/synqly_models/filter_parser.py +332 -0
  147. regscale/models/integration_models/synqly_models/ocsf_mapper.py +124 -25
  148. regscale/models/integration_models/synqly_models/synqly_model.py +89 -16
  149. regscale/models/locking.py +12 -8
  150. regscale/models/platform.py +4 -2
  151. regscale/models/regscale_models/__init__.py +7 -0
  152. regscale/models/regscale_models/assessment.py +2 -1
  153. regscale/models/regscale_models/catalog.py +1 -1
  154. regscale/models/regscale_models/compliance_settings.py +251 -1
  155. regscale/models/regscale_models/component.py +1 -0
  156. regscale/models/regscale_models/control_implementation.py +236 -41
  157. regscale/models/regscale_models/control_objective.py +74 -5
  158. regscale/models/regscale_models/file.py +2 -0
  159. regscale/models/regscale_models/form_field_value.py +5 -3
  160. regscale/models/regscale_models/inheritance.py +44 -0
  161. regscale/models/regscale_models/issue.py +301 -102
  162. regscale/models/regscale_models/milestone.py +33 -14
  163. regscale/models/regscale_models/organization.py +3 -0
  164. regscale/models/regscale_models/regscale_model.py +310 -73
  165. regscale/models/regscale_models/security_plan.py +4 -2
  166. regscale/models/regscale_models/vulnerability.py +3 -3
  167. regscale/regscale.py +25 -4
  168. regscale/templates/__init__.py +0 -0
  169. regscale/utils/threading/threadhandler.py +20 -15
  170. regscale/validation/record.py +23 -1
  171. {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/METADATA +17 -33
  172. {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/RECORD +310 -111
  173. tests/core/__init__.py +0 -0
  174. tests/core/utils/__init__.py +0 -0
  175. tests/core/utils/test_async_graphql_client.py +472 -0
  176. tests/fixtures/test_fixture.py +13 -8
  177. tests/regscale/core/test_login.py +171 -4
  178. tests/regscale/integrations/commercial/__init__.py +0 -0
  179. tests/regscale/integrations/commercial/aws/__init__.py +0 -0
  180. tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
  181. tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
  182. tests/regscale/integrations/commercial/aws/test_aws_analytics_collector.py +260 -0
  183. tests/regscale/integrations/commercial/aws/test_aws_applications_collector.py +242 -0
  184. tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
  185. tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
  186. tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
  187. tests/regscale/integrations/commercial/aws/test_aws_developer_tools_collector.py +203 -0
  188. tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
  189. tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
  190. tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
  191. tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
  192. tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
  193. tests/regscale/integrations/commercial/aws/test_aws_machine_learning_collector.py +237 -0
  194. tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
  195. tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
  196. tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
  197. tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
  198. tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
  199. tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
  200. tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
  201. tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
  202. tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
  203. tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
  204. tests/regscale/integrations/commercial/aws/test_control_compliance_analyzer.py +375 -0
  205. tests/regscale/integrations/commercial/aws/test_datetime_parsing.py +223 -0
  206. tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
  207. tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
  208. tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
  209. tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
  210. tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
  211. tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
  212. tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
  213. tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
  214. tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
  215. tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
  216. tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
  217. tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
  218. tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
  219. tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
  220. tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
  221. tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
  222. tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
  223. tests/regscale/integrations/commercial/conftest.py +28 -0
  224. tests/regscale/integrations/commercial/microsoft_defender/__init__.py +1 -0
  225. tests/regscale/integrations/commercial/microsoft_defender/test_defender.py +1517 -0
  226. tests/regscale/integrations/commercial/microsoft_defender/test_defender_api.py +1748 -0
  227. tests/regscale/integrations/commercial/microsoft_defender/test_defender_constants.py +327 -0
  228. tests/regscale/integrations/commercial/microsoft_defender/test_defender_scanner.py +487 -0
  229. tests/regscale/integrations/commercial/test_aws.py +3742 -0
  230. tests/regscale/integrations/commercial/test_burp.py +48 -0
  231. tests/regscale/integrations/commercial/test_crowdstrike.py +49 -0
  232. tests/regscale/integrations/commercial/test_dependabot.py +341 -0
  233. tests/regscale/integrations/commercial/test_gcp.py +1543 -0
  234. tests/regscale/integrations/commercial/test_gitlab.py +549 -0
  235. tests/regscale/integrations/commercial/test_ip_mac_address_length.py +84 -0
  236. tests/regscale/integrations/commercial/test_jira.py +2204 -0
  237. tests/regscale/integrations/commercial/test_npm_audit.py +42 -0
  238. tests/regscale/integrations/commercial/test_okta.py +1228 -0
  239. tests/regscale/integrations/commercial/test_sarif_converter.py +251 -0
  240. tests/regscale/integrations/commercial/test_sicura.py +349 -0
  241. tests/regscale/integrations/commercial/test_snow.py +423 -0
  242. tests/regscale/integrations/commercial/test_sonarcloud.py +394 -0
  243. tests/regscale/integrations/commercial/test_sqlserver.py +186 -0
  244. tests/regscale/integrations/commercial/test_stig.py +33 -0
  245. tests/regscale/integrations/commercial/test_stig_mapper.py +153 -0
  246. tests/regscale/integrations/commercial/test_stigv2.py +406 -0
  247. tests/regscale/integrations/commercial/test_wiz.py +1365 -0
  248. tests/regscale/integrations/commercial/test_wiz_inventory.py +256 -0
  249. tests/regscale/integrations/commercial/wizv2/__init__.py +339 -0
  250. tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
  251. tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
  252. tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
  253. tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
  254. tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
  255. tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
  256. tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
  257. tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
  258. tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
  259. tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
  260. tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
  261. tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
  262. tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
  263. tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
  264. tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
  265. tests/regscale/integrations/commercial/wizv2/test_compliance_report_normalization.py +138 -0
  266. tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
  267. tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
  268. tests/regscale/integrations/commercial/wizv2/test_issue.py +343 -0
  269. tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
  270. tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
  271. tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
  272. tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
  273. tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +165 -0
  274. tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +1394 -0
  275. tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_unit.py +341 -0
  276. tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py +138 -0
  277. tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
  278. tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
  279. tests/regscale/integrations/commercial/wizv2/test_wiz_status_mapping.py +149 -0
  280. tests/regscale/integrations/commercial/wizv2/test_wizv2.py +1218 -0
  281. tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +519 -0
  282. tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
  283. tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
  284. tests/regscale/integrations/public/__init__.py +0 -0
  285. tests/regscale/integrations/public/fedramp/__init__.py +1 -0
  286. tests/regscale/integrations/public/fedramp/test_gen_asset_list.py +150 -0
  287. tests/regscale/integrations/public/fedramp/test_poam_export_v5.py +1293 -0
  288. tests/regscale/integrations/public/test_alienvault.py +220 -0
  289. tests/regscale/integrations/public/test_cci.py +1053 -0
  290. tests/regscale/integrations/public/test_cisa.py +1021 -0
  291. tests/regscale/integrations/public/test_emass.py +518 -0
  292. tests/regscale/integrations/public/test_fedramp.py +1152 -0
  293. tests/regscale/integrations/public/test_fedramp_cis_crm.py +3661 -0
  294. tests/regscale/integrations/public/test_file_uploads.py +506 -0
  295. tests/regscale/integrations/public/test_oscal.py +453 -0
  296. tests/regscale/integrations/test_compliance_status_mapping.py +406 -0
  297. tests/regscale/integrations/test_control_matcher.py +1421 -0
  298. tests/regscale/integrations/test_control_matching.py +155 -0
  299. tests/regscale/integrations/test_milestone_manager.py +408 -0
  300. tests/regscale/models/test_control_implementation.py +118 -3
  301. tests/regscale/models/test_form_field_value_integration.py +304 -0
  302. tests/regscale/models/test_issue.py +378 -1
  303. tests/regscale/models/test_module_integration.py +582 -0
  304. tests/regscale/models/test_tenable_integrations.py +811 -105
  305. regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3057
  306. regscale/integrations/public/fedramp/mappings/fedramp_r4_parts.json +0 -7388
  307. regscale/integrations/public/fedramp/mappings/fedramp_r5_parts.json +0 -9605
  308. regscale/integrations/public/fedramp/parts_mapper.py +0 -107
  309. /regscale/integrations/commercial/{amazon → sarif}/__init__.py +0 -0
  310. /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
  311. {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/LICENSE +0 -0
  312. {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/WHEEL +0 -0
  313. {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/entry_points.txt +0 -0
  314. {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,36 @@
1
1
  """AWS database resource collectors."""
2
2
 
3
- from typing import Dict, List, Any
3
+ from typing import Dict, List, Any, Optional
4
4
 
5
5
  from ..base import BaseCollector
6
6
 
7
7
 
8
8
  class DatabaseCollector(BaseCollector):
9
- """Collector for AWS database resources."""
9
+ """Collector for AWS database resources with filtering support."""
10
+
11
+ def __init__(
12
+ self,
13
+ session: Any,
14
+ region: str,
15
+ account_id: Optional[str] = None,
16
+ tags: Optional[Dict[str, str]] = None,
17
+ enabled_services: Optional[Dict[str, bool]] = None,
18
+ ):
19
+ """
20
+ Initialize database collector with filtering support.
21
+
22
+ :param session: AWS session to use for API calls
23
+ :param str region: AWS region to collect from
24
+ :param str account_id: Optional AWS account ID to filter resources
25
+ :param dict tags: Optional tag filters (AND logic)
26
+ :param dict enabled_services: Optional dict of service names to boolean flags for enabling/disabling collection
27
+ """
28
+ super().__init__(session, region, account_id, tags)
29
+ self.enabled_services = enabled_services or {}
10
30
 
11
31
  def get_rds_instances(self) -> List[Dict[str, Any]]:
12
32
  """
13
- Get information about RDS instances.
33
+ Get information about RDS instances with filtering.
14
34
 
15
35
  :return: List of RDS instance information
16
36
  :rtype: List[Dict[str, Any]]
@@ -22,10 +42,20 @@ class DatabaseCollector(BaseCollector):
22
42
 
23
43
  for page in paginator.paginate():
24
44
  for instance in page.get("DBInstances", []):
45
+ # Apply tag filtering
46
+ if self.tags and not self._matches_tags(instance.get("TagList", [])):
47
+ continue
48
+
49
+ # Apply account filtering using DBInstanceArn
50
+ instance_arn = instance.get("DBInstanceArn", "")
51
+ if not self._matches_account(instance_arn):
52
+ continue
53
+
25
54
  instances.append(
26
55
  {
27
56
  "Region": self.region,
28
57
  "DBInstanceIdentifier": instance.get("DBInstanceIdentifier"),
58
+ "DBInstanceArn": instance.get("DBInstanceArn"),
29
59
  "DBInstanceClass": instance.get("DBInstanceClass"),
30
60
  "Engine": instance.get("Engine"),
31
61
  "EngineVersion": instance.get("EngineVersion"),
@@ -34,6 +64,7 @@ class DatabaseCollector(BaseCollector):
34
64
  "AllocatedStorage": instance.get("AllocatedStorage"),
35
65
  "InstanceCreateTime": str(instance.get("InstanceCreateTime")),
36
66
  "VpcId": instance.get("DBSubnetGroup", {}).get("VpcId"),
67
+ "AvailabilityZone": instance.get("AvailabilityZone"),
37
68
  "MultiAZ": instance.get("MultiAZ"),
38
69
  "PubliclyAccessible": instance.get("PubliclyAccessible"),
39
70
  "StorageEncrypted": instance.get("StorageEncrypted"),
@@ -45,9 +76,60 @@ class DatabaseCollector(BaseCollector):
45
76
  self._handle_error(e, "RDS instances")
46
77
  return instances
47
78
 
79
+ def _should_include_table(self, dynamodb, table_arn: str, table_name: str) -> bool:
80
+ """
81
+ Check if table should be included based on account and tag filters.
82
+
83
+ :param dynamodb: DynamoDB client
84
+ :param str table_arn: Table ARN
85
+ :param str table_name: Table name
86
+ :return: True if table should be included, False otherwise
87
+ :rtype: bool
88
+ """
89
+ if not self._matches_account(table_arn):
90
+ return False
91
+
92
+ if self.tags:
93
+ try:
94
+ tags_response = dynamodb.list_tags_of_resource(ResourceArn=table_arn)
95
+ table_tags = tags_response.get("Tags", [])
96
+ return self._matches_tags(table_tags)
97
+ except Exception as e:
98
+ self._handle_error(e, f"DynamoDB table tags for {table_name}")
99
+ return False
100
+
101
+ return True
102
+
103
+ def _build_table_data(self, table: Dict[str, Any]) -> Dict[str, Any]:
104
+ """
105
+ Build table data dictionary.
106
+
107
+ :param table: Raw table data
108
+ :return: Processed table data
109
+ :rtype: Dict[str, Any]
110
+ """
111
+ return {
112
+ "Region": self.region,
113
+ "TableName": table.get("TableName"),
114
+ "TableStatus": table.get("TableStatus"),
115
+ "CreationDateTime": str(table.get("CreationDateTime")),
116
+ "TableSizeBytes": table.get("TableSizeBytes"),
117
+ "ItemCount": table.get("ItemCount"),
118
+ "TableArn": table.get("TableArn"),
119
+ "ProvisionedThroughput": {
120
+ "ReadCapacityUnits": table.get("ProvisionedThroughput", {}).get("ReadCapacityUnits"),
121
+ "WriteCapacityUnits": table.get("ProvisionedThroughput", {}).get("WriteCapacityUnits"),
122
+ },
123
+ "BillingModeSummary": table.get("BillingModeSummary", {}),
124
+ "GlobalSecondaryIndexes": table.get("GlobalSecondaryIndexes", []),
125
+ "LocalSecondaryIndexes": table.get("LocalSecondaryIndexes", []),
126
+ "StreamSpecification": table.get("StreamSpecification", {}),
127
+ "SSEDescription": table.get("SSEDescription", {}),
128
+ }
129
+
48
130
  def get_dynamodb_tables(self) -> List[Dict[str, Any]]:
49
131
  """
50
- Get information about DynamoDB tables.
132
+ Get information about DynamoDB tables with filtering.
51
133
 
52
134
  :return: List of DynamoDB table information
53
135
  :rtype: List[Dict[str, Any]]
@@ -61,41 +143,409 @@ class DatabaseCollector(BaseCollector):
61
143
  for table_name in page.get("TableNames", []):
62
144
  try:
63
145
  table = dynamodb.describe_table(TableName=table_name)["Table"]
64
- tables.append(
65
- {
66
- "Region": self.region,
67
- "TableName": table.get("TableName"),
68
- "TableStatus": table.get("TableStatus"),
69
- "CreationDateTime": str(table.get("CreationDateTime")),
70
- "TableSizeBytes": table.get("TableSizeBytes"),
71
- "ItemCount": table.get("ItemCount"),
72
- "TableArn": table.get("TableArn"),
73
- "ProvisionedThroughput": {
74
- "ReadCapacityUnits": table.get("ProvisionedThroughput", {}).get(
75
- "ReadCapacityUnits"
76
- ),
77
- "WriteCapacityUnits": table.get("ProvisionedThroughput", {}).get(
78
- "WriteCapacityUnits"
79
- ),
80
- },
81
- "BillingModeSummary": table.get("BillingModeSummary", {}),
82
- "GlobalSecondaryIndexes": table.get("GlobalSecondaryIndexes", []),
83
- "LocalSecondaryIndexes": table.get("LocalSecondaryIndexes", []),
84
- "StreamSpecification": table.get("StreamSpecification", {}),
85
- "SSEDescription": table.get("SSEDescription", {}),
86
- }
87
- )
146
+ table_arn = table.get("TableArn", "")
147
+
148
+ if not self._should_include_table(dynamodb, table_arn, table_name):
149
+ continue
150
+
151
+ table_data = self._build_table_data(table)
152
+ tables.append(table_data)
88
153
  except Exception as e:
89
154
  self._handle_error(e, f"DynamoDB table {table_name}")
90
155
  except Exception as e:
91
156
  self._handle_error(e, "DynamoDB tables")
92
157
  return tables
93
158
 
159
+ def get_elasticache_clusters(self) -> List[Dict[str, Any]]:
160
+ """
161
+ Get information about ElastiCache clusters (Redis and Memcached).
162
+
163
+ :return: List of ElastiCache cluster information
164
+ :rtype: List[Dict[str, Any]]
165
+ """
166
+ clusters = []
167
+ try:
168
+ elasticache = self._get_client("elasticache")
169
+ paginator = elasticache.get_paginator("describe_cache_clusters")
170
+
171
+ for page in paginator.paginate(ShowCacheNodeInfo=True):
172
+ for cluster in page.get("CacheClusters", []):
173
+ cluster_arn = cluster.get("ARN", "")
174
+
175
+ if not self._matches_account(cluster_arn):
176
+ continue
177
+
178
+ if not self._matches_tags(cluster.get("Tags", [])):
179
+ continue
180
+
181
+ clusters.append(
182
+ {
183
+ "Region": self.region,
184
+ "CacheClusterId": cluster.get("CacheClusterId"),
185
+ "CacheClusterArn": cluster_arn,
186
+ "Engine": cluster.get("Engine"),
187
+ "EngineVersion": cluster.get("EngineVersion"),
188
+ "CacheClusterStatus": cluster.get("CacheClusterStatus"),
189
+ "CacheNodeType": cluster.get("CacheNodeType"),
190
+ "NumCacheNodes": cluster.get("NumCacheNodes"),
191
+ "PreferredAvailabilityZone": cluster.get("PreferredAvailabilityZone"),
192
+ "CacheClusterCreateTime": cluster.get("CacheClusterCreateTime"),
193
+ "Tags": cluster.get("Tags", []),
194
+ }
195
+ )
196
+ except Exception as e:
197
+ self._handle_error(e, "ElastiCache clusters")
198
+ return clusters
199
+
200
+ def get_neptune_clusters(self) -> List[Dict[str, Any]]:
201
+ """
202
+ Get information about Neptune graph database clusters.
203
+
204
+ :return: List of Neptune cluster information
205
+ :rtype: List[Dict[str, Any]]
206
+ """
207
+ clusters = []
208
+ try:
209
+ neptune = self._get_client("neptune")
210
+ paginator = neptune.get_paginator("describe_db_clusters")
211
+
212
+ for page in paginator.paginate():
213
+ for cluster in page.get("DBClusters", []):
214
+ cluster_arn = cluster.get("DBClusterArn", "")
215
+
216
+ if not self._matches_account(cluster_arn):
217
+ continue
218
+
219
+ if not self._matches_tags(cluster.get("TagList", [])):
220
+ continue
221
+
222
+ clusters.append(
223
+ {
224
+ "Region": self.region,
225
+ "DBClusterIdentifier": cluster.get("DBClusterIdentifier"),
226
+ "DBClusterArn": cluster_arn,
227
+ "Engine": cluster.get("Engine"),
228
+ "EngineVersion": cluster.get("EngineVersion"),
229
+ "Status": cluster.get("Status"),
230
+ "Endpoint": cluster.get("Endpoint"),
231
+ "ReaderEndpoint": cluster.get("ReaderEndpoint"),
232
+ "MultiAZ": cluster.get("MultiAZ"),
233
+ "StorageEncrypted": cluster.get("StorageEncrypted"),
234
+ "KmsKeyId": cluster.get("KmsKeyId"),
235
+ "Tags": cluster.get("TagList", []),
236
+ }
237
+ )
238
+ except Exception as e:
239
+ self._handle_error(e, "Neptune clusters")
240
+ return clusters
241
+
242
+ def get_docdb_clusters(self) -> List[Dict[str, Any]]:
243
+ """
244
+ Get information about DocumentDB clusters.
245
+
246
+ :return: List of DocumentDB cluster information
247
+ :rtype: List[Dict[str, Any]]
248
+ """
249
+ clusters = []
250
+ try:
251
+ docdb = self._get_client("docdb")
252
+ paginator = docdb.get_paginator("describe_db_clusters")
253
+
254
+ for page in paginator.paginate():
255
+ for cluster in page.get("DBClusters", []):
256
+ cluster_arn = cluster.get("DBClusterArn", "")
257
+
258
+ if not self._matches_account(cluster_arn):
259
+ continue
260
+
261
+ if not self._matches_tags(cluster.get("TagList", [])):
262
+ continue
263
+
264
+ clusters.append(
265
+ {
266
+ "Region": self.region,
267
+ "DBClusterIdentifier": cluster.get("DBClusterIdentifier"),
268
+ "DBClusterArn": cluster_arn,
269
+ "Engine": cluster.get("Engine"),
270
+ "EngineVersion": cluster.get("EngineVersion"),
271
+ "Status": cluster.get("Status"),
272
+ "Endpoint": cluster.get("Endpoint"),
273
+ "ReaderEndpoint": cluster.get("ReaderEndpoint"),
274
+ "MultiAZ": cluster.get("MultiAZ"),
275
+ "StorageEncrypted": cluster.get("StorageEncrypted"),
276
+ "KmsKeyId": cluster.get("KmsKeyId"),
277
+ "Tags": cluster.get("TagList", []),
278
+ }
279
+ )
280
+ except Exception as e:
281
+ self._handle_error(e, "DocumentDB clusters")
282
+ return clusters
283
+
284
+ def get_redshift_clusters(self) -> List[Dict[str, Any]]:
285
+ """
286
+ Get information about Redshift data warehouse clusters.
287
+
288
+ :return: List of Redshift cluster information
289
+ :rtype: List[Dict[str, Any]]
290
+ """
291
+ clusters = []
292
+ try:
293
+ redshift = self._get_client("redshift")
294
+ paginator = redshift.get_paginator("describe_clusters")
295
+
296
+ for page in paginator.paginate():
297
+ for cluster in page.get("Clusters", []):
298
+ cluster_arn = (
299
+ f"arn:aws:redshift:{self.region}:{cluster.get('ClusterNamespaceArn', '').split(':')[4]}:"
300
+ f"cluster:{cluster.get('ClusterIdentifier')}"
301
+ )
302
+
303
+ if not self._matches_account(cluster_arn):
304
+ continue
305
+
306
+ if not self._matches_tags(cluster.get("Tags", [])):
307
+ continue
308
+
309
+ clusters.append(
310
+ {
311
+ "Region": self.region,
312
+ "ClusterIdentifier": cluster.get("ClusterIdentifier"),
313
+ "ClusterStatus": cluster.get("ClusterStatus"),
314
+ "NodeType": cluster.get("NodeType"),
315
+ "NumberOfNodes": cluster.get("NumberOfNodes"),
316
+ "DBName": cluster.get("DBName"),
317
+ "Endpoint": cluster.get("Endpoint"),
318
+ "ClusterCreateTime": cluster.get("ClusterCreateTime"),
319
+ "Encrypted": cluster.get("Encrypted"),
320
+ "KmsKeyId": cluster.get("KmsKeyId"),
321
+ "VpcId": cluster.get("VpcId"),
322
+ "PubliclyAccessible": cluster.get("PubliclyAccessible"),
323
+ "Tags": cluster.get("Tags", []),
324
+ }
325
+ )
326
+ except Exception as e:
327
+ self._handle_error(e, "Redshift clusters")
328
+ return clusters
329
+
330
+ def get_keyspaces(self) -> List[Dict[str, Any]]:
331
+ """
332
+ Get information about Keyspaces (Apache Cassandra) keyspaces and tables.
333
+
334
+ :return: List of Keyspaces keyspace information
335
+ :rtype: List[Dict[str, Any]]
336
+ """
337
+ keyspaces = []
338
+ try:
339
+ keyspaces_client = self._get_client("keyspaces")
340
+ paginator = keyspaces_client.get_paginator("list_keyspaces")
341
+
342
+ for page in paginator.paginate():
343
+ for keyspace in page.get("keyspaces", []):
344
+ keyspace_name = keyspace.get("keyspaceName")
345
+ keyspace_arn = keyspace.get("resourceArn", "")
346
+
347
+ if not self._matches_account(keyspace_arn):
348
+ continue
349
+
350
+ try:
351
+ tags_response = keyspaces_client.list_tags_for_resource(resourceArn=keyspace_arn)
352
+ keyspace_tags = tags_response.get("tags", [])
353
+
354
+ if not self._matches_tags(keyspace_tags):
355
+ continue
356
+
357
+ keyspaces.append(
358
+ {
359
+ "Region": self.region,
360
+ "KeyspaceName": keyspace_name,
361
+ "KeyspaceArn": keyspace_arn,
362
+ "Tags": keyspace_tags,
363
+ }
364
+ )
365
+ except Exception as tag_error:
366
+ self._handle_error(tag_error, f"Keyspaces tags for {keyspace_name}")
367
+ continue
368
+
369
+ except Exception as e:
370
+ self._handle_error(e, "Keyspaces")
371
+ return keyspaces
372
+
373
+ def _process_timestream_database(self, timestream: Any, database: Dict[str, Any]) -> Optional[Dict[str, Any]]:
374
+ """
375
+ Process a single Timestream database.
376
+
377
+ :param timestream: Timestream client
378
+ :param dict database: Database information
379
+ :return: Database information or None if filtered out
380
+ :rtype: Optional[Dict[str, Any]]
381
+ """
382
+ database_arn = database.get("Arn", "")
383
+
384
+ if not self._matches_account(database_arn):
385
+ return None
386
+
387
+ try:
388
+ tags_response = timestream.list_tags_for_resource(ResourceARN=database_arn)
389
+ db_tags = tags_response.get("Tags", [])
390
+
391
+ if not self._matches_tags(db_tags):
392
+ return None
393
+
394
+ return {
395
+ "Region": self.region,
396
+ "DatabaseName": database.get("DatabaseName"),
397
+ "DatabaseArn": database_arn,
398
+ "TableCount": database.get("TableCount"),
399
+ "KmsKeyId": database.get("KmsKeyId"),
400
+ "CreationTime": database.get("CreationTime"),
401
+ "Tags": db_tags,
402
+ }
403
+ except Exception as tag_error:
404
+ self._handle_error(tag_error, f"Timestream database tags for {database_arn}")
405
+ return None
406
+
407
+ def get_timestream_databases(self) -> List[Dict[str, Any]]:
408
+ """
409
+ Get information about Timestream databases.
410
+
411
+ :return: List of Timestream database information
412
+ :rtype: List[Dict[str, Any]]
413
+ """
414
+ databases = []
415
+ try:
416
+ timestream = self._get_client("timestream-write")
417
+ next_token = None
418
+
419
+ while True:
420
+ if next_token:
421
+ response = timestream.list_databases(NextToken=next_token)
422
+ else:
423
+ response = timestream.list_databases()
424
+
425
+ for database in response.get("Databases", []):
426
+ db_info = self._process_timestream_database(timestream, database)
427
+ if db_info:
428
+ databases.append(db_info)
429
+
430
+ next_token = response.get("NextToken")
431
+ if not next_token:
432
+ break
433
+
434
+ except Exception as e:
435
+ self._handle_error(e, "Timestream databases")
436
+ return databases
437
+
438
+ def _process_qldb_ledger(self, qldb: Any, ledger_name: str) -> Optional[Dict[str, Any]]:
439
+ """
440
+ Process a single QLDB ledger.
441
+
442
+ :param qldb: QLDB client
443
+ :param str ledger_name: Ledger name
444
+ :return: Ledger information or None if filtered out
445
+ :rtype: Optional[Dict[str, Any]]
446
+ """
447
+ try:
448
+ ledger_details = qldb.describe_ledger(Name=ledger_name)
449
+ ledger_arn = ledger_details.get("Arn", "")
450
+
451
+ if not self._matches_account(ledger_arn):
452
+ return None
453
+
454
+ tags_response = qldb.list_tags_for_resource(ResourceArn=ledger_arn)
455
+ ledger_tags = tags_response.get("Tags", {})
456
+
457
+ if not self._matches_tags(ledger_tags):
458
+ return None
459
+
460
+ return {
461
+ "Region": self.region,
462
+ "Name": ledger_name,
463
+ "Arn": ledger_arn,
464
+ "State": ledger_details.get("State"),
465
+ "CreationDateTime": ledger_details.get("CreationDateTime"),
466
+ "PermissionsMode": ledger_details.get("PermissionsMode"),
467
+ "DeletionProtection": ledger_details.get("DeletionProtection"),
468
+ "Tags": ledger_tags,
469
+ }
470
+ except Exception as ledger_error:
471
+ self._handle_error(ledger_error, f"QLDB ledger details for {ledger_name}")
472
+ return None
473
+
474
+ def get_qldb_ledgers(self) -> List[Dict[str, Any]]:
475
+ """
476
+ Get information about QLDB (Quantum Ledger Database) ledgers.
477
+
478
+ :return: List of QLDB ledger information
479
+ :rtype: List[Dict[str, Any]]
480
+ """
481
+ ledgers = []
482
+ try:
483
+ qldb = self._get_client("qldb")
484
+ next_token = None
485
+
486
+ while True:
487
+ if next_token:
488
+ response = qldb.list_ledgers(NextToken=next_token)
489
+ else:
490
+ response = qldb.list_ledgers()
491
+
492
+ for ledger in response.get("Ledgers", []):
493
+ ledger_name = ledger.get("Name")
494
+ ledger_info = self._process_qldb_ledger(qldb, ledger_name)
495
+ if ledger_info:
496
+ ledgers.append(ledger_info)
497
+
498
+ next_token = response.get("NextToken")
499
+ if not next_token:
500
+ break
501
+
502
+ except Exception as e:
503
+ self._handle_error(e, "QLDB ledgers")
504
+ return ledgers
505
+
94
506
  def collect(self) -> Dict[str, Any]:
95
507
  """
96
- Collect all database resources.
508
+ Collect database resources based on enabled_services configuration.
97
509
 
98
- :return: Dictionary containing all database resource information
510
+ :return: Dictionary containing enabled database resource information
99
511
  :rtype: Dict[str, Any]
100
512
  """
101
- return {"RDSInstances": self.get_rds_instances(), "DynamoDBTables": self.get_dynamodb_tables()}
513
+ result = {}
514
+
515
+ # RDS Instances
516
+ if self.enabled_services.get("rds", True):
517
+ result["RDSInstances"] = self.get_rds_instances()
518
+
519
+ # DynamoDB Tables
520
+ if self.enabled_services.get("dynamodb", True):
521
+ result["DynamoDBTables"] = self.get_dynamodb_tables()
522
+
523
+ # ElastiCache Clusters
524
+ if self.enabled_services.get("elasticache", True):
525
+ result["ElastiCacheClusters"] = self.get_elasticache_clusters()
526
+
527
+ # Neptune Clusters
528
+ if self.enabled_services.get("neptune", True):
529
+ result["NeptuneClusters"] = self.get_neptune_clusters()
530
+
531
+ # DocumentDB Clusters
532
+ if self.enabled_services.get("docdb", True):
533
+ result["DocumentDBClusters"] = self.get_docdb_clusters()
534
+
535
+ # Redshift Clusters
536
+ if self.enabled_services.get("redshift", True):
537
+ result["RedshiftClusters"] = self.get_redshift_clusters()
538
+
539
+ # Keyspaces
540
+ if self.enabled_services.get("keyspaces", True):
541
+ result["Keyspaces"] = self.get_keyspaces()
542
+
543
+ # Timestream Databases
544
+ if self.enabled_services.get("timestream", True):
545
+ result["TimestreamDatabases"] = self.get_timestream_databases()
546
+
547
+ # QLDB Ledgers
548
+ if self.enabled_services.get("qldb", True):
549
+ result["QLDBLedgers"] = self.get_qldb_ledgers()
550
+
551
+ return result