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,464 @@
1
+ """AWS Config 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 ConfigCollector(BaseCollector):
14
+ """Collector for AWS Config 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 Config 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 tags to filter resources (key-value pairs)
26
+ """
27
+ super().__init__(session, region, account_id, tags)
28
+
29
+ def collect(self) -> Dict[str, Any]:
30
+ """
31
+ Collect AWS Config resources.
32
+
33
+ :return: Dictionary containing Config recorders, rules, and compliance information
34
+ :rtype: Dict[str, Any]
35
+ """
36
+ result = {
37
+ "ConfigurationRecorders": [],
38
+ "RecorderStatuses": [],
39
+ "DeliveryChannels": [],
40
+ "ConfigRules": [],
41
+ "ComplianceSummary": [],
42
+ }
43
+
44
+ try:
45
+ client = self._get_client("config")
46
+
47
+ # Collect basic Config resources
48
+ result["ConfigurationRecorders"] = self._describe_configuration_recorders(client)
49
+ result["RecorderStatuses"] = self._describe_configuration_recorder_status(client)
50
+ result["DeliveryChannels"] = self._describe_delivery_channels(client)
51
+
52
+ # Get and filter config rules
53
+ config_rules = self._describe_config_rules(client)
54
+ filtered_rules = self._filter_config_rules(client, config_rules)
55
+ result["ConfigRules"] = filtered_rules
56
+
57
+ # Get compliance information
58
+ result["ComplianceSummary"] = self._collect_compliance_summary(client, filtered_rules)
59
+
60
+ logger.info(
61
+ f"Collected {len(result['ConfigurationRecorders'])} Config recorder(s), "
62
+ f"{len(filtered_rules)} rule(s) from {self.region}"
63
+ )
64
+
65
+ except ClientError as e:
66
+ self._handle_error(e, "AWS Config resources")
67
+ except Exception as e:
68
+ logger.error(f"Unexpected error collecting AWS Config resources: {e}", exc_info=True)
69
+
70
+ return result
71
+
72
+ def _filter_config_rules(self, client: Any, config_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
73
+ """
74
+ Filter config rules by account ID and tags if specified.
75
+
76
+ :param client: Config client
77
+ :param List[Dict[str, Any]] config_rules: List of config rules to filter
78
+ :return: Filtered list of config rules
79
+ :rtype: List[Dict[str, Any]]
80
+ """
81
+ filtered_rules = []
82
+ for rule in config_rules:
83
+ if self._should_include_rule(client, rule):
84
+ filtered_rules.append(rule)
85
+ return filtered_rules
86
+
87
+ def _should_include_rule(self, client: Any, rule: Dict[str, Any]) -> bool:
88
+ """
89
+ Determine if a config rule should be included based on filters.
90
+
91
+ :param client: Config client
92
+ :param Dict[str, Any] rule: Config rule to check
93
+ :return: True if rule should be included, False otherwise
94
+ :rtype: bool
95
+ """
96
+ rule_arn = rule.get("ConfigRuleArn", "")
97
+
98
+ # Filter by account ID if specified using BaseCollector method
99
+ if not self._matches_account(rule_arn):
100
+ logger.debug(f"Skipping rule {rule_arn} - does not match account ID {self.account_id}")
101
+ return False
102
+
103
+ # Get tags for filtering using BaseCollector method
104
+ if self.tags:
105
+ rule_tags = self._get_rule_tags(client, rule_arn)
106
+ if not self._matches_tags(rule_tags):
107
+ logger.debug(f"Skipping rule {rule_arn} - does not match tag filters")
108
+ return False
109
+ rule["Tags"] = rule_tags
110
+
111
+ return True
112
+
113
+ def _collect_compliance_summary(self, client: Any, filtered_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
114
+ """
115
+ Collect compliance information for filtered rules.
116
+
117
+ :param client: Config client
118
+ :param List[Dict[str, Any]] filtered_rules: List of filtered config rules
119
+ :return: List of compliance summaries
120
+ :rtype: List[Dict[str, Any]]
121
+ """
122
+ compliance_summary = []
123
+ for rule in filtered_rules:
124
+ rule_name = rule.get("ConfigRuleName")
125
+ if rule_name:
126
+ compliance = self._describe_compliance_by_config_rule(client, rule_name)
127
+ if compliance:
128
+ compliance_summary.append(compliance)
129
+ return compliance_summary
130
+
131
+ def _describe_configuration_recorders(self, client: Any) -> List[Dict[str, Any]]:
132
+ """
133
+ Describe configuration recorders.
134
+
135
+ :param client: Config client
136
+ :return: List of configuration recorders
137
+ :rtype: List[Dict[str, Any]]
138
+ """
139
+ try:
140
+ response = client.describe_configuration_recorders()
141
+ recorders = response.get("ConfigurationRecorders", [])
142
+
143
+ # Add region information
144
+ for recorder in recorders:
145
+ recorder["Region"] = self.region
146
+
147
+ return recorders
148
+ except ClientError as e:
149
+ if e.response["Error"]["Code"] == "AccessDeniedException":
150
+ logger.warning(f"Access denied to describe configuration recorders in {self.region}")
151
+ return []
152
+ raise
153
+
154
+ def _describe_configuration_recorder_status(self, client: Any) -> List[Dict[str, Any]]:
155
+ """
156
+ Describe configuration recorder status.
157
+
158
+ :param client: Config client
159
+ :return: List of recorder statuses
160
+ :rtype: List[Dict[str, Any]]
161
+ """
162
+ try:
163
+ response = client.describe_configuration_recorder_status()
164
+ statuses = response.get("ConfigurationRecordersStatus", [])
165
+
166
+ # Add region information
167
+ for status in statuses:
168
+ status["Region"] = self.region
169
+
170
+ return statuses
171
+ except ClientError as e:
172
+ if e.response["Error"]["Code"] == "AccessDeniedException":
173
+ logger.warning(f"Access denied to describe configuration recorder status in {self.region}")
174
+ return []
175
+ logger.error(f"Error describing configuration recorder status: {e}")
176
+ return []
177
+
178
+ def _describe_delivery_channels(self, client: Any) -> List[Dict[str, Any]]:
179
+ """
180
+ Describe delivery channels.
181
+
182
+ :param client: Config client
183
+ :return: List of delivery channels
184
+ :rtype: List[Dict[str, Any]]
185
+ """
186
+ try:
187
+ response = client.describe_delivery_channels()
188
+ channels = response.get("DeliveryChannels", [])
189
+
190
+ # Add region information
191
+ for channel in channels:
192
+ channel["Region"] = self.region
193
+
194
+ return channels
195
+ except ClientError as e:
196
+ if e.response["Error"]["Code"] == "AccessDeniedException":
197
+ logger.warning(f"Access denied to describe delivery channels in {self.region}")
198
+ return []
199
+ logger.error(f"Error describing delivery channels: {e}")
200
+ return []
201
+
202
+ def _describe_config_rules(self, client: Any) -> List[Dict[str, Any]]:
203
+ """
204
+ Describe AWS Config rules with pagination support.
205
+
206
+ :param client: Config client
207
+ :return: List of config rules
208
+ :rtype: List[Dict[str, Any]]
209
+ """
210
+ rules = []
211
+ next_token = None
212
+
213
+ try:
214
+ while True:
215
+ params = {}
216
+ if next_token:
217
+ params["NextToken"] = next_token
218
+
219
+ response = client.describe_config_rules(**params)
220
+ rules.extend(response.get("ConfigRules", []))
221
+
222
+ next_token = response.get("NextToken")
223
+ if not next_token:
224
+ break
225
+
226
+ # Add region information
227
+ for rule in rules:
228
+ rule["Region"] = self.region
229
+
230
+ except ClientError as e:
231
+ if e.response["Error"]["Code"] == "AccessDeniedException":
232
+ logger.warning(f"Access denied to describe config rules in {self.region}")
233
+ else:
234
+ logger.error(f"Error describing config rules: {e}")
235
+
236
+ return rules
237
+
238
+ def _describe_compliance_by_config_rule(self, client: Any, rule_name: str) -> Optional[Dict[str, Any]]:
239
+ """
240
+ Get compliance information for a specific config rule.
241
+
242
+ :param client: Config client
243
+ :param str rule_name: Name of the config rule
244
+ :return: Compliance information or None
245
+ :rtype: Optional[Dict[str, Any]]
246
+ """
247
+ try:
248
+ response = client.describe_compliance_by_config_rule(ConfigRuleNames=[rule_name])
249
+ compliance_by_rules = response.get("ComplianceByConfigRules", [])
250
+
251
+ if compliance_by_rules:
252
+ compliance = compliance_by_rules[0]
253
+ compliance["Region"] = self.region
254
+ return compliance
255
+
256
+ return None
257
+ except ClientError as e:
258
+ if e.response["Error"]["Code"] != "AccessDeniedException":
259
+ logger.error(f"Error getting compliance for rule {rule_name}: {e}")
260
+ return None
261
+
262
+ def get_compliance_details(
263
+ self, rule_name: str, compliance_types: Optional[List[str]] = None
264
+ ) -> List[Dict[str, Any]]:
265
+ """
266
+ Get detailed compliance information for a config rule.
267
+
268
+ :param str rule_name: Name of the config rule
269
+ :param List[str] compliance_types: Optional list of compliance types to filter
270
+ :return: List of compliance details
271
+ :rtype: List[Dict[str, Any]]
272
+ """
273
+ details = []
274
+ next_token = None
275
+
276
+ try:
277
+ client = self._get_client("config")
278
+
279
+ while True:
280
+ params = {"ConfigRuleName": rule_name}
281
+
282
+ if compliance_types:
283
+ params["ComplianceTypes"] = compliance_types
284
+
285
+ if next_token:
286
+ params["NextToken"] = next_token
287
+
288
+ response = client.get_compliance_details_by_config_rule(**params)
289
+ evaluation_results = response.get("EvaluationResults", [])
290
+
291
+ for result in evaluation_results:
292
+ result["Region"] = self.region
293
+
294
+ details.extend(evaluation_results)
295
+
296
+ next_token = response.get("NextToken")
297
+ if not next_token:
298
+ break
299
+
300
+ except ClientError as e:
301
+ self._handle_error(e, f"compliance details for rule {rule_name}")
302
+
303
+ return details
304
+
305
+ def _get_rule_tags(self, client: Any, rule_arn: str) -> Dict[str, str]:
306
+ """
307
+ Get tags for an AWS Config rule.
308
+
309
+ :param client: Config client
310
+ :param str rule_arn: Config rule ARN
311
+ :return: Dictionary of tags (TagKey -> TagValue)
312
+ :rtype: Dict[str, str]
313
+ """
314
+ try:
315
+ response = client.list_tags_for_resource(ResourceArn=rule_arn)
316
+ tags_list = response.get("Tags", [])
317
+ return {tag["Key"]: tag["Value"] for tag in tags_list}
318
+ except ClientError as e:
319
+ logger.debug(f"Error getting tags for config rule {rule_arn}: {e}")
320
+ return {}
321
+
322
+ def get_conformance_packs(self) -> List[Dict[str, Any]]:
323
+ """
324
+ Get deployed conformance packs.
325
+
326
+ :return: List of conformance packs
327
+ :rtype: List[Dict[str, Any]]
328
+ """
329
+ packs = []
330
+ next_token = None
331
+
332
+ try:
333
+ client = self._get_client("config")
334
+
335
+ while True:
336
+ params = {}
337
+ if next_token:
338
+ params["NextToken"] = next_token
339
+
340
+ response = client.describe_conformance_packs(**params)
341
+ pack_details = response.get("ConformancePackDetails", [])
342
+
343
+ for pack in pack_details:
344
+ pack["Region"] = self.region
345
+
346
+ packs.extend(pack_details)
347
+
348
+ next_token = response.get("NextToken")
349
+ if not next_token:
350
+ break
351
+
352
+ except ClientError as e:
353
+ if e.response["Error"]["Code"] == "AccessDeniedException":
354
+ logger.warning(f"Access denied to describe conformance packs in {self.region}")
355
+ else:
356
+ logger.error(f"Error describing conformance packs: {e}")
357
+
358
+ return packs
359
+
360
+ def get_conformance_pack_compliance(self, pack_name: str) -> Dict[str, Any]:
361
+ """
362
+ Get compliance status for a conformance pack.
363
+
364
+ :param str pack_name: Name of the conformance pack
365
+ :return: Conformance pack compliance status
366
+ :rtype: Dict[str, Any]
367
+ """
368
+ try:
369
+ client = self._get_client("config")
370
+ response = client.describe_conformance_pack_status(ConformancePackNames=[pack_name])
371
+ statuses = response.get("ConformancePackStatusDetails", [])
372
+
373
+ if statuses:
374
+ status = statuses[0]
375
+ status["Region"] = self.region
376
+ return status
377
+
378
+ return {}
379
+ except ClientError as e:
380
+ if e.response["Error"]["Code"] != "AccessDeniedException":
381
+ logger.error(f"Error getting conformance pack compliance for {pack_name}: {e}")
382
+ return {}
383
+
384
+ def get_conformance_pack_compliance_details(self, pack_name: str) -> List[Dict[str, Any]]:
385
+ """
386
+ Get detailed compliance information for all rules in a conformance pack.
387
+
388
+ :param str pack_name: Name of the conformance pack
389
+ :return: List of rule compliance details
390
+ :rtype: List[Dict[str, Any]]
391
+ """
392
+ details = []
393
+ next_token = None
394
+
395
+ try:
396
+ client = self._get_client("config")
397
+
398
+ while True:
399
+ params = {"ConformancePackName": pack_name}
400
+
401
+ if next_token:
402
+ params["NextToken"] = next_token
403
+
404
+ response = client.get_conformance_pack_compliance_details(**params)
405
+ rule_details = response.get("ConformancePackRuleCompliances", [])
406
+
407
+ for rule in rule_details:
408
+ rule["Region"] = self.region
409
+ rule["ConformancePackName"] = pack_name
410
+
411
+ details.extend(rule_details)
412
+
413
+ next_token = response.get("NextToken")
414
+ if not next_token:
415
+ break
416
+
417
+ except ClientError as e:
418
+ self._handle_error(e, f"conformance pack compliance details for {pack_name}")
419
+
420
+ return details
421
+
422
+ def get_aggregate_compliance_by_control(
423
+ self, control_mappings: Dict[str, List[str]]
424
+ ) -> Dict[str, List[Dict[str, Any]]]:
425
+ """
426
+ Aggregate Config rule compliance by control ID.
427
+
428
+ :param Dict[str, List[str]] control_mappings: Map of control_id -> list of rule names
429
+ :return: Dictionary mapping control_id to list of rule evaluation results
430
+ :rtype: Dict[str, List[Dict[str, Any]]]
431
+ """
432
+ control_compliance = {}
433
+
434
+ try:
435
+ client = self._get_client("config")
436
+
437
+ for control_id, rule_names in control_mappings.items():
438
+ control_compliance[control_id] = []
439
+
440
+ for rule_name in rule_names:
441
+ # Get compliance summary for this rule
442
+ compliance = self._describe_compliance_by_config_rule(client, rule_name)
443
+
444
+ if compliance:
445
+ # Get detailed evaluation results
446
+ details = self.get_compliance_details(rule_name)
447
+
448
+ evaluation_result = {
449
+ "control_id": control_id,
450
+ "rule_name": rule_name,
451
+ "compliance_type": compliance.get("Compliance", {}).get("ComplianceType", ""),
452
+ "compliance_summary": compliance.get("Compliance", {}),
453
+ "evaluation_details": details,
454
+ "non_compliant_resource_count": sum(
455
+ 1 for d in details if d.get("ComplianceType") == "NON_COMPLIANT"
456
+ ),
457
+ }
458
+
459
+ control_compliance[control_id].append(evaluation_result)
460
+
461
+ except Exception as e:
462
+ logger.error(f"Error aggregating compliance by control: {e}", exc_info=True)
463
+
464
+ return control_compliance
@@ -1,12 +1,32 @@
1
1
  """AWS container 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 ContainerCollector(BaseCollector):
9
- """Collector for AWS container resources."""
9
+ """Collector for AWS container 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 container 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
  @staticmethod
12
32
  def _get_repository_policy(ecr, repository_name: str) -> Dict[str, Any]:
@@ -78,9 +98,45 @@ class ContainerCollector(BaseCollector):
78
98
  "Images": images,
79
99
  }
80
100
 
101
+ def _should_include_repository(self, ecr, repo_arn: str) -> bool:
102
+ """
103
+ Check if repository should be included based on account and tag filters.
104
+
105
+ :param ecr: ECR client
106
+ :param str repo_arn: Repository ARN
107
+ :return: True if repository should be included, False otherwise
108
+ :rtype: bool
109
+ """
110
+ if not self._matches_account(repo_arn):
111
+ return False
112
+
113
+ if self.tags:
114
+ try:
115
+ tags_response = ecr.list_tags_for_resource(resourceArn=repo_arn)
116
+ repo_tags = tags_response.get("tags", [])
117
+ return self._matches_tags(repo_tags)
118
+ except Exception:
119
+ return False
120
+
121
+ return True
122
+
123
+ def _process_single_repository(self, ecr, repo: Dict[str, Any]) -> Dict[str, Any]:
124
+ """
125
+ Process a single repository, retrieving policy, images, and building data.
126
+
127
+ :param ecr: ECR client
128
+ :param repo: Repository data
129
+ :return: Processed repository data
130
+ :rtype: Dict[str, Any]
131
+ """
132
+ repo_name = repo["repositoryName"]
133
+ policy = self._get_repository_policy(ecr, repo_name)
134
+ images = self._get_repository_images(ecr, repo_name)
135
+ return self._build_repository_data(repo, policy, images)
136
+
81
137
  def get_ecr_repositories(self) -> List[Dict[str, Any]]:
82
138
  """
83
- Get information about ECR repositories.
139
+ Get information about ECR repositories with filtering.
84
140
 
85
141
  :return: List of ECR repository information
86
142
  :rtype: List[Dict[str, Any]]
@@ -93,9 +149,12 @@ class ContainerCollector(BaseCollector):
93
149
  for page in paginator.paginate():
94
150
  for repo in page.get("repositories", []):
95
151
  try:
96
- policy = self._get_repository_policy(ecr, repo["repositoryName"])
97
- images = self._get_repository_images(ecr, repo["repositoryName"])
98
- repo_data = self._build_repository_data(repo, policy, images)
152
+ repo_arn = repo.get("repositoryArn", "")
153
+
154
+ if not self._should_include_repository(ecr, repo_arn):
155
+ continue
156
+
157
+ repo_data = self._process_single_repository(ecr, repo)
99
158
  repositories.append(repo_data)
100
159
  except Exception as e:
101
160
  self._handle_error(e, f"ECR repository {repo['repositoryName']}")
@@ -105,9 +164,15 @@ class ContainerCollector(BaseCollector):
105
164
 
106
165
  def collect(self) -> Dict[str, Any]:
107
166
  """
108
- Collect all container resources.
167
+ Collect container resources based on enabled_services configuration.
109
168
 
110
- :return: Dictionary containing all container resource information
169
+ :return: Dictionary containing enabled container resource information
111
170
  :rtype: Dict[str, Any]
112
171
  """
113
- return {"ECRRepositories": self.get_ecr_repositories()}
172
+ result = {}
173
+
174
+ # ECR Repositories
175
+ if self.enabled_services.get("ecr", True):
176
+ result["ECRRepositories"] = self.get_ecr_repositories()
177
+
178
+ return result