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
@@ -0,0 +1,447 @@
1
+ """AWS KMS resource collection."""
2
+
3
+ import logging
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ from botocore.exceptions import ClientError
7
+
8
+ from regscale.integrations.commercial.aws.inventory.base import BaseCollector
9
+
10
+ logger = logging.getLogger("regscale")
11
+
12
+
13
+ class KMSCollector(BaseCollector):
14
+ """Collector for AWS KMS resources."""
15
+
16
+ def __init__(
17
+ self, session: Any, region: str, account_id: Optional[str] = None, tags: Optional[Dict[str, str]] = None
18
+ ):
19
+ """
20
+ Initialize KMS collector.
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 tags to filter resources (key-value pairs)
26
+ """
27
+ super().__init__(session, region)
28
+ self.account_id = account_id
29
+ self.tags = tags or {}
30
+
31
+ def collect(self) -> Dict[str, Any]:
32
+ """
33
+ Collect AWS KMS resources.
34
+
35
+ :return: Dictionary containing KMS key information
36
+ :rtype: Dict[str, Any]
37
+ """
38
+ result = {"Keys": [], "Aliases": []}
39
+
40
+ try:
41
+ client = self._get_client("kms")
42
+
43
+ # Get all keys
44
+ keys = self._list_keys(client)
45
+ result["Keys"] = keys
46
+
47
+ # Get all aliases
48
+ aliases = self._list_aliases(client)
49
+ result["Aliases"] = aliases
50
+
51
+ logger.info(f"Collected {len(keys)} KMS key(s), {len(aliases)} alias(es) from {self.region}")
52
+
53
+ except ClientError as e:
54
+ self._handle_error(e, "KMS keys")
55
+ except Exception as e:
56
+ logger.error(f"Unexpected error collecting KMS resources: {e}", exc_info=True)
57
+
58
+ return result
59
+
60
+ def _list_keys(self, client: Any) -> List[Dict[str, Any]]:
61
+ """
62
+ List KMS keys with enhanced details.
63
+
64
+ :param client: KMS client
65
+ :return: List of key information
66
+ :rtype: List[Dict[str, Any]]
67
+ """
68
+ keys = []
69
+ try:
70
+ paginator = client.get_paginator("list_keys")
71
+
72
+ for page in paginator.paginate():
73
+ for key in page.get("Keys", []):
74
+ key_id = key["KeyId"]
75
+ processed_key = self._process_key(client, key_id)
76
+ if processed_key:
77
+ keys.append(processed_key)
78
+
79
+ except ClientError as e:
80
+ self._handle_list_keys_error(e)
81
+
82
+ return keys
83
+
84
+ def _process_key(self, client: Any, key_id: str) -> Optional[Dict[str, Any]]:
85
+ """
86
+ Process a single KMS key and return its details if it passes filters.
87
+
88
+ :param client: KMS client
89
+ :param str key_id: Key ID to process
90
+ :return: Key information if it passes filters, None otherwise
91
+ :rtype: Optional[Dict[str, Any]]
92
+ """
93
+ try:
94
+ key_info = self._describe_key(client, key_id)
95
+ if not key_info:
96
+ return None
97
+
98
+ if not self._passes_account_filter(key_info):
99
+ return None
100
+
101
+ self._enrich_key_info(client, key_id, key_info)
102
+
103
+ if not self._passes_tag_filter(client, key_id):
104
+ return None
105
+
106
+ return key_info
107
+
108
+ except ClientError as e:
109
+ self._handle_key_processing_error(e, key_id)
110
+ return None
111
+
112
+ def _passes_account_filter(self, key_info: Dict[str, Any]) -> bool:
113
+ """
114
+ Check if key passes account ID filter.
115
+
116
+ :param dict key_info: Key information dictionary
117
+ :return: True if key passes account filter
118
+ :rtype: bool
119
+ """
120
+ if not self.account_id:
121
+ return True
122
+ return self._matches_account_id(key_info.get("Arn", ""))
123
+
124
+ def _enrich_key_info(self, client: Any, key_id: str, key_info: Dict[str, Any]) -> None:
125
+ """
126
+ Enrich key information with additional details.
127
+
128
+ :param client: KMS client
129
+ :param str key_id: Key ID
130
+ :param dict key_info: Key information dictionary to enrich
131
+ """
132
+ key_info["Region"] = self.region
133
+ key_info["RotationEnabled"] = self._get_key_rotation_status(client, key_id)
134
+ key_info["Policy"] = self._get_key_policy(client, key_id)
135
+
136
+ grants = self._list_grants(client, key_id)
137
+ key_info["GrantCount"] = len(grants)
138
+
139
+ tags = self._list_resource_tags(client, key_id)
140
+ key_info["Tags"] = tags
141
+
142
+ def _passes_tag_filter(self, client: Any, key_id: str) -> bool:
143
+ """
144
+ Check if key passes tag filter.
145
+
146
+ :param client: KMS client
147
+ :param str key_id: Key ID
148
+ :return: True if key passes tag filter
149
+ :rtype: bool
150
+ """
151
+ if not self.tags:
152
+ return True
153
+
154
+ key_tags = self._get_key_tags(client, key_id)
155
+ if not self._matches_tags(key_tags):
156
+ logger.debug(f"Skipping key {key_id} - does not match tag filters")
157
+ return False
158
+ return True
159
+
160
+ def _handle_list_keys_error(self, error: ClientError) -> None:
161
+ """
162
+ Handle errors from list_keys operation.
163
+
164
+ :param error: Client error exception
165
+ """
166
+ if error.response["Error"]["Code"] == "AccessDeniedException":
167
+ logger.warning(f"Access denied to list KMS keys in {self.region}")
168
+ else:
169
+ logger.error(f"Error listing KMS keys: {error}")
170
+
171
+ def _handle_key_processing_error(self, error: ClientError, key_id: str) -> None:
172
+ """
173
+ Handle errors from processing individual keys.
174
+
175
+ :param error: Client error exception
176
+ :param str key_id: Key ID being processed
177
+ """
178
+ if error.response["Error"]["Code"] not in ["NotFoundException", "AccessDeniedException"]:
179
+ logger.error(f"Error getting details for key {key_id}: {error}")
180
+
181
+ def _describe_key(self, client: Any, key_id: str) -> Optional[Dict[str, Any]]:
182
+ """
183
+ Get key metadata.
184
+
185
+ :param client: KMS client
186
+ :param str key_id: Key ID
187
+ :return: Key metadata
188
+ :rtype: Optional[Dict[str, Any]]
189
+ """
190
+ try:
191
+ response = client.describe_key(KeyId=key_id)
192
+ key_metadata = response["KeyMetadata"]
193
+
194
+ return {
195
+ "KeyId": key_metadata.get("KeyId"),
196
+ "Arn": key_metadata.get("Arn"),
197
+ "Description": key_metadata.get("Description"),
198
+ "Enabled": key_metadata.get("Enabled"),
199
+ "KeyState": key_metadata.get("KeyState"),
200
+ "CreationDate": str(key_metadata.get("CreationDate")),
201
+ "DeletionDate": str(key_metadata.get("DeletionDate")) if key_metadata.get("DeletionDate") else None,
202
+ "Origin": key_metadata.get("Origin"),
203
+ "KeyManager": key_metadata.get("KeyManager"),
204
+ "KeySpec": key_metadata.get("KeySpec"),
205
+ "KeyUsage": key_metadata.get("KeyUsage"),
206
+ "MultiRegion": key_metadata.get("MultiRegion", False),
207
+ "MultiRegionConfiguration": key_metadata.get("MultiRegionConfiguration"),
208
+ }
209
+ except ClientError as e:
210
+ if e.response["Error"]["Code"] not in ["NotFoundException", "AccessDeniedException"]:
211
+ logger.error(f"Error describing key {key_id}: {e}")
212
+ return None
213
+
214
+ def _get_key_rotation_status(self, client: Any, key_id: str) -> bool:
215
+ """
216
+ Get key rotation status.
217
+
218
+ :param client: KMS client
219
+ :param str key_id: Key ID
220
+ :return: Rotation enabled status
221
+ :rtype: bool
222
+ """
223
+ try:
224
+ response = client.get_key_rotation_status(KeyId=key_id)
225
+ return response.get("KeyRotationEnabled", False)
226
+ except ClientError as e:
227
+ if e.response["Error"]["Code"] in [
228
+ "NotFoundException",
229
+ "AccessDeniedException",
230
+ "UnsupportedOperationException",
231
+ ]:
232
+ return False
233
+ logger.debug(f"Error getting rotation status for key {key_id}: {e}")
234
+ return False
235
+
236
+ def _get_key_policy(self, client: Any, key_id: str) -> Optional[str]:
237
+ """
238
+ Get key policy.
239
+
240
+ :param client: KMS client
241
+ :param str key_id: Key ID
242
+ :return: Key policy as JSON string
243
+ :rtype: Optional[str]
244
+ """
245
+ try:
246
+ response = client.get_key_policy(KeyId=key_id, PolicyName="default")
247
+ return response.get("Policy")
248
+ except ClientError as e:
249
+ if e.response["Error"]["Code"] not in ["NotFoundException", "AccessDeniedException"]:
250
+ logger.debug(f"Error getting policy for key {key_id}: {e}")
251
+ return None
252
+
253
+ def _list_grants(self, client: Any, key_id: str) -> List[Dict[str, Any]]:
254
+ """
255
+ List grants for a key.
256
+
257
+ :param client: KMS client
258
+ :param str key_id: Key ID
259
+ :return: List of grants
260
+ :rtype: List[Dict[str, Any]]
261
+ """
262
+ grants = []
263
+ try:
264
+ paginator = client.get_paginator("list_grants")
265
+
266
+ for page in paginator.paginate(KeyId=key_id):
267
+ grants.extend(page.get("Grants", []))
268
+
269
+ except ClientError as e:
270
+ if e.response["Error"]["Code"] not in ["NotFoundException", "AccessDeniedException"]:
271
+ logger.debug(f"Error listing grants for key {key_id}: {e}")
272
+
273
+ return grants
274
+
275
+ def _list_resource_tags(self, client: Any, key_id: str) -> List[Dict[str, str]]:
276
+ """
277
+ List tags for a key.
278
+
279
+ :param client: KMS client
280
+ :param str key_id: Key ID
281
+ :return: List of tags
282
+ :rtype: List[Dict[str, str]]
283
+ """
284
+ try:
285
+ response = client.list_resource_tags(KeyId=key_id)
286
+ return response.get("Tags", [])
287
+ except ClientError as e:
288
+ if e.response["Error"]["Code"] not in ["NotFoundException", "AccessDeniedException"]:
289
+ logger.debug(f"Error listing tags for key {key_id}: {e}")
290
+ return []
291
+
292
+ def _list_aliases(self, client: Any) -> List[Dict[str, Any]]:
293
+ """
294
+ List KMS aliases.
295
+
296
+ :param client: KMS client
297
+ :return: List of aliases
298
+ :rtype: List[Dict[str, Any]]
299
+ """
300
+ aliases = []
301
+ try:
302
+ paginator = client.get_paginator("list_aliases")
303
+
304
+ for page in paginator.paginate():
305
+ for alias in page.get("Aliases", []):
306
+ processed_alias = self._process_alias(client, alias)
307
+ if processed_alias:
308
+ aliases.append(processed_alias)
309
+
310
+ except ClientError as e:
311
+ self._handle_list_aliases_error(e)
312
+
313
+ return aliases
314
+
315
+ def _process_alias(self, client: Any, alias: Dict[str, Any]) -> Optional[Dict[str, Any]]:
316
+ """
317
+ Process a single KMS alias and return its details if it passes filters.
318
+
319
+ :param client: KMS client
320
+ :param dict alias: Alias information from AWS API
321
+ :return: Alias dictionary if it passes filters, None otherwise
322
+ :rtype: Optional[Dict[str, Any]]
323
+ """
324
+ if not self._alias_passes_filters(client, alias):
325
+ return None
326
+
327
+ return {
328
+ "Region": self.region,
329
+ "AliasName": alias.get("AliasName"),
330
+ "AliasArn": alias.get("AliasArn"),
331
+ "TargetKeyId": alias.get("TargetKeyId"),
332
+ }
333
+
334
+ def _alias_passes_filters(self, client: Any, alias: Dict[str, Any]) -> bool:
335
+ """
336
+ Check if alias passes account filtering rules.
337
+
338
+ :param client: KMS client
339
+ :param dict alias: Alias information
340
+ :return: True if alias passes filters
341
+ :rtype: bool
342
+ """
343
+ if not self.account_id:
344
+ return True
345
+
346
+ if self._is_aws_managed_alias(alias):
347
+ return False
348
+
349
+ return self._alias_target_matches_account(client, alias)
350
+
351
+ def _is_aws_managed_alias(self, alias: Dict[str, Any]) -> bool:
352
+ """
353
+ Check if alias is AWS-managed.
354
+
355
+ :param dict alias: Alias information
356
+ :return: True if alias is AWS-managed
357
+ :rtype: bool
358
+ """
359
+ alias_name = alias.get("AliasName", "")
360
+ return alias_name.startswith("alias/aws/")
361
+
362
+ def _alias_target_matches_account(self, client: Any, alias: Dict[str, Any]) -> bool:
363
+ """
364
+ Check if alias target key matches the account filter.
365
+
366
+ :param client: KMS client
367
+ :param dict alias: Alias information
368
+ :return: True if target key matches account or no target key exists
369
+ :rtype: bool
370
+ """
371
+ target_key_id = alias.get("TargetKeyId")
372
+ if not target_key_id:
373
+ return True
374
+
375
+ key_info = self._describe_key(client, target_key_id)
376
+ if not key_info:
377
+ return True
378
+
379
+ return self._matches_account_id(key_info.get("Arn", ""))
380
+
381
+ def _handle_list_aliases_error(self, error: ClientError) -> None:
382
+ """
383
+ Handle errors from list_aliases operation.
384
+
385
+ :param error: Client error exception
386
+ """
387
+ if error.response["Error"]["Code"] == "AccessDeniedException":
388
+ logger.warning(f"Access denied to list KMS aliases in {self.region}")
389
+ else:
390
+ logger.error(f"Error listing KMS aliases: {error}")
391
+
392
+ def _matches_account_id(self, arn: str) -> bool:
393
+ """
394
+ Check if ARN matches the specified account ID.
395
+
396
+ :param str arn: ARN to check
397
+ :return: True if matches or no account_id filter specified
398
+ :rtype: bool
399
+ """
400
+ if not self.account_id:
401
+ return True
402
+
403
+ # ARN format: arn:aws:kms:region:account-id:key/key-id
404
+ try:
405
+ arn_parts = arn.split(":")
406
+ if len(arn_parts) >= 5:
407
+ key_account_id = arn_parts[4]
408
+ return key_account_id == self.account_id
409
+ except (IndexError, AttributeError):
410
+ logger.warning(f"Could not parse account ID from KMS key ARN: {arn}")
411
+
412
+ return False
413
+
414
+ def _get_key_tags(self, client: Any, key_id: str) -> Dict[str, str]:
415
+ """
416
+ Get tags for a KMS key.
417
+
418
+ :param client: KMS client
419
+ :param str key_id: Key ID
420
+ :return: Dictionary of tags (Key -> Value)
421
+ :rtype: Dict[str, str]
422
+ """
423
+ try:
424
+ response = client.list_resource_tags(KeyId=key_id)
425
+ tags_list = response.get("Tags", [])
426
+ return {tag["TagKey"]: tag["TagValue"] for tag in tags_list}
427
+ except ClientError as e:
428
+ logger.debug(f"Error getting tags for key {key_id}: {e}")
429
+ return {}
430
+
431
+ def _matches_tags(self, resource_tags: Dict[str, str]) -> bool:
432
+ """
433
+ Check if resource tags match the specified filter tags.
434
+
435
+ :param dict resource_tags: Tags on the resource
436
+ :return: True if all filter tags match
437
+ :rtype: bool
438
+ """
439
+ if not self.tags:
440
+ return True
441
+
442
+ # All filter tags must match
443
+ for key, value in self.tags.items():
444
+ if resource_tags.get(key) != value:
445
+ return False
446
+
447
+ return True