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.
- regscale/_version.py +1 -1
- regscale/airflow/hierarchy.py +2 -2
- regscale/core/app/api.py +5 -2
- regscale/core/app/application.py +36 -6
- regscale/core/app/internal/control_editor.py +73 -21
- regscale/core/app/internal/evidence.py +727 -204
- regscale/core/app/internal/login.py +4 -2
- regscale/core/app/internal/model_editor.py +219 -64
- regscale/core/app/utils/app_utils.py +86 -12
- regscale/core/app/utils/catalog_utils/common.py +1 -1
- regscale/core/login.py +21 -4
- regscale/core/utils/async_graphql_client.py +363 -0
- regscale/core/utils/date.py +77 -1
- regscale/dev/cli.py +26 -0
- regscale/dev/code_gen.py +109 -24
- regscale/dev/version.py +72 -0
- regscale/integrations/commercial/__init__.py +30 -2
- regscale/integrations/commercial/aws/audit_manager_compliance.py +3908 -0
- regscale/integrations/commercial/aws/cli.py +3107 -54
- regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
- regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
- regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
- regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
- regscale/integrations/commercial/{amazon → aws}/common.py +71 -19
- regscale/integrations/commercial/aws/config_compliance.py +914 -0
- regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
- regscale/integrations/commercial/aws/control_compliance_analyzer.py +439 -0
- regscale/integrations/commercial/aws/evidence_generator.py +283 -0
- regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
- regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
- regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
- regscale/integrations/commercial/aws/iam_evidence.py +574 -0
- regscale/integrations/commercial/aws/inventory/__init__.py +338 -22
- regscale/integrations/commercial/aws/inventory/base.py +107 -5
- regscale/integrations/commercial/aws/inventory/resources/analytics.py +390 -0
- regscale/integrations/commercial/aws/inventory/resources/applications.py +234 -0
- regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
- regscale/integrations/commercial/aws/inventory/resources/compute.py +328 -9
- regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
- regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
- regscale/integrations/commercial/aws/inventory/resources/database.py +481 -31
- regscale/integrations/commercial/aws/inventory/resources/developer_tools.py +253 -0
- regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
- regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
- regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
- regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
- regscale/integrations/commercial/aws/inventory/resources/machine_learning.py +358 -0
- regscale/integrations/commercial/aws/inventory/resources/networking.py +390 -67
- regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
- regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
- regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
- regscale/integrations/commercial/aws/inventory/resources/storage.py +288 -29
- regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
- regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
- regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
- regscale/integrations/commercial/aws/kms_evidence.py +879 -0
- regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
- regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
- regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
- regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
- regscale/integrations/commercial/aws/org_evidence.py +666 -0
- regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
- regscale/integrations/commercial/aws/s3_evidence.py +632 -0
- regscale/integrations/commercial/aws/scanner.py +1072 -205
- regscale/integrations/commercial/aws/security_hub.py +319 -0
- regscale/integrations/commercial/aws/session_manager.py +282 -0
- regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
- regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
- regscale/integrations/commercial/jira.py +489 -153
- regscale/integrations/commercial/microsoft_defender/defender.py +326 -5
- regscale/integrations/commercial/microsoft_defender/defender_api.py +348 -14
- regscale/integrations/commercial/microsoft_defender/defender_constants.py +157 -0
- regscale/integrations/commercial/qualys/__init__.py +167 -68
- regscale/integrations/commercial/qualys/scanner.py +305 -39
- regscale/integrations/commercial/sarif/sairf_importer.py +432 -0
- regscale/integrations/commercial/sarif/sarif_converter.py +67 -0
- regscale/integrations/commercial/sicura/api.py +79 -42
- regscale/integrations/commercial/sicura/commands.py +8 -2
- regscale/integrations/commercial/sicura/scanner.py +83 -44
- regscale/integrations/commercial/stigv2/ckl_parser.py +5 -5
- regscale/integrations/commercial/synqly/assets.py +133 -16
- regscale/integrations/commercial/synqly/edr.py +2 -8
- regscale/integrations/commercial/synqly/query_builder.py +536 -0
- regscale/integrations/commercial/synqly/ticketing.py +27 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +165 -28
- regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
- regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
- regscale/integrations/commercial/tenablev2/commands.py +146 -5
- regscale/integrations/commercial/tenablev2/scanner.py +1 -3
- regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
- regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +191 -76
- regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
- regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
- regscale/integrations/commercial/wizv2/compliance_report.py +1592 -0
- regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
- regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +7 -3
- regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +92 -89
- regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
- regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +66 -9
- regscale/integrations/commercial/wizv2/file_cleanup.py +104 -0
- regscale/integrations/commercial/wizv2/issue.py +776 -28
- regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
- regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
- regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
- regscale/integrations/commercial/wizv2/reports.py +243 -0
- regscale/integrations/commercial/wizv2/sbom.py +1 -1
- regscale/integrations/commercial/wizv2/scanner.py +1031 -441
- regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
- regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
- regscale/integrations/commercial/wizv2/variables.py +89 -3
- regscale/integrations/compliance_integration.py +1036 -151
- regscale/integrations/control_matcher.py +432 -0
- regscale/integrations/due_date_handler.py +333 -0
- regscale/integrations/milestone_manager.py +291 -0
- regscale/integrations/public/__init__.py +14 -0
- regscale/integrations/public/cci_importer.py +834 -0
- regscale/integrations/public/csam/__init__.py +0 -0
- regscale/integrations/public/csam/csam.py +938 -0
- regscale/integrations/public/csam/csam_agency_defined.py +179 -0
- regscale/integrations/public/csam/csam_common.py +154 -0
- regscale/integrations/public/csam/csam_controls.py +432 -0
- regscale/integrations/public/csam/csam_poam.py +124 -0
- regscale/integrations/public/fedramp/click.py +77 -6
- regscale/integrations/public/fedramp/docx_parser.py +10 -1
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +675 -289
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/public/fedramp/poam/scanner.py +75 -7
- regscale/integrations/public/fedramp/poam_export_v5.py +888 -0
- regscale/integrations/scanner_integration.py +1961 -430
- regscale/models/integration_models/CCI_List.xml +1 -0
- regscale/models/integration_models/aqua.py +2 -2
- regscale/models/integration_models/cisa_kev_data.json +805 -11
- regscale/models/integration_models/flat_file_importer/__init__.py +5 -8
- regscale/models/integration_models/nexpose.py +36 -10
- regscale/models/integration_models/qualys.py +3 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +87 -18
- regscale/models/integration_models/synqly_models/filter_parser.py +332 -0
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +124 -25
- regscale/models/integration_models/synqly_models/synqly_model.py +89 -16
- regscale/models/locking.py +12 -8
- regscale/models/platform.py +4 -2
- regscale/models/regscale_models/__init__.py +7 -0
- regscale/models/regscale_models/assessment.py +2 -1
- regscale/models/regscale_models/catalog.py +1 -1
- regscale/models/regscale_models/compliance_settings.py +251 -1
- regscale/models/regscale_models/component.py +1 -0
- regscale/models/regscale_models/control_implementation.py +236 -41
- regscale/models/regscale_models/control_objective.py +74 -5
- regscale/models/regscale_models/file.py +2 -0
- regscale/models/regscale_models/form_field_value.py +5 -3
- regscale/models/regscale_models/inheritance.py +44 -0
- regscale/models/regscale_models/issue.py +301 -102
- regscale/models/regscale_models/milestone.py +33 -14
- regscale/models/regscale_models/organization.py +3 -0
- regscale/models/regscale_models/regscale_model.py +310 -73
- regscale/models/regscale_models/security_plan.py +4 -2
- regscale/models/regscale_models/vulnerability.py +3 -3
- regscale/regscale.py +25 -4
- regscale/templates/__init__.py +0 -0
- regscale/utils/threading/threadhandler.py +20 -15
- regscale/validation/record.py +23 -1
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/METADATA +17 -33
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/RECORD +310 -111
- tests/core/__init__.py +0 -0
- tests/core/utils/__init__.py +0 -0
- tests/core/utils/test_async_graphql_client.py +472 -0
- tests/fixtures/test_fixture.py +13 -8
- tests/regscale/core/test_login.py +171 -4
- tests/regscale/integrations/commercial/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
- tests/regscale/integrations/commercial/aws/test_aws_analytics_collector.py +260 -0
- tests/regscale/integrations/commercial/aws/test_aws_applications_collector.py +242 -0
- tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
- tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
- tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
- tests/regscale/integrations/commercial/aws/test_aws_developer_tools_collector.py +203 -0
- tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
- tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
- tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
- tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
- tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
- tests/regscale/integrations/commercial/aws/test_aws_machine_learning_collector.py +237 -0
- tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
- tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
- tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
- tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
- tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
- tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
- tests/regscale/integrations/commercial/aws/test_control_compliance_analyzer.py +375 -0
- tests/regscale/integrations/commercial/aws/test_datetime_parsing.py +223 -0
- tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
- tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
- tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
- tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
- tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
- tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
- tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
- tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
- tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
- tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
- tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
- tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
- tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
- tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
- tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
- tests/regscale/integrations/commercial/conftest.py +28 -0
- tests/regscale/integrations/commercial/microsoft_defender/__init__.py +1 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender.py +1517 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_api.py +1748 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_constants.py +327 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_scanner.py +487 -0
- tests/regscale/integrations/commercial/test_aws.py +3742 -0
- tests/regscale/integrations/commercial/test_burp.py +48 -0
- tests/regscale/integrations/commercial/test_crowdstrike.py +49 -0
- tests/regscale/integrations/commercial/test_dependabot.py +341 -0
- tests/regscale/integrations/commercial/test_gcp.py +1543 -0
- tests/regscale/integrations/commercial/test_gitlab.py +549 -0
- tests/regscale/integrations/commercial/test_ip_mac_address_length.py +84 -0
- tests/regscale/integrations/commercial/test_jira.py +2204 -0
- tests/regscale/integrations/commercial/test_npm_audit.py +42 -0
- tests/regscale/integrations/commercial/test_okta.py +1228 -0
- tests/regscale/integrations/commercial/test_sarif_converter.py +251 -0
- tests/regscale/integrations/commercial/test_sicura.py +349 -0
- tests/regscale/integrations/commercial/test_snow.py +423 -0
- tests/regscale/integrations/commercial/test_sonarcloud.py +394 -0
- tests/regscale/integrations/commercial/test_sqlserver.py +186 -0
- tests/regscale/integrations/commercial/test_stig.py +33 -0
- tests/regscale/integrations/commercial/test_stig_mapper.py +153 -0
- tests/regscale/integrations/commercial/test_stigv2.py +406 -0
- tests/regscale/integrations/commercial/test_wiz.py +1365 -0
- tests/regscale/integrations/commercial/test_wiz_inventory.py +256 -0
- tests/regscale/integrations/commercial/wizv2/__init__.py +339 -0
- tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
- tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
- tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
- tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
- tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
- tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
- tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
- tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
- tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +343 -0
- tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
- tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
- tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
- tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +165 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +1394 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_unit.py +341 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_status_mapping.py +149 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +1218 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +519 -0
- tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
- tests/regscale/integrations/public/__init__.py +0 -0
- tests/regscale/integrations/public/fedramp/__init__.py +1 -0
- tests/regscale/integrations/public/fedramp/test_gen_asset_list.py +150 -0
- tests/regscale/integrations/public/fedramp/test_poam_export_v5.py +1293 -0
- tests/regscale/integrations/public/test_alienvault.py +220 -0
- tests/regscale/integrations/public/test_cci.py +1053 -0
- tests/regscale/integrations/public/test_cisa.py +1021 -0
- tests/regscale/integrations/public/test_emass.py +518 -0
- tests/regscale/integrations/public/test_fedramp.py +1152 -0
- tests/regscale/integrations/public/test_fedramp_cis_crm.py +3661 -0
- tests/regscale/integrations/public/test_file_uploads.py +506 -0
- tests/regscale/integrations/public/test_oscal.py +453 -0
- tests/regscale/integrations/test_compliance_status_mapping.py +406 -0
- tests/regscale/integrations/test_control_matcher.py +1421 -0
- tests/regscale/integrations/test_control_matching.py +155 -0
- tests/regscale/integrations/test_milestone_manager.py +408 -0
- tests/regscale/models/test_control_implementation.py +118 -3
- tests/regscale/models/test_form_field_value_integration.py +304 -0
- tests/regscale/models/test_issue.py +378 -1
- tests/regscale/models/test_module_integration.py +582 -0
- tests/regscale/models/test_tenable_integrations.py +811 -105
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3057
- regscale/integrations/public/fedramp/mappings/fedramp_r4_parts.json +0 -7388
- regscale/integrations/public/fedramp/mappings/fedramp_r5_parts.json +0 -9605
- regscale/integrations/public/fedramp/parts_mapper.py +0 -107
- /regscale/integrations/commercial/{amazon → sarif}/__init__.py +0 -0
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/LICENSE +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/WHEEL +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"""AWS analytics resource collectors."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Dict, List, Any, Optional
|
|
5
|
+
|
|
6
|
+
from ..base import BaseCollector
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger("regscale")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AnalyticsCollector(BaseCollector):
|
|
12
|
+
"""Collector for AWS analytics resources with filtering support."""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
session: Any,
|
|
17
|
+
region: str,
|
|
18
|
+
account_id: Optional[str] = None,
|
|
19
|
+
tags: Optional[Dict[str, str]] = None,
|
|
20
|
+
enabled_services: Optional[Dict[str, bool]] = None,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Initialize analytics collector with filtering support.
|
|
24
|
+
|
|
25
|
+
:param session: AWS session to use for API calls
|
|
26
|
+
:param str region: AWS region to collect from
|
|
27
|
+
:param str account_id: Optional AWS account ID to filter resources
|
|
28
|
+
:param dict tags: Optional tag filters (AND logic)
|
|
29
|
+
:param dict enabled_services: Optional dict of service names to boolean flags for enabling/disabling collection
|
|
30
|
+
"""
|
|
31
|
+
super().__init__(session, region, account_id, tags)
|
|
32
|
+
self.enabled_services = enabled_services or {}
|
|
33
|
+
|
|
34
|
+
def get_emr_clusters(self) -> List[Dict[str, Any]]:
|
|
35
|
+
"""
|
|
36
|
+
Get information about EMR clusters.
|
|
37
|
+
|
|
38
|
+
:return: List of EMR cluster information
|
|
39
|
+
:rtype: List[Dict[str, Any]]
|
|
40
|
+
"""
|
|
41
|
+
clusters = []
|
|
42
|
+
try:
|
|
43
|
+
emr_client = self._get_client("emr")
|
|
44
|
+
paginator = emr_client.get_paginator("list_clusters")
|
|
45
|
+
|
|
46
|
+
for page in paginator.paginate(ClusterStates=["STARTING", "BOOTSTRAPPING", "RUNNING", "WAITING"]):
|
|
47
|
+
for cluster_summary in page.get("Clusters", []):
|
|
48
|
+
cluster_id = cluster_summary.get("Id")
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
cluster_detail = emr_client.describe_cluster(ClusterId=cluster_id)
|
|
52
|
+
cluster = cluster_detail.get("Cluster", {})
|
|
53
|
+
cluster_arn = cluster.get("ClusterArn", "")
|
|
54
|
+
|
|
55
|
+
if not self._matches_account(cluster_arn):
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
if not self._matches_tags(cluster.get("Tags", [])):
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
clusters.append(
|
|
62
|
+
{
|
|
63
|
+
"Region": self.region,
|
|
64
|
+
"ClusterId": cluster_id,
|
|
65
|
+
"ClusterArn": cluster_arn,
|
|
66
|
+
"Name": cluster.get("Name"),
|
|
67
|
+
"Status": cluster.get("Status", {}).get("State"),
|
|
68
|
+
"NormalizedInstanceHours": cluster.get("NormalizedInstanceHours"),
|
|
69
|
+
"MasterPublicDnsName": cluster.get("MasterPublicDnsName"),
|
|
70
|
+
"ReleaseLabel": cluster.get("ReleaseLabel"),
|
|
71
|
+
"AutoTerminate": cluster.get("AutoTerminate"),
|
|
72
|
+
"Tags": cluster.get("Tags", []),
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
except Exception as detail_error:
|
|
76
|
+
logger.debug("Error getting EMR cluster details for %s: %s", cluster_id, detail_error)
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
except Exception as e:
|
|
80
|
+
self._handle_error(e, "EMR clusters")
|
|
81
|
+
return clusters
|
|
82
|
+
|
|
83
|
+
def get_kinesis_streams(self) -> List[Dict[str, Any]]:
|
|
84
|
+
"""
|
|
85
|
+
Get information about Kinesis Data Streams.
|
|
86
|
+
|
|
87
|
+
:return: List of Kinesis stream information
|
|
88
|
+
:rtype: List[Dict[str, Any]]
|
|
89
|
+
"""
|
|
90
|
+
streams = []
|
|
91
|
+
try:
|
|
92
|
+
kinesis_client = self._get_client("kinesis")
|
|
93
|
+
paginator = kinesis_client.get_paginator("list_streams")
|
|
94
|
+
|
|
95
|
+
for page in paginator.paginate():
|
|
96
|
+
for stream_name in page.get("StreamNames", []):
|
|
97
|
+
try:
|
|
98
|
+
stream_detail = kinesis_client.describe_stream(StreamName=stream_name)
|
|
99
|
+
stream = stream_detail.get("StreamDescription", {})
|
|
100
|
+
stream_arn = stream.get("StreamARN", "")
|
|
101
|
+
|
|
102
|
+
if not self._matches_account(stream_arn):
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
tags_response = kinesis_client.list_tags_for_stream(StreamName=stream_name)
|
|
106
|
+
stream_tags = tags_response.get("Tags", [])
|
|
107
|
+
|
|
108
|
+
if not self._matches_tags(stream_tags):
|
|
109
|
+
continue
|
|
110
|
+
|
|
111
|
+
streams.append(
|
|
112
|
+
{
|
|
113
|
+
"Region": self.region,
|
|
114
|
+
"StreamName": stream_name,
|
|
115
|
+
"StreamARN": stream_arn,
|
|
116
|
+
"StreamStatus": stream.get("StreamStatus"),
|
|
117
|
+
"RetentionPeriodHours": stream.get("RetentionPeriodHours"),
|
|
118
|
+
"StreamCreationTimestamp": stream.get("StreamCreationTimestamp"),
|
|
119
|
+
"EnhancedMonitoring": stream.get("EnhancedMonitoring", []),
|
|
120
|
+
"EncryptionType": stream.get("EncryptionType"),
|
|
121
|
+
"Tags": stream_tags,
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
except Exception as stream_error:
|
|
125
|
+
logger.debug("Error getting Kinesis stream details for %s: %s", stream_name, stream_error)
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
self._handle_error(e, "Kinesis Data Streams")
|
|
130
|
+
return streams
|
|
131
|
+
|
|
132
|
+
def _process_firehose_stream(self, firehose_client: Any, stream_name: str) -> Optional[Dict[str, Any]]:
|
|
133
|
+
"""
|
|
134
|
+
Process a single Firehose delivery stream.
|
|
135
|
+
|
|
136
|
+
:param firehose_client: Firehose client
|
|
137
|
+
:param str stream_name: Stream name
|
|
138
|
+
:return: Stream information or None if filtered out
|
|
139
|
+
:rtype: Optional[Dict[str, Any]]
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
stream_detail = firehose_client.describe_delivery_stream(DeliveryStreamName=stream_name)
|
|
143
|
+
stream = stream_detail.get("DeliveryStreamDescription", {})
|
|
144
|
+
stream_arn = stream.get("DeliveryStreamARN", "")
|
|
145
|
+
|
|
146
|
+
if not self._matches_account(stream_arn):
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
tags_response = firehose_client.list_tags_for_delivery_stream(DeliveryStreamName=stream_name)
|
|
150
|
+
stream_tags = tags_response.get("Tags", [])
|
|
151
|
+
|
|
152
|
+
if not self._matches_tags(stream_tags):
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
"Region": self.region,
|
|
157
|
+
"DeliveryStreamName": stream_name,
|
|
158
|
+
"DeliveryStreamARN": stream_arn,
|
|
159
|
+
"DeliveryStreamStatus": stream.get("DeliveryStreamStatus"),
|
|
160
|
+
"DeliveryStreamType": stream.get("DeliveryStreamType"),
|
|
161
|
+
"VersionId": stream.get("VersionId"),
|
|
162
|
+
"CreateTimestamp": stream.get("CreateTimestamp"),
|
|
163
|
+
"Tags": stream_tags,
|
|
164
|
+
}
|
|
165
|
+
except Exception as stream_error:
|
|
166
|
+
logger.debug("Error getting Firehose stream details for %s: %s", stream_name, stream_error)
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
def get_kinesis_firehose_streams(self) -> List[Dict[str, Any]]:
|
|
170
|
+
"""
|
|
171
|
+
Get information about Kinesis Firehose delivery streams.
|
|
172
|
+
|
|
173
|
+
:return: List of Kinesis Firehose stream information
|
|
174
|
+
:rtype: List[Dict[str, Any]]
|
|
175
|
+
"""
|
|
176
|
+
streams = []
|
|
177
|
+
try:
|
|
178
|
+
firehose_client = self._get_client("firehose")
|
|
179
|
+
has_more = True
|
|
180
|
+
exclusive_start_stream_name = None
|
|
181
|
+
|
|
182
|
+
while has_more:
|
|
183
|
+
if exclusive_start_stream_name:
|
|
184
|
+
response = firehose_client.list_delivery_streams(
|
|
185
|
+
ExclusiveStartDeliveryStreamName=exclusive_start_stream_name
|
|
186
|
+
)
|
|
187
|
+
else:
|
|
188
|
+
response = firehose_client.list_delivery_streams()
|
|
189
|
+
|
|
190
|
+
for stream_name in response.get("DeliveryStreamNames", []):
|
|
191
|
+
stream_info = self._process_firehose_stream(firehose_client, stream_name)
|
|
192
|
+
if stream_info:
|
|
193
|
+
streams.append(stream_info)
|
|
194
|
+
|
|
195
|
+
has_more = response.get("HasMoreDeliveryStreams", False)
|
|
196
|
+
if has_more and response.get("DeliveryStreamNames"):
|
|
197
|
+
exclusive_start_stream_name = response["DeliveryStreamNames"][-1]
|
|
198
|
+
else:
|
|
199
|
+
has_more = False
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
self._handle_error(e, "Kinesis Firehose delivery streams")
|
|
203
|
+
return streams
|
|
204
|
+
|
|
205
|
+
def get_glue_databases(self) -> List[Dict[str, Any]]:
|
|
206
|
+
"""
|
|
207
|
+
Get information about AWS Glue databases.
|
|
208
|
+
|
|
209
|
+
:return: List of Glue database information
|
|
210
|
+
:rtype: List[Dict[str, Any]]
|
|
211
|
+
"""
|
|
212
|
+
databases = []
|
|
213
|
+
try:
|
|
214
|
+
glue_client = self._get_client("glue")
|
|
215
|
+
paginator = glue_client.get_paginator("get_databases")
|
|
216
|
+
|
|
217
|
+
for page in paginator.paginate():
|
|
218
|
+
for database in page.get("DatabaseList", []):
|
|
219
|
+
database_name = database.get("Name")
|
|
220
|
+
database_arn = f"arn:aws:glue:{self.region}:{self.account_id or '*'}:database/{database_name}"
|
|
221
|
+
|
|
222
|
+
if not self._matches_account(database_arn):
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
tags_response = glue_client.get_tags(ResourceArn=database_arn)
|
|
227
|
+
database_tags = tags_response.get("Tags", {})
|
|
228
|
+
|
|
229
|
+
if not self._matches_tags(database_tags):
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
databases.append(
|
|
233
|
+
{
|
|
234
|
+
"Region": self.region,
|
|
235
|
+
"DatabaseName": database_name,
|
|
236
|
+
"Description": database.get("Description"),
|
|
237
|
+
"LocationUri": database.get("LocationUri"),
|
|
238
|
+
"CreateTime": database.get("CreateTime"),
|
|
239
|
+
"Tags": database_tags,
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
except Exception as tag_error:
|
|
243
|
+
logger.debug("Error getting Glue database tags for %s: %s", database_name, tag_error)
|
|
244
|
+
continue
|
|
245
|
+
|
|
246
|
+
except Exception as e:
|
|
247
|
+
self._handle_error(e, "Glue databases")
|
|
248
|
+
return databases
|
|
249
|
+
|
|
250
|
+
def _process_athena_workgroup(self, athena_client: Any, wg_name: str) -> Optional[Dict[str, Any]]:
|
|
251
|
+
"""
|
|
252
|
+
Process a single Athena workgroup.
|
|
253
|
+
|
|
254
|
+
:param athena_client: Athena client
|
|
255
|
+
:param str wg_name: Workgroup name
|
|
256
|
+
:return: Workgroup information or None if filtered out
|
|
257
|
+
:rtype: Optional[Dict[str, Any]]
|
|
258
|
+
"""
|
|
259
|
+
try:
|
|
260
|
+
wg_detail = athena_client.get_work_group(WorkGroup=wg_name)
|
|
261
|
+
workgroup = wg_detail.get("WorkGroup", {})
|
|
262
|
+
|
|
263
|
+
wg_arn = f"arn:aws:athena:{self.region}:{self.account_id or '*'}:workgroup/{wg_name}"
|
|
264
|
+
|
|
265
|
+
if not self._matches_account(wg_arn):
|
|
266
|
+
return None
|
|
267
|
+
|
|
268
|
+
tags_response = athena_client.list_tags_for_resource(ResourceARN=wg_arn)
|
|
269
|
+
wg_tags = tags_response.get("Tags", [])
|
|
270
|
+
|
|
271
|
+
if not self._matches_tags(wg_tags):
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
"Region": self.region,
|
|
276
|
+
"WorkGroupName": wg_name,
|
|
277
|
+
"State": workgroup.get("State"),
|
|
278
|
+
"Description": workgroup.get("Description"),
|
|
279
|
+
"CreationTime": workgroup.get("CreationTime"),
|
|
280
|
+
"Tags": wg_tags,
|
|
281
|
+
}
|
|
282
|
+
except Exception as wg_error:
|
|
283
|
+
logger.debug("Error getting Athena workgroup details for %s: %s", wg_name, wg_error)
|
|
284
|
+
return None
|
|
285
|
+
|
|
286
|
+
def get_athena_workgroups(self) -> List[Dict[str, Any]]:
|
|
287
|
+
"""
|
|
288
|
+
Get information about Athena workgroups.
|
|
289
|
+
|
|
290
|
+
:return: List of Athena workgroup information
|
|
291
|
+
:rtype: List[Dict[str, Any]]
|
|
292
|
+
"""
|
|
293
|
+
workgroups = []
|
|
294
|
+
try:
|
|
295
|
+
athena_client = self._get_client("athena")
|
|
296
|
+
next_token = None
|
|
297
|
+
|
|
298
|
+
while True:
|
|
299
|
+
if next_token:
|
|
300
|
+
response = athena_client.list_work_groups(NextToken=next_token)
|
|
301
|
+
else:
|
|
302
|
+
response = athena_client.list_work_groups()
|
|
303
|
+
|
|
304
|
+
for wg_summary in response.get("WorkGroups", []):
|
|
305
|
+
wg_name = wg_summary.get("Name")
|
|
306
|
+
wg_info = self._process_athena_workgroup(athena_client, wg_name)
|
|
307
|
+
if wg_info:
|
|
308
|
+
workgroups.append(wg_info)
|
|
309
|
+
|
|
310
|
+
next_token = response.get("NextToken")
|
|
311
|
+
if not next_token:
|
|
312
|
+
break
|
|
313
|
+
|
|
314
|
+
except Exception as e:
|
|
315
|
+
self._handle_error(e, "Athena workgroups")
|
|
316
|
+
return workgroups
|
|
317
|
+
|
|
318
|
+
def get_msk_clusters(self) -> List[Dict[str, Any]]:
|
|
319
|
+
"""
|
|
320
|
+
Get information about MSK (Managed Streaming for Kafka) clusters.
|
|
321
|
+
|
|
322
|
+
:return: List of MSK cluster information
|
|
323
|
+
:rtype: List[Dict[str, Any]]
|
|
324
|
+
"""
|
|
325
|
+
clusters = []
|
|
326
|
+
try:
|
|
327
|
+
msk_client = self._get_client("kafka")
|
|
328
|
+
paginator = msk_client.get_paginator("list_clusters")
|
|
329
|
+
|
|
330
|
+
for page in paginator.paginate():
|
|
331
|
+
for cluster_info in page.get("ClusterInfoList", []):
|
|
332
|
+
cluster_arn = cluster_info.get("ClusterArn", "")
|
|
333
|
+
|
|
334
|
+
if not self._matches_account(cluster_arn):
|
|
335
|
+
continue
|
|
336
|
+
|
|
337
|
+
if not self._matches_tags(cluster_info.get("Tags", {})):
|
|
338
|
+
continue
|
|
339
|
+
|
|
340
|
+
clusters.append(
|
|
341
|
+
{
|
|
342
|
+
"Region": self.region,
|
|
343
|
+
"ClusterName": cluster_info.get("ClusterName"),
|
|
344
|
+
"ClusterArn": cluster_arn,
|
|
345
|
+
"State": cluster_info.get("State"),
|
|
346
|
+
"ClusterType": cluster_info.get("ClusterType"),
|
|
347
|
+
"CurrentVersion": cluster_info.get("CurrentVersion"),
|
|
348
|
+
"CreationTime": cluster_info.get("CreationTime"),
|
|
349
|
+
"NumberOfBrokerNodes": cluster_info.get("NumberOfBrokerNodes"),
|
|
350
|
+
"Tags": cluster_info.get("Tags", {}),
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
except Exception as e:
|
|
354
|
+
self._handle_error(e, "MSK clusters")
|
|
355
|
+
return clusters
|
|
356
|
+
|
|
357
|
+
def collect(self) -> Dict[str, Any]:
|
|
358
|
+
"""
|
|
359
|
+
Collect analytics resources based on enabled_services configuration.
|
|
360
|
+
|
|
361
|
+
:return: Dictionary containing enabled analytics resource information
|
|
362
|
+
:rtype: Dict[str, Any]
|
|
363
|
+
"""
|
|
364
|
+
result = {}
|
|
365
|
+
|
|
366
|
+
# EMR Clusters
|
|
367
|
+
if self.enabled_services.get("emr", True):
|
|
368
|
+
result["EMRClusters"] = self.get_emr_clusters()
|
|
369
|
+
|
|
370
|
+
# Kinesis Data Streams
|
|
371
|
+
if self.enabled_services.get("kinesis_streams", True):
|
|
372
|
+
result["KinesisStreams"] = self.get_kinesis_streams()
|
|
373
|
+
|
|
374
|
+
# Kinesis Firehose
|
|
375
|
+
if self.enabled_services.get("kinesis_firehose", True):
|
|
376
|
+
result["KinesisFirehoseStreams"] = self.get_kinesis_firehose_streams()
|
|
377
|
+
|
|
378
|
+
# Glue Databases
|
|
379
|
+
if self.enabled_services.get("glue", True):
|
|
380
|
+
result["GlueDatabases"] = self.get_glue_databases()
|
|
381
|
+
|
|
382
|
+
# Athena Workgroups
|
|
383
|
+
if self.enabled_services.get("athena", True):
|
|
384
|
+
result["AthenaWorkgroups"] = self.get_athena_workgroups()
|
|
385
|
+
|
|
386
|
+
# MSK Clusters
|
|
387
|
+
if self.enabled_services.get("msk", True):
|
|
388
|
+
result["MSKClusters"] = self.get_msk_clusters()
|
|
389
|
+
|
|
390
|
+
return result
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""AWS application service resource collectors."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Dict, List, Any, Optional
|
|
5
|
+
|
|
6
|
+
from ..base import BaseCollector
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger("regscale")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ApplicationCollector(BaseCollector):
|
|
12
|
+
"""Collector for AWS application service resources with filtering support."""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
session: Any,
|
|
17
|
+
region: str,
|
|
18
|
+
account_id: Optional[str] = None,
|
|
19
|
+
tags: Optional[Dict[str, str]] = None,
|
|
20
|
+
enabled_services: Optional[Dict[str, bool]] = None,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
Initialize application collector with filtering support.
|
|
24
|
+
|
|
25
|
+
:param session: AWS session to use for API calls
|
|
26
|
+
:param str region: AWS region to collect from
|
|
27
|
+
:param str account_id: Optional AWS account ID to filter resources
|
|
28
|
+
:param dict tags: Optional tag filters (AND logic)
|
|
29
|
+
:param dict enabled_services: Optional dict of service names to boolean flags for enabling/disabling collection
|
|
30
|
+
"""
|
|
31
|
+
super().__init__(session, region, account_id, tags)
|
|
32
|
+
self.enabled_services = enabled_services or {}
|
|
33
|
+
|
|
34
|
+
def get_step_functions_state_machines(self) -> List[Dict[str, Any]]:
|
|
35
|
+
"""
|
|
36
|
+
Get information about Step Functions state machines.
|
|
37
|
+
|
|
38
|
+
:return: List of Step Functions state machine information
|
|
39
|
+
:rtype: List[Dict[str, Any]]
|
|
40
|
+
"""
|
|
41
|
+
state_machines = []
|
|
42
|
+
try:
|
|
43
|
+
sfn_client = self._get_client("stepfunctions")
|
|
44
|
+
paginator = sfn_client.get_paginator("list_state_machines")
|
|
45
|
+
|
|
46
|
+
for page in paginator.paginate():
|
|
47
|
+
for sm_item in page.get("stateMachines", []):
|
|
48
|
+
sm_arn = sm_item.get("stateMachineArn", "")
|
|
49
|
+
|
|
50
|
+
if not self._matches_account(sm_arn):
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
sm_detail = sfn_client.describe_state_machine(stateMachineArn=sm_arn)
|
|
55
|
+
tags_response = sfn_client.list_tags_for_resource(resourceArn=sm_arn)
|
|
56
|
+
sm_tags = tags_response.get("tags", [])
|
|
57
|
+
|
|
58
|
+
if not self._matches_tags(sm_tags):
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
state_machines.append(
|
|
62
|
+
{
|
|
63
|
+
"Region": self.region,
|
|
64
|
+
"StateMachineName": sm_item.get("name"),
|
|
65
|
+
"StateMachineArn": sm_arn,
|
|
66
|
+
"Type": sm_item.get("type"),
|
|
67
|
+
"Status": sm_detail.get("status"),
|
|
68
|
+
"RoleArn": sm_detail.get("roleArn"),
|
|
69
|
+
"CreationDate": sm_item.get("creationDate"),
|
|
70
|
+
"Tags": sm_tags,
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
except Exception as sm_error:
|
|
74
|
+
logger.debug("Error getting Step Functions state machine details for %s: %s", sm_arn, sm_error)
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
self._handle_error(e, "Step Functions state machines")
|
|
79
|
+
return state_machines
|
|
80
|
+
|
|
81
|
+
def get_appsync_apis(self) -> List[Dict[str, Any]]:
|
|
82
|
+
"""
|
|
83
|
+
Get information about AppSync GraphQL APIs.
|
|
84
|
+
|
|
85
|
+
:return: List of AppSync API information
|
|
86
|
+
:rtype: List[Dict[str, Any]]
|
|
87
|
+
"""
|
|
88
|
+
apis = []
|
|
89
|
+
try:
|
|
90
|
+
appsync_client = self._get_client("appsync")
|
|
91
|
+
paginator = appsync_client.get_paginator("list_graphql_apis")
|
|
92
|
+
|
|
93
|
+
for page in paginator.paginate():
|
|
94
|
+
for api in page.get("graphqlApis", []):
|
|
95
|
+
api_arn = api.get("arn", "")
|
|
96
|
+
|
|
97
|
+
if not self._matches_account(api_arn):
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
if not self._matches_tags(api.get("tags", {})):
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
apis.append(
|
|
104
|
+
{
|
|
105
|
+
"Region": self.region,
|
|
106
|
+
"ApiId": api.get("apiId"),
|
|
107
|
+
"ApiArn": api_arn,
|
|
108
|
+
"Name": api.get("name"),
|
|
109
|
+
"AuthenticationType": api.get("authenticationType"),
|
|
110
|
+
"Uris": api.get("uris"),
|
|
111
|
+
"Tags": api.get("tags", {}),
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
except Exception as e:
|
|
115
|
+
self._handle_error(e, "AppSync GraphQL APIs")
|
|
116
|
+
return apis
|
|
117
|
+
|
|
118
|
+
def get_workspaces(self) -> List[Dict[str, Any]]:
|
|
119
|
+
"""
|
|
120
|
+
Get information about WorkSpaces virtual desktops.
|
|
121
|
+
|
|
122
|
+
:return: List of WorkSpaces information
|
|
123
|
+
:rtype: List[Dict[str, Any]]
|
|
124
|
+
"""
|
|
125
|
+
workspaces = []
|
|
126
|
+
try:
|
|
127
|
+
workspaces_client = self._get_client("workspaces")
|
|
128
|
+
paginator = workspaces_client.get_paginator("describe_workspaces")
|
|
129
|
+
|
|
130
|
+
for page in paginator.paginate():
|
|
131
|
+
for workspace in page.get("Workspaces", []):
|
|
132
|
+
workspace_id = workspace.get("WorkspaceId")
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
tags_response = workspaces_client.describe_tags(ResourceId=workspace_id)
|
|
136
|
+
workspace_tags = tags_response.get("TagList", [])
|
|
137
|
+
|
|
138
|
+
if not self._matches_tags(workspace_tags):
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
workspaces.append(
|
|
142
|
+
{
|
|
143
|
+
"Region": self.region,
|
|
144
|
+
"WorkspaceId": workspace_id,
|
|
145
|
+
"DirectoryId": workspace.get("DirectoryId"),
|
|
146
|
+
"UserName": workspace.get("UserName"),
|
|
147
|
+
"IpAddress": workspace.get("IpAddress"),
|
|
148
|
+
"State": workspace.get("State"),
|
|
149
|
+
"BundleId": workspace.get("BundleId"),
|
|
150
|
+
"SubnetId": workspace.get("SubnetId"),
|
|
151
|
+
"ComputerName": workspace.get("ComputerName"),
|
|
152
|
+
"Tags": workspace_tags,
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
except Exception as tag_error:
|
|
156
|
+
logger.debug("Error getting WorkSpaces tags for %s: %s", workspace_id, tag_error)
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
except Exception as e:
|
|
160
|
+
self._handle_error(e, "WorkSpaces")
|
|
161
|
+
return workspaces
|
|
162
|
+
|
|
163
|
+
def get_iot_things(self) -> List[Dict[str, Any]]:
|
|
164
|
+
"""
|
|
165
|
+
Get information about IoT Core things.
|
|
166
|
+
|
|
167
|
+
:return: List of IoT thing information
|
|
168
|
+
:rtype: List[Dict[str, Any]]
|
|
169
|
+
"""
|
|
170
|
+
things = []
|
|
171
|
+
try:
|
|
172
|
+
iot_client = self._get_client("iot")
|
|
173
|
+
paginator = iot_client.get_paginator("list_things")
|
|
174
|
+
|
|
175
|
+
for page in paginator.paginate():
|
|
176
|
+
for thing in page.get("things", []):
|
|
177
|
+
thing_name = thing.get("thingName")
|
|
178
|
+
thing_arn = thing.get("thingArn", "")
|
|
179
|
+
|
|
180
|
+
if not self._matches_account(thing_arn):
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
tags_response = iot_client.list_tags_for_resource(resourceArn=thing_arn)
|
|
185
|
+
thing_tags = tags_response.get("tags", [])
|
|
186
|
+
|
|
187
|
+
if not self._matches_tags(thing_tags):
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
things.append(
|
|
191
|
+
{
|
|
192
|
+
"Region": self.region,
|
|
193
|
+
"ThingName": thing_name,
|
|
194
|
+
"ThingArn": thing_arn,
|
|
195
|
+
"ThingTypeName": thing.get("thingTypeName"),
|
|
196
|
+
"Attributes": thing.get("attributes", {}),
|
|
197
|
+
"Version": thing.get("version"),
|
|
198
|
+
"Tags": thing_tags,
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
except Exception as tag_error:
|
|
202
|
+
logger.debug("Error getting IoT thing tags for %s: %s", thing_name, tag_error)
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
except Exception as e:
|
|
206
|
+
self._handle_error(e, "IoT things")
|
|
207
|
+
return things
|
|
208
|
+
|
|
209
|
+
def collect(self) -> Dict[str, Any]:
|
|
210
|
+
"""
|
|
211
|
+
Collect application service resources based on enabled_services configuration.
|
|
212
|
+
|
|
213
|
+
:return: Dictionary containing enabled application resource information
|
|
214
|
+
:rtype: Dict[str, Any]
|
|
215
|
+
"""
|
|
216
|
+
result = {}
|
|
217
|
+
|
|
218
|
+
# Step Functions State Machines
|
|
219
|
+
if self.enabled_services.get("step_functions", True):
|
|
220
|
+
result["StepFunctionsStateMachines"] = self.get_step_functions_state_machines()
|
|
221
|
+
|
|
222
|
+
# AppSync GraphQL APIs
|
|
223
|
+
if self.enabled_services.get("appsync", True):
|
|
224
|
+
result["AppSyncAPIs"] = self.get_appsync_apis()
|
|
225
|
+
|
|
226
|
+
# WorkSpaces
|
|
227
|
+
if self.enabled_services.get("workspaces", True):
|
|
228
|
+
result["WorkSpaces"] = self.get_workspaces()
|
|
229
|
+
|
|
230
|
+
# IoT Things
|
|
231
|
+
if self.enabled_services.get("iot", True):
|
|
232
|
+
result["IoTThings"] = self.get_iot_things()
|
|
233
|
+
|
|
234
|
+
return result
|