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
|
@@ -8,7 +8,89 @@ from regscale.core.app.utils.app_utils import get_current_datetime
|
|
|
8
8
|
from regscale.integrations.scanner_integration import IntegrationFinding, issue_due_date
|
|
9
9
|
from regscale.models import regscale_models
|
|
10
10
|
|
|
11
|
-
logger = logging.getLogger(
|
|
11
|
+
logger = logging.getLogger("regscale")
|
|
12
|
+
|
|
13
|
+
# Constants
|
|
14
|
+
DEFAULT_CCI_REF = "CCI-000366" # Default CCI reference for STIG findings
|
|
15
|
+
UNKNOWN_VULN_NUM = "unknown"
|
|
16
|
+
_SOLUTION_KEYWORD = "Solution:"
|
|
17
|
+
_REFERENCE_INFO_KEYWORD = "Reference Information:"
|
|
18
|
+
|
|
19
|
+
# Status mapping for STIG results
|
|
20
|
+
_RESULT_STATUS_MAP = {
|
|
21
|
+
"PASSED": regscale_models.ChecklistStatus.PASS,
|
|
22
|
+
"FAILED": regscale_models.ChecklistStatus.FAIL,
|
|
23
|
+
"ERROR": regscale_models.ChecklistStatus.FAIL,
|
|
24
|
+
"NOT APPLICABLE": regscale_models.ChecklistStatus.NOT_APPLICABLE,
|
|
25
|
+
"NOT_APPLICABLE": regscale_models.ChecklistStatus.NOT_APPLICABLE,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Severity mapping for STIG findings
|
|
29
|
+
_SEVERITY_MAP = {
|
|
30
|
+
"critical": regscale_models.IssueSeverity.Critical,
|
|
31
|
+
"high": regscale_models.IssueSeverity.High,
|
|
32
|
+
"medium": regscale_models.IssueSeverity.Moderate,
|
|
33
|
+
"low": regscale_models.IssueSeverity.Low,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _extract_field(pattern: str, text: str, flags: Union[int, re.RegexFlag] = 0, group: int = 1) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Extracts a field from a string using a regular expression.
|
|
40
|
+
|
|
41
|
+
:param str pattern: The regular expression pattern to search for
|
|
42
|
+
:param str text: The string to search in
|
|
43
|
+
:param int flags: Optional regular expression flags, defaults to 0
|
|
44
|
+
:param int group: The group number to return from the match, defaults to 1
|
|
45
|
+
:return: The extracted field as a string. Empty string if no match was found
|
|
46
|
+
:rtype: str
|
|
47
|
+
"""
|
|
48
|
+
match = re.search(pattern, text, flags)
|
|
49
|
+
return match.group(group).strip() if match else ""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _extract_reference_dict(output: str) -> dict:
|
|
53
|
+
"""
|
|
54
|
+
Extract and parse reference information into dictionary.
|
|
55
|
+
|
|
56
|
+
:param str output: The STIG output string
|
|
57
|
+
:return: Dictionary of reference information
|
|
58
|
+
:rtype: dict
|
|
59
|
+
"""
|
|
60
|
+
ref_info = _extract_field(r"Reference Information:\s*(.+)", output, flags=re.DOTALL)
|
|
61
|
+
ref_dict = {}
|
|
62
|
+
for item in ref_info.split(","):
|
|
63
|
+
if "|" in item:
|
|
64
|
+
parts = item.split("|", 1)
|
|
65
|
+
if len(parts) == 2:
|
|
66
|
+
ref_dict[parts[0].strip()] = parts[1].strip()
|
|
67
|
+
return ref_dict
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _map_result_to_status(result: str) -> regscale_models.ChecklistStatus:
|
|
71
|
+
"""
|
|
72
|
+
Map result string to ChecklistStatus enum.
|
|
73
|
+
|
|
74
|
+
:param str result: The result string from STIG output
|
|
75
|
+
:return: ChecklistStatus enum value
|
|
76
|
+
:rtype: regscale_models.ChecklistStatus
|
|
77
|
+
"""
|
|
78
|
+
result_key = result.upper().replace("_", " ").strip()
|
|
79
|
+
if result_key not in _RESULT_STATUS_MAP:
|
|
80
|
+
logger.warning("Result '%s' not found in status map", result)
|
|
81
|
+
return regscale_models.ChecklistStatus.NOT_REVIEWED
|
|
82
|
+
return _RESULT_STATUS_MAP[result_key]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _map_severity_to_enum(severity: str) -> regscale_models.IssueSeverity:
|
|
86
|
+
"""
|
|
87
|
+
Map severity string to IssueSeverity enum.
|
|
88
|
+
|
|
89
|
+
:param str severity: The severity string
|
|
90
|
+
:return: IssueSeverity enum value
|
|
91
|
+
:rtype: regscale_models.IssueSeverity
|
|
92
|
+
"""
|
|
93
|
+
return _SEVERITY_MAP.get(severity.lower(), regscale_models.IssueSeverity.NotAssigned)
|
|
12
94
|
|
|
13
95
|
|
|
14
96
|
def parse_stig_output(output: str, finding: IntegrationFinding) -> IntegrationFinding:
|
|
@@ -20,43 +102,39 @@ def parse_stig_output(output: str, finding: IntegrationFinding) -> IntegrationFi
|
|
|
20
102
|
:return: An IntegrationFinding object containing the parsed finding information.
|
|
21
103
|
:rtype: IntegrationFinding
|
|
22
104
|
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"""
|
|
26
|
-
Extracts a field from a string using a regular expression
|
|
27
|
-
|
|
28
|
-
:param str pattern: The regular expression pattern to search for
|
|
29
|
-
:param str text: The string to search in
|
|
30
|
-
:param int flags: Optional regular expression flags, defaults to 0
|
|
31
|
-
:param int group: The group number to return from the match, defaults to 1
|
|
32
|
-
:return: The extracted field as a string. Empty string if no match was found
|
|
33
|
-
:rtype: str
|
|
34
|
-
"""
|
|
35
|
-
match = re.search(pattern, text, flags)
|
|
36
|
-
return match.group(group).strip() if match else ""
|
|
37
|
-
|
|
38
|
-
# Extract fields
|
|
39
|
-
check_name_full = _extract_field(r"Check Name:\s*(.*?)\n", output, flags=re.DOTALL | re.MULTILINE)
|
|
105
|
+
# Extract fields using optimized regex patterns (preventing catastrophic backtracking)
|
|
106
|
+
check_name_full = _extract_field(r"Check Name:\s*([^\n]+)", output)
|
|
40
107
|
check_name_parts = check_name_full.split(":", 1)
|
|
41
108
|
rule_id = check_name_parts[0].strip()
|
|
42
109
|
check_description = check_name_parts[1].strip() if len(check_name_parts) > 1 else ""
|
|
43
110
|
|
|
111
|
+
# Extract baseline from Target keyword
|
|
44
112
|
baseline = _extract_field(r"(.*?)\s+Target\s+(.*)", check_description, group=2)
|
|
45
|
-
|
|
113
|
+
target_match = _extract_field(r"(.*?)\s+Target\s+(.*)", check_description)
|
|
114
|
+
if target_match:
|
|
46
115
|
check_description = check_description[: check_description.find(target_match) + len(target_match)].strip()
|
|
47
116
|
|
|
48
|
-
information = _extract_field(r"Information:\s*(
|
|
49
|
-
vuln_discuss = _extract_field(r"VulnDiscussion='(
|
|
50
|
-
result = _extract_field(r"Result:\s*(
|
|
51
|
-
solution
|
|
117
|
+
information = _extract_field(r"Information:\s*([^\n]+)", output)
|
|
118
|
+
vuln_discuss = _extract_field(r"VulnDiscussion='([^']+)'\s", output)
|
|
119
|
+
result = _extract_field(r"Result:\s*([^\n]+)", output, flags=re.IGNORECASE)
|
|
120
|
+
# Extract solution using a safe pattern that avoids backtracking
|
|
121
|
+
# Split on reference keyword and take the solution section
|
|
122
|
+
if _SOLUTION_KEYWORD in output and _REFERENCE_INFO_KEYWORD in output:
|
|
123
|
+
solution_start = output.find(_SOLUTION_KEYWORD) + len(_SOLUTION_KEYWORD)
|
|
124
|
+
ref_start = output.find(_REFERENCE_INFO_KEYWORD, solution_start)
|
|
125
|
+
solution = output[solution_start:ref_start].strip()
|
|
126
|
+
elif _SOLUTION_KEYWORD in output:
|
|
127
|
+
solution_start = output.find(_SOLUTION_KEYWORD) + len(_SOLUTION_KEYWORD)
|
|
128
|
+
solution = output[solution_start:].strip()
|
|
129
|
+
else:
|
|
130
|
+
solution = ""
|
|
52
131
|
|
|
53
|
-
# Extract reference information
|
|
54
|
-
|
|
55
|
-
ref_dict = dict(item.split("|", 1) for item in ref_info.split(",") if "|" in item)
|
|
132
|
+
# Extract reference information using helper function
|
|
133
|
+
ref_dict = _extract_reference_dict(output)
|
|
56
134
|
|
|
57
135
|
# Extract specific references
|
|
58
|
-
cci_ref = ref_dict.get("CCI",
|
|
59
|
-
|
|
136
|
+
cci_ref = ref_dict.get("CCI", DEFAULT_CCI_REF)
|
|
137
|
+
severity_str = ref_dict.get("SEVERITY", "").lower()
|
|
60
138
|
oval_def = ref_dict.get("OVAL-DEF", "")
|
|
61
139
|
generated_date = ref_dict.get("GENERATED-DATE", "")
|
|
62
140
|
updated_date = ref_dict.get("UPDATED-DATE", "")
|
|
@@ -64,36 +142,19 @@ def parse_stig_output(output: str, finding: IntegrationFinding) -> IntegrationFi
|
|
|
64
142
|
rule_id_full = ref_dict.get("RULE-ID", "")
|
|
65
143
|
group_id = ref_dict.get("GROUP-ID", "")
|
|
66
144
|
|
|
145
|
+
# Extract vulnerability number
|
|
67
146
|
vuln_num_match = re.search(r"SV-\d+r\d+_rule", rule_id)
|
|
68
|
-
vuln_num = vuln_num_match.group(0) if vuln_num_match else
|
|
147
|
+
vuln_num = vuln_num_match.group(0) if vuln_num_match else UNKNOWN_VULN_NUM
|
|
69
148
|
|
|
70
149
|
title = f"{vuln_num}: {check_description}"
|
|
71
150
|
issue_title = title
|
|
72
151
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"FAILED": regscale_models.ChecklistStatus.FAIL,
|
|
76
|
-
"ERROR": regscale_models.ChecklistStatus.FAIL,
|
|
77
|
-
"NOT APPLICABLE": regscale_models.ChecklistStatus.NOT_APPLICABLE,
|
|
78
|
-
"NOT_APPLICABLE": regscale_models.ChecklistStatus.NOT_APPLICABLE,
|
|
79
|
-
}
|
|
152
|
+
# Map result to status using helper function
|
|
153
|
+
status = _map_result_to_status(result)
|
|
80
154
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
status = regscale_models.ChecklistStatus.NOT_REVIEWED
|
|
85
|
-
else:
|
|
86
|
-
status = status_map[result_key]
|
|
87
|
-
|
|
88
|
-
# Map severity to IssueSeverity enum
|
|
89
|
-
priority = (severity or "").title()
|
|
90
|
-
severity_map = {
|
|
91
|
-
"critical": regscale_models.IssueSeverity.Critical,
|
|
92
|
-
"high": regscale_models.IssueSeverity.High,
|
|
93
|
-
"medium": regscale_models.IssueSeverity.Moderate,
|
|
94
|
-
"low": regscale_models.IssueSeverity.Low,
|
|
95
|
-
}
|
|
96
|
-
severity = severity_map.get(severity.lower(), regscale_models.IssueSeverity.NotAssigned)
|
|
155
|
+
# Map severity to IssueSeverity enum using helper function
|
|
156
|
+
priority = (severity_str or "").title()
|
|
157
|
+
severity = _map_severity_to_enum(severity_str)
|
|
97
158
|
|
|
98
159
|
results = (
|
|
99
160
|
f"Vulnerability Number: {vuln_num}, Severity: {severity.value}, "
|
|
@@ -132,9 +193,4 @@ def parse_stig_output(output: str, finding: IntegrationFinding) -> IntegrationFi
|
|
|
132
193
|
finding.rule_id_full = rule_id_full
|
|
133
194
|
finding.group_id = group_id
|
|
134
195
|
|
|
135
|
-
# Future values
|
|
136
|
-
# finding.comments = ""
|
|
137
|
-
# finding.poam_comments = ""
|
|
138
|
-
# finding.rule_version = ""
|
|
139
|
-
|
|
140
196
|
return finding
|
|
@@ -5,7 +5,7 @@ from datetime import datetime, timedelta
|
|
|
5
5
|
from typing import Optional, Dict, Any, List
|
|
6
6
|
|
|
7
7
|
from regscale.core.app.utils.app_utils import error_and_exit, check_file_path
|
|
8
|
-
from regscale.integrations.commercial.wizv2.constants import CONTENT_TYPE
|
|
8
|
+
from regscale.integrations.commercial.wizv2.core.constants import CONTENT_TYPE
|
|
9
9
|
from regscale.core.app.application import Application
|
|
10
10
|
from regscale.utils import PaginatedGraphQLClient
|
|
11
11
|
|
|
@@ -25,7 +25,7 @@ def wiz():
|
|
|
25
25
|
@click.option("--client_secret", default=None, hide_input=True, required=False) # type: ignore
|
|
26
26
|
def authenticate(client_id, client_secret):
|
|
27
27
|
"""Authenticate to Wiz."""
|
|
28
|
-
from regscale.integrations.commercial.wizv2.
|
|
28
|
+
from regscale.integrations.commercial.wizv2.core.auth import wiz_authenticate
|
|
29
29
|
|
|
30
30
|
wiz_authenticate(client_id, client_secret)
|
|
31
31
|
|
|
@@ -45,7 +45,7 @@ def authenticate(client_id, client_secret):
|
|
|
45
45
|
"--client_id",
|
|
46
46
|
"-ci",
|
|
47
47
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
48
|
-
default=
|
|
48
|
+
default=None,
|
|
49
49
|
hide_input=False,
|
|
50
50
|
required=False,
|
|
51
51
|
)
|
|
@@ -53,7 +53,7 @@ def authenticate(client_id, client_secret):
|
|
|
53
53
|
"--client_secret",
|
|
54
54
|
"-cs",
|
|
55
55
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
56
|
-
default=
|
|
56
|
+
default=None,
|
|
57
57
|
hide_input=False,
|
|
58
58
|
required=False,
|
|
59
59
|
)
|
|
@@ -77,9 +77,9 @@ def inventory(
|
|
|
77
77
|
"""Process inventory from Wiz and create assets in RegScale."""
|
|
78
78
|
from regscale.integrations.commercial.wizv2.scanner import WizVulnerabilityIntegration
|
|
79
79
|
|
|
80
|
-
if
|
|
80
|
+
if client_secret is None:
|
|
81
81
|
client_secret = WizVariables.wizClientSecret
|
|
82
|
-
if
|
|
82
|
+
if client_id is None:
|
|
83
83
|
client_id = WizVariables.wizClientId
|
|
84
84
|
|
|
85
85
|
scanner = WizVulnerabilityIntegration(plan_id=regscale_ssp_id)
|
|
@@ -104,14 +104,14 @@ def inventory(
|
|
|
104
104
|
@click.option(
|
|
105
105
|
"--client_id",
|
|
106
106
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
107
|
-
default=
|
|
107
|
+
default=None,
|
|
108
108
|
hide_input=False,
|
|
109
109
|
required=False,
|
|
110
110
|
)
|
|
111
111
|
@click.option(
|
|
112
112
|
"--client_secret",
|
|
113
113
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
114
|
-
default=
|
|
114
|
+
default=None,
|
|
115
115
|
hide_input=True,
|
|
116
116
|
required=False,
|
|
117
117
|
)
|
|
@@ -136,13 +136,13 @@ def issues(
|
|
|
136
136
|
Process Issues from Wiz into RegScale
|
|
137
137
|
"""
|
|
138
138
|
from regscale.core.app.utils.app_utils import check_license
|
|
139
|
-
from regscale.integrations.commercial.wizv2.
|
|
139
|
+
from regscale.integrations.commercial.wizv2.core.auth import wiz_authenticate
|
|
140
140
|
from regscale.integrations.commercial.wizv2.issue import WizIssue
|
|
141
141
|
import json
|
|
142
142
|
|
|
143
|
-
if
|
|
143
|
+
if client_secret is None:
|
|
144
144
|
client_secret = WizVariables.wizClientSecret
|
|
145
|
-
if
|
|
145
|
+
if client_id is None:
|
|
146
146
|
client_id = WizVariables.wizClientId
|
|
147
147
|
|
|
148
148
|
check_license()
|
|
@@ -154,7 +154,7 @@ def issues(
|
|
|
154
154
|
scanner = WizIssue(plan_id=regscale_ssp_id)
|
|
155
155
|
scanner.sync_findings(
|
|
156
156
|
plan_id=regscale_ssp_id,
|
|
157
|
-
filter_by_override=
|
|
157
|
+
filter_by_override=filter_by, # Pass the processed dict with project ID
|
|
158
158
|
client_id=client_id, # type: ignore
|
|
159
159
|
client_secret=client_secret, # type: ignore
|
|
160
160
|
wiz_project_id=wiz_project_id,
|
|
@@ -166,7 +166,7 @@ def issues(
|
|
|
166
166
|
"--client_id",
|
|
167
167
|
"-ci",
|
|
168
168
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
169
|
-
default=
|
|
169
|
+
default=None,
|
|
170
170
|
hide_input=False,
|
|
171
171
|
required=False,
|
|
172
172
|
)
|
|
@@ -174,7 +174,7 @@ def issues(
|
|
|
174
174
|
"--client_secret",
|
|
175
175
|
"-cs",
|
|
176
176
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
177
|
-
default=
|
|
177
|
+
default=None,
|
|
178
178
|
hide_input=True,
|
|
179
179
|
required=False,
|
|
180
180
|
)
|
|
@@ -191,12 +191,12 @@ def attach_sbom(
|
|
|
191
191
|
standard="CycloneDX",
|
|
192
192
|
):
|
|
193
193
|
"""Download SBOMs from a Wiz report by ID and add them to the corresponding RegScale assets."""
|
|
194
|
-
from regscale.integrations.commercial.wizv2.
|
|
194
|
+
from regscale.integrations.commercial.wizv2.core.auth import wiz_authenticate
|
|
195
195
|
from regscale.integrations.commercial.wizv2.utils import fetch_sbom_report
|
|
196
196
|
|
|
197
|
-
if
|
|
197
|
+
if client_secret is None:
|
|
198
198
|
client_secret = WizVariables.wizClientSecret
|
|
199
|
-
if
|
|
199
|
+
if client_id is None:
|
|
200
200
|
client_id = WizVariables.wizClientId
|
|
201
201
|
|
|
202
202
|
wiz_authenticate(
|
|
@@ -212,15 +212,6 @@ def attach_sbom(
|
|
|
212
212
|
)
|
|
213
213
|
|
|
214
214
|
|
|
215
|
-
@wiz.command()
|
|
216
|
-
def threats():
|
|
217
|
-
"""Process threats from Wiz -> Coming soon"""
|
|
218
|
-
from regscale.core.app.utils.app_utils import check_license
|
|
219
|
-
|
|
220
|
-
check_license()
|
|
221
|
-
logger.info("Threats - COMING SOON")
|
|
222
|
-
|
|
223
|
-
|
|
224
215
|
@wiz.command()
|
|
225
216
|
@click.option( # type: ignore
|
|
226
217
|
"--wiz_project_id",
|
|
@@ -234,7 +225,7 @@ def threats():
|
|
|
234
225
|
"--client_id",
|
|
235
226
|
"-ci",
|
|
236
227
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
237
|
-
default=
|
|
228
|
+
default=None,
|
|
238
229
|
hide_input=False,
|
|
239
230
|
required=False,
|
|
240
231
|
)
|
|
@@ -242,7 +233,7 @@ def threats():
|
|
|
242
233
|
"--client_secret",
|
|
243
234
|
"-cs",
|
|
244
235
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
245
|
-
default=
|
|
236
|
+
default=None,
|
|
246
237
|
hide_input=True,
|
|
247
238
|
required=False,
|
|
248
239
|
)
|
|
@@ -266,9 +257,9 @@ def vulnerabilities(
|
|
|
266
257
|
"""Process vulnerabilities from Wiz"""
|
|
267
258
|
from regscale.integrations.commercial.wizv2.scanner import WizVulnerabilityIntegration
|
|
268
259
|
|
|
269
|
-
if
|
|
260
|
+
if client_secret is None:
|
|
270
261
|
client_secret = WizVariables.wizClientSecret
|
|
271
|
-
if
|
|
262
|
+
if client_id is None:
|
|
272
263
|
client_id = WizVariables.wizClientId
|
|
273
264
|
|
|
274
265
|
scanner = WizVulnerabilityIntegration(plan_id=regscale_ssp_id)
|
|
@@ -286,7 +277,7 @@ def vulnerabilities(
|
|
|
286
277
|
"--client_id",
|
|
287
278
|
"-ci",
|
|
288
279
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
289
|
-
default=
|
|
280
|
+
default=None,
|
|
290
281
|
hide_input=False,
|
|
291
282
|
required=False,
|
|
292
283
|
)
|
|
@@ -294,14 +285,18 @@ def vulnerabilities(
|
|
|
294
285
|
"--client_secret",
|
|
295
286
|
"-cs",
|
|
296
287
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
297
|
-
default=
|
|
288
|
+
default=None,
|
|
298
289
|
hide_input=True,
|
|
299
290
|
required=False,
|
|
300
291
|
)
|
|
301
292
|
@click.option("--evidence_id", "-e", help="Wiz Evidence ID", required=True, type=int) # type: ignore
|
|
302
293
|
@click.option("--report_id", "-r", help="Wiz Report ID", required=True) # type: ignore
|
|
303
|
-
@click.option(
|
|
304
|
-
|
|
294
|
+
@click.option(
|
|
295
|
+
"--report_file_name", "-n", help="Report file name", default="evidence_report", required=False
|
|
296
|
+
) # type: ignore
|
|
297
|
+
@click.option(
|
|
298
|
+
"--report_file_extension", "-e", help="Report file extension", default="csv", required=False
|
|
299
|
+
) # type: ignore
|
|
305
300
|
def add_report_evidence(
|
|
306
301
|
client_id,
|
|
307
302
|
client_secret,
|
|
@@ -311,12 +306,12 @@ def add_report_evidence(
|
|
|
311
306
|
report_file_extension: str = "csv",
|
|
312
307
|
):
|
|
313
308
|
"""Download a Wiz report by ID and Attach to Evidence locker"""
|
|
314
|
-
from regscale.integrations.commercial.wizv2.
|
|
309
|
+
from regscale.integrations.commercial.wizv2.core.auth import wiz_authenticate
|
|
315
310
|
from regscale.integrations.commercial.wizv2.utils import fetch_report_by_id
|
|
316
311
|
|
|
317
|
-
if
|
|
312
|
+
if client_secret is None:
|
|
318
313
|
client_secret = WizVariables.wizClientSecret
|
|
319
|
-
if
|
|
314
|
+
if client_id is None:
|
|
320
315
|
client_id = WizVariables.wizClientId
|
|
321
316
|
|
|
322
317
|
wiz_authenticate(
|
|
@@ -324,11 +319,18 @@ def add_report_evidence(
|
|
|
324
319
|
client_secret=client_secret,
|
|
325
320
|
)
|
|
326
321
|
fetch_report_by_id(
|
|
327
|
-
report_id,
|
|
322
|
+
report_id,
|
|
323
|
+
parent_id=evidence_id,
|
|
324
|
+
report_file_name=report_file_name,
|
|
325
|
+
report_file_extension=report_file_extension,
|
|
328
326
|
)
|
|
329
327
|
|
|
330
328
|
|
|
331
|
-
@wiz.command(
|
|
329
|
+
@wiz.command(
|
|
330
|
+
"sync_compliance",
|
|
331
|
+
deprecated=True,
|
|
332
|
+
help="[BETA] This command shows an experimental feature. Use with caution. Use compliance report instead for Compliance sync from Wiz.",
|
|
333
|
+
)
|
|
332
334
|
@click.option( # type: ignore
|
|
333
335
|
"--wiz_project_id",
|
|
334
336
|
"-p",
|
|
@@ -342,7 +344,7 @@ def add_report_evidence(
|
|
|
342
344
|
"--client_id",
|
|
343
345
|
"-i",
|
|
344
346
|
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
345
|
-
default=
|
|
347
|
+
default=None,
|
|
346
348
|
hide_input=False,
|
|
347
349
|
required=False,
|
|
348
350
|
)
|
|
@@ -350,14 +352,17 @@ def add_report_evidence(
|
|
|
350
352
|
"--client_secret",
|
|
351
353
|
"-s",
|
|
352
354
|
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
353
|
-
default=
|
|
355
|
+
default=None,
|
|
354
356
|
hide_input=True,
|
|
355
357
|
required=False,
|
|
356
358
|
)
|
|
357
359
|
@click.option( # type: ignore
|
|
358
360
|
"--framework_id",
|
|
359
361
|
"-f",
|
|
360
|
-
help=
|
|
362
|
+
help=(
|
|
363
|
+
"Wiz framework ID or shorthand (e.g., 'nist', 'aws', 'wf-id-4'). "
|
|
364
|
+
"Use --list-frameworks to see options. Default: wf-id-4 (NIST SP 800-53 Rev 5)"
|
|
365
|
+
),
|
|
361
366
|
default="wf-id-4",
|
|
362
367
|
required=False,
|
|
363
368
|
)
|
|
@@ -416,63 +421,173 @@ def sync_compliance(
|
|
|
416
421
|
"""
|
|
417
422
|
Sync policy compliance assessments from Wiz to RegScale.
|
|
418
423
|
|
|
419
|
-
This command
|
|
424
|
+
This command now uses CSV compliance reports from Wiz instead of GraphQL API.
|
|
425
|
+
It creates:
|
|
420
426
|
- Control assessments based on policy compliance results
|
|
421
427
|
- Issues for failed policy assessments (if --create-issues enabled)
|
|
422
428
|
- Updates to control implementation status (if --update-control-status enabled)
|
|
423
|
-
- JSON output file with policy compliance data in artifacts/wiz/ directory
|
|
424
|
-
- Cached framework mapping for improved performance
|
|
425
429
|
|
|
426
|
-
|
|
427
|
-
By default, the command will reuse cached policy data if it's newer than the cache
|
|
428
|
-
duration (default: 60 minutes). Use --refresh to force fresh data from Wiz.
|
|
429
|
-
Use --cache-duration to adjust how long cached data is considered valid.
|
|
430
|
+
NOTE: This command is deprecated. Use 'compliance_report' command instead.
|
|
430
431
|
"""
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
list_available_frameworks,
|
|
434
|
-
resolve_framework_id,
|
|
435
|
-
)
|
|
432
|
+
click.echo("⚠️ sync_compliance is deprecated and now uses compliance_report implementation.")
|
|
433
|
+
click.echo(" Consider using 'regscale wiz compliance_report' directly for future use.\n")
|
|
436
434
|
|
|
437
|
-
# Handle --list-frameworks flag
|
|
435
|
+
# Handle --list-frameworks flag (no longer supported, inform user)
|
|
438
436
|
if list_frameworks:
|
|
439
|
-
click.echo(
|
|
437
|
+
click.echo("❌ --list-frameworks is no longer supported in the deprecated sync_compliance command.")
|
|
438
|
+
click.echo(" Please use 'regscale wiz compliance_report' instead.\n")
|
|
440
439
|
return
|
|
441
440
|
|
|
442
441
|
# Use environment variables if not provided
|
|
443
|
-
if
|
|
442
|
+
if client_secret is None or client_secret == "":
|
|
444
443
|
client_secret = WizVariables.wizClientSecret
|
|
445
|
-
if
|
|
444
|
+
if client_id is None or client_id == "":
|
|
446
445
|
client_id = WizVariables.wizClientId
|
|
447
446
|
|
|
448
|
-
#
|
|
449
|
-
|
|
450
|
-
resolved_framework_id = resolve_framework_id(framework_id.lower())
|
|
451
|
-
if resolved_framework_id != framework_id:
|
|
452
|
-
from regscale.integrations.commercial.wizv2.policy_compliance import FRAMEWORK_MAPPINGS
|
|
453
|
-
|
|
454
|
-
framework_name = FRAMEWORK_MAPPINGS.get(resolved_framework_id, resolved_framework_id)
|
|
455
|
-
click.echo(f"🔍 Resolved '{framework_id}' to '{framework_name}' ({resolved_framework_id})")
|
|
456
|
-
except ValueError as e:
|
|
457
|
-
click.echo(f"❌ {str(e)}")
|
|
458
|
-
click.echo("\nUse --list-frameworks to see all available options.")
|
|
459
|
-
return
|
|
447
|
+
# Import compliance_report processor instead of GraphQL-based integration
|
|
448
|
+
from regscale.integrations.commercial.wizv2.compliance_report import WizComplianceReportProcessor
|
|
460
449
|
|
|
461
|
-
# Create
|
|
462
|
-
|
|
450
|
+
# Create processor with similar options to compliance_report command
|
|
451
|
+
processor = WizComplianceReportProcessor(
|
|
463
452
|
plan_id=regscale_id,
|
|
464
453
|
wiz_project_id=wiz_project_id,
|
|
465
454
|
client_id=client_id,
|
|
466
455
|
client_secret=client_secret,
|
|
467
|
-
framework_id=resolved_framework_id,
|
|
468
456
|
regscale_module=regscale_module,
|
|
469
457
|
create_poams=create_poams,
|
|
470
|
-
|
|
471
|
-
|
|
458
|
+
create_issues=create_issues,
|
|
459
|
+
update_control_status=update_control_status,
|
|
460
|
+
report_file_path=None, # Will create new report
|
|
461
|
+
force_fresh_report=refresh, # Map --refresh to force_fresh_report
|
|
462
|
+
reuse_existing_reports=not refresh, # Inverse of refresh
|
|
463
|
+
bypass_control_filtering=True, # Enable for performance
|
|
472
464
|
)
|
|
473
465
|
|
|
474
|
-
#
|
|
475
|
-
|
|
466
|
+
# Process the compliance report using new ComplianceIntegration pattern
|
|
467
|
+
processor.process_compliance_sync()
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
@wiz.command(name="compliance_report")
|
|
471
|
+
@click.option(
|
|
472
|
+
"--wiz_project_id",
|
|
473
|
+
"-p",
|
|
474
|
+
prompt="Enter the Wiz project ID",
|
|
475
|
+
help="Enter the Wiz Project ID for compliance report processing.",
|
|
476
|
+
required=True,
|
|
477
|
+
)
|
|
478
|
+
@regscale_id(help="RegScale will create and update control assessments as children of this record.")
|
|
479
|
+
@regscale_module(required=True, default="securityplans", prompt=False)
|
|
480
|
+
@click.option(
|
|
481
|
+
"--client_id",
|
|
482
|
+
"-i",
|
|
483
|
+
help="Wiz Client ID, or can be set as environment variable wizClientId",
|
|
484
|
+
default=None,
|
|
485
|
+
hide_input=False,
|
|
486
|
+
required=False,
|
|
487
|
+
)
|
|
488
|
+
@click.option(
|
|
489
|
+
"--client_secret",
|
|
490
|
+
"-s",
|
|
491
|
+
help="Wiz Client Secret, or can be set as environment variable wizClientSecret",
|
|
492
|
+
default=None,
|
|
493
|
+
hide_input=True,
|
|
494
|
+
required=False,
|
|
495
|
+
)
|
|
496
|
+
@click.option(
|
|
497
|
+
"--report_file_path",
|
|
498
|
+
"-f",
|
|
499
|
+
help="Path to existing CSV compliance report file (optional - will create new report if not provided)",
|
|
500
|
+
default=None,
|
|
501
|
+
required=False,
|
|
502
|
+
)
|
|
503
|
+
@click.option(
|
|
504
|
+
"--create-issues/--no-create-issues",
|
|
505
|
+
"-ci/-ni",
|
|
506
|
+
default=True,
|
|
507
|
+
help="Create issues for failed compliance assessments (default: enabled)",
|
|
508
|
+
)
|
|
509
|
+
@click.option(
|
|
510
|
+
"--update-control-status/--no-update-control-status",
|
|
511
|
+
"-ucs/-nucs",
|
|
512
|
+
default=True,
|
|
513
|
+
help="Update control implementation status based on assessment results (default: enabled)",
|
|
514
|
+
)
|
|
515
|
+
@click.option(
|
|
516
|
+
"--create-poams/--no-create-poams",
|
|
517
|
+
"-cp/-ncp",
|
|
518
|
+
default=False,
|
|
519
|
+
help="Mark created issues as POAMs (default: disabled)",
|
|
520
|
+
)
|
|
521
|
+
@click.option(
|
|
522
|
+
"--reuse-existing-reports/--no-reuse-existing-reports",
|
|
523
|
+
"-rer/-nrer",
|
|
524
|
+
default=True,
|
|
525
|
+
help="Reuse existing Wiz compliance reports instead of creating new ones (default: enabled)",
|
|
526
|
+
)
|
|
527
|
+
@click.option(
|
|
528
|
+
"--force-fresh-report/--no-force-fresh-report",
|
|
529
|
+
"-ffr/-nffr",
|
|
530
|
+
default=False,
|
|
531
|
+
help="Force creation of a fresh compliance report, ignoring existing reports (default: disabled)",
|
|
532
|
+
)
|
|
533
|
+
def compliance_report(
|
|
534
|
+
wiz_project_id,
|
|
535
|
+
regscale_id,
|
|
536
|
+
regscale_module,
|
|
537
|
+
client_id,
|
|
538
|
+
client_secret,
|
|
539
|
+
report_file_path,
|
|
540
|
+
create_issues,
|
|
541
|
+
update_control_status,
|
|
542
|
+
create_poams,
|
|
543
|
+
reuse_existing_reports,
|
|
544
|
+
force_fresh_report,
|
|
545
|
+
):
|
|
546
|
+
"""
|
|
547
|
+
Process Wiz compliance reports and create assessments in RegScale.
|
|
548
|
+
|
|
549
|
+
This command can either:
|
|
550
|
+
1. Create a new compliance report from Wiz and process it
|
|
551
|
+
2. Process an existing compliance report CSV file
|
|
552
|
+
|
|
553
|
+
The command will:
|
|
554
|
+
- Parse compliance assessment data from CSV format
|
|
555
|
+
- Create control assessments based on compliance results
|
|
556
|
+
- Create issues for failed compliance assessments (if --create-issues enabled)
|
|
557
|
+
- Update control implementation status (if --update-control-status enabled)
|
|
558
|
+
- Support POAM creation for compliance issues
|
|
559
|
+
|
|
560
|
+
REPORT MANAGEMENT:
|
|
561
|
+
By default, the command will look for existing compliance reports in Wiz for the
|
|
562
|
+
specified project and rerun them instead of creating new ones. This prevents the
|
|
563
|
+
accumulation of duplicate reports in Wiz. Use --no-reuse-existing-reports to
|
|
564
|
+
always create new reports, or --force-fresh-report to force a new report even
|
|
565
|
+
when reuse is enabled.
|
|
566
|
+
"""
|
|
567
|
+
from regscale.integrations.commercial.wizv2.compliance_report import WizComplianceReportProcessor
|
|
568
|
+
|
|
569
|
+
# Use environment variables if not provided or empty
|
|
570
|
+
if not client_secret:
|
|
571
|
+
client_secret = WizVariables.wizClientSecret
|
|
572
|
+
if not client_id:
|
|
573
|
+
client_id = WizVariables.wizClientId
|
|
574
|
+
|
|
575
|
+
# Create and run the compliance report processor
|
|
576
|
+
# Enable bypass_control_filtering by default for performance with large control sets
|
|
577
|
+
processor = WizComplianceReportProcessor(
|
|
578
|
+
plan_id=regscale_id,
|
|
579
|
+
wiz_project_id=wiz_project_id,
|
|
580
|
+
client_id=client_id,
|
|
581
|
+
client_secret=client_secret,
|
|
582
|
+
regscale_module=regscale_module,
|
|
583
|
+
create_poams=create_poams,
|
|
476
584
|
create_issues=create_issues,
|
|
477
585
|
update_control_status=update_control_status,
|
|
586
|
+
report_file_path=report_file_path,
|
|
587
|
+
bypass_control_filtering=True, # Bypass filtering for performance with large control sets
|
|
588
|
+
reuse_existing_reports=reuse_existing_reports,
|
|
589
|
+
force_fresh_report=force_fresh_report,
|
|
478
590
|
)
|
|
591
|
+
|
|
592
|
+
# Process the compliance report using new ComplianceIntegration pattern
|
|
593
|
+
processor.process_compliance_sync()
|