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,851 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Comprehensive tests for Wiz Click command handlers with focus on uncovered lines."""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from click.testing import CliRunner
|
|
7
|
+
from unittest.mock import patch, MagicMock
|
|
8
|
+
from regscale.integrations.commercial.wizv2.click import wiz
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestWizClickComprehensive:
|
|
12
|
+
"""Comprehensive tests for Wiz CLI commands focusing on uncovered lines."""
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def runner(self):
|
|
16
|
+
"""Create a Click test runner."""
|
|
17
|
+
return CliRunner()
|
|
18
|
+
|
|
19
|
+
@pytest.fixture
|
|
20
|
+
def mock_wiz_variables(self):
|
|
21
|
+
"""Mock WizVariables to avoid environment dependencies."""
|
|
22
|
+
with patch("regscale.integrations.commercial.wizv2.click.WizVariables") as mock:
|
|
23
|
+
mock.wizClientId = "env_client_id"
|
|
24
|
+
mock.wizClientSecret = "env_client_secret"
|
|
25
|
+
mock.wizInventoryFilterBy = "{}"
|
|
26
|
+
mock.wizIssueFilterBy = "{}"
|
|
27
|
+
yield mock
|
|
28
|
+
|
|
29
|
+
# ========================================
|
|
30
|
+
# Test authenticate command (lines 28-30)
|
|
31
|
+
# ========================================
|
|
32
|
+
|
|
33
|
+
def test_authenticate_with_provided_credentials(self, runner, mock_wiz_variables):
|
|
34
|
+
"""Test authenticate command with provided client_id and client_secret."""
|
|
35
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
36
|
+
mock_auth.return_value = "test_token"
|
|
37
|
+
|
|
38
|
+
result = runner.invoke(
|
|
39
|
+
wiz,
|
|
40
|
+
[
|
|
41
|
+
"authenticate",
|
|
42
|
+
"--client_id",
|
|
43
|
+
"test_client_id",
|
|
44
|
+
"--client_secret",
|
|
45
|
+
"test_secret",
|
|
46
|
+
],
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Verify wiz_authenticate was called with the provided credentials
|
|
50
|
+
mock_auth.assert_called_once_with("test_client_id", "test_secret")
|
|
51
|
+
assert result.exit_code == 0
|
|
52
|
+
|
|
53
|
+
def test_authenticate_without_credentials(self, runner, mock_wiz_variables):
|
|
54
|
+
"""Test authenticate command without providing credentials (uses env vars)."""
|
|
55
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
56
|
+
mock_auth.return_value = "test_token"
|
|
57
|
+
|
|
58
|
+
result = runner.invoke(wiz, ["authenticate"])
|
|
59
|
+
|
|
60
|
+
# Verify wiz_authenticate was called with None values (will use env vars internally)
|
|
61
|
+
mock_auth.assert_called_once_with(None, None)
|
|
62
|
+
assert result.exit_code == 0
|
|
63
|
+
|
|
64
|
+
# ========================================
|
|
65
|
+
# Test issues command (lines 143-146)
|
|
66
|
+
# ========================================
|
|
67
|
+
|
|
68
|
+
@pytest.fixture
|
|
69
|
+
def mock_wiz_issue(self):
|
|
70
|
+
"""Mock the WizIssue scanner."""
|
|
71
|
+
with patch("regscale.integrations.commercial.wizv2.issue.WizIssue") as mock:
|
|
72
|
+
instance = MagicMock()
|
|
73
|
+
mock.return_value = instance
|
|
74
|
+
yield instance
|
|
75
|
+
|
|
76
|
+
@pytest.fixture
|
|
77
|
+
def mock_wiz_auth(self):
|
|
78
|
+
"""Mock wiz_authenticate."""
|
|
79
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock:
|
|
80
|
+
yield mock
|
|
81
|
+
|
|
82
|
+
@pytest.fixture
|
|
83
|
+
def mock_check_license(self):
|
|
84
|
+
"""Mock check_license."""
|
|
85
|
+
with patch("regscale.core.app.utils.app_utils.check_license") as mock:
|
|
86
|
+
yield mock
|
|
87
|
+
|
|
88
|
+
def test_issues_with_none_client_secret(
|
|
89
|
+
self,
|
|
90
|
+
runner,
|
|
91
|
+
mock_wiz_variables,
|
|
92
|
+
mock_wiz_issue,
|
|
93
|
+
mock_wiz_auth,
|
|
94
|
+
mock_check_license,
|
|
95
|
+
):
|
|
96
|
+
"""Test issues command when client_secret is None (line 143-144)."""
|
|
97
|
+
result = runner.invoke(
|
|
98
|
+
wiz,
|
|
99
|
+
[
|
|
100
|
+
"issues",
|
|
101
|
+
"--wiz_project_id",
|
|
102
|
+
"test-project",
|
|
103
|
+
"--regscale_ssp_id",
|
|
104
|
+
"2288",
|
|
105
|
+
# Not providing client_secret, so it will be None and use env var
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Check that the command ran
|
|
110
|
+
assert result.exit_code == 0 or "successfully" in result.output.lower()
|
|
111
|
+
|
|
112
|
+
# Verify that wiz_authenticate was called with env credentials
|
|
113
|
+
mock_wiz_auth.assert_called_once_with("env_client_id", "env_client_secret")
|
|
114
|
+
|
|
115
|
+
def test_issues_with_none_client_id(
|
|
116
|
+
self,
|
|
117
|
+
runner,
|
|
118
|
+
mock_wiz_variables,
|
|
119
|
+
mock_wiz_issue,
|
|
120
|
+
mock_wiz_auth,
|
|
121
|
+
mock_check_license,
|
|
122
|
+
):
|
|
123
|
+
"""Test issues command when client_id is None (line 145-146)."""
|
|
124
|
+
result = runner.invoke(
|
|
125
|
+
wiz,
|
|
126
|
+
[
|
|
127
|
+
"issues",
|
|
128
|
+
"--wiz_project_id",
|
|
129
|
+
"test-project",
|
|
130
|
+
"--regscale_ssp_id",
|
|
131
|
+
"2288",
|
|
132
|
+
"--client_secret",
|
|
133
|
+
"provided_secret",
|
|
134
|
+
# Not providing client_id, so it will be None and use env var
|
|
135
|
+
],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Check that the command ran
|
|
139
|
+
assert result.exit_code == 0 or "successfully" in result.output.lower()
|
|
140
|
+
|
|
141
|
+
# Verify that wiz_authenticate was called with env client_id
|
|
142
|
+
mock_wiz_auth.assert_called_once_with("env_client_id", "provided_secret")
|
|
143
|
+
|
|
144
|
+
# ========================================
|
|
145
|
+
# Test attach_sbom command (lines 194-206)
|
|
146
|
+
# ========================================
|
|
147
|
+
|
|
148
|
+
def test_attach_sbom_with_none_client_secret(self, runner, mock_wiz_variables):
|
|
149
|
+
"""Test attach_sbom command when client_secret is None (lines 197-198)."""
|
|
150
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
151
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_sbom_report") as mock_fetch:
|
|
152
|
+
mock_auth.return_value = "test_token"
|
|
153
|
+
mock_fetch.return_value = None
|
|
154
|
+
|
|
155
|
+
result = runner.invoke(
|
|
156
|
+
wiz,
|
|
157
|
+
[
|
|
158
|
+
"attach_sbom",
|
|
159
|
+
"--regscale_ssp_id",
|
|
160
|
+
"2288",
|
|
161
|
+
"--report_id",
|
|
162
|
+
"test-report-id",
|
|
163
|
+
# Not providing client_secret
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Verify wiz_authenticate was called with env secret
|
|
168
|
+
mock_auth.assert_called_once_with(
|
|
169
|
+
client_id="env_client_id",
|
|
170
|
+
client_secret="env_client_secret",
|
|
171
|
+
)
|
|
172
|
+
assert result.exit_code == 0 or "report" in result.output.lower()
|
|
173
|
+
|
|
174
|
+
def test_attach_sbom_with_none_client_id(self, runner, mock_wiz_variables):
|
|
175
|
+
"""Test attach_sbom command when client_id is None (lines 199-200)."""
|
|
176
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
177
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_sbom_report") as mock_fetch:
|
|
178
|
+
mock_auth.return_value = "test_token"
|
|
179
|
+
mock_fetch.return_value = None
|
|
180
|
+
|
|
181
|
+
result = runner.invoke(
|
|
182
|
+
wiz,
|
|
183
|
+
[
|
|
184
|
+
"attach_sbom",
|
|
185
|
+
"--regscale_ssp_id",
|
|
186
|
+
"2288",
|
|
187
|
+
"--report_id",
|
|
188
|
+
"test-report-id",
|
|
189
|
+
"--client_secret",
|
|
190
|
+
"provided_secret",
|
|
191
|
+
# Not providing client_id
|
|
192
|
+
],
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Verify wiz_authenticate was called with env client_id
|
|
196
|
+
mock_auth.assert_called_once_with(
|
|
197
|
+
client_id="env_client_id",
|
|
198
|
+
client_secret="provided_secret",
|
|
199
|
+
)
|
|
200
|
+
assert result.exit_code == 0 or "report" in result.output.lower()
|
|
201
|
+
|
|
202
|
+
def test_attach_sbom_full_flow(self, runner, mock_wiz_variables):
|
|
203
|
+
"""Test attach_sbom command full flow (lines 202-212)."""
|
|
204
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
205
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_sbom_report") as mock_fetch:
|
|
206
|
+
mock_auth.return_value = "test_token"
|
|
207
|
+
mock_fetch.return_value = None
|
|
208
|
+
|
|
209
|
+
result = runner.invoke(
|
|
210
|
+
wiz,
|
|
211
|
+
[
|
|
212
|
+
"attach_sbom",
|
|
213
|
+
"--client_id",
|
|
214
|
+
"test_client",
|
|
215
|
+
"--client_secret",
|
|
216
|
+
"test_secret",
|
|
217
|
+
"--regscale_ssp_id",
|
|
218
|
+
"2288",
|
|
219
|
+
"--report_id",
|
|
220
|
+
"test-report-id",
|
|
221
|
+
"--standard",
|
|
222
|
+
"SPDX",
|
|
223
|
+
],
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# Verify fetch_sbom_report was called with correct parameters
|
|
227
|
+
mock_fetch.assert_called_once_with(
|
|
228
|
+
"test-report-id",
|
|
229
|
+
parent_id=2288, # parent_id is an integer from click
|
|
230
|
+
report_file_name="sbom_report",
|
|
231
|
+
report_file_extension="zip",
|
|
232
|
+
standard="SPDX",
|
|
233
|
+
)
|
|
234
|
+
assert result.exit_code == 0
|
|
235
|
+
|
|
236
|
+
# ========================================
|
|
237
|
+
# Test vulnerabilities command (lines 261-264)
|
|
238
|
+
# ========================================
|
|
239
|
+
|
|
240
|
+
@pytest.fixture
|
|
241
|
+
def mock_scanner(self):
|
|
242
|
+
"""Mock the WizVulnerabilityIntegration scanner."""
|
|
243
|
+
with patch("regscale.integrations.commercial.wizv2.scanner.WizVulnerabilityIntegration") as mock:
|
|
244
|
+
instance = MagicMock()
|
|
245
|
+
mock.return_value = instance
|
|
246
|
+
yield instance
|
|
247
|
+
|
|
248
|
+
def test_vulnerabilities_with_none_client_secret(self, runner, mock_wiz_variables, mock_scanner):
|
|
249
|
+
"""Test vulnerabilities command when client_secret is None (lines 261-262)."""
|
|
250
|
+
result = runner.invoke(
|
|
251
|
+
wiz,
|
|
252
|
+
[
|
|
253
|
+
"vulnerabilities",
|
|
254
|
+
"--wiz_project_id",
|
|
255
|
+
"test-project",
|
|
256
|
+
"--regscale_ssp_id",
|
|
257
|
+
"2288",
|
|
258
|
+
# Not providing client_secret
|
|
259
|
+
],
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Check that the command ran
|
|
263
|
+
assert result.exit_code == 0 or "successfully" in result.output.lower()
|
|
264
|
+
|
|
265
|
+
# Verify that sync_findings was called with env credentials
|
|
266
|
+
mock_scanner.sync_findings.assert_called_once()
|
|
267
|
+
call_kwargs = mock_scanner.sync_findings.call_args[1]
|
|
268
|
+
assert call_kwargs["client_secret"] == "env_client_secret"
|
|
269
|
+
|
|
270
|
+
def test_vulnerabilities_with_none_client_id(self, runner, mock_wiz_variables, mock_scanner):
|
|
271
|
+
"""Test vulnerabilities command when client_id is None (lines 263-264)."""
|
|
272
|
+
result = runner.invoke(
|
|
273
|
+
wiz,
|
|
274
|
+
[
|
|
275
|
+
"vulnerabilities",
|
|
276
|
+
"--wiz_project_id",
|
|
277
|
+
"test-project",
|
|
278
|
+
"--regscale_ssp_id",
|
|
279
|
+
"2288",
|
|
280
|
+
"--client_secret",
|
|
281
|
+
"provided_secret",
|
|
282
|
+
# Not providing client_id
|
|
283
|
+
],
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Check that the command ran
|
|
287
|
+
assert result.exit_code == 0 or "successfully" in result.output.lower()
|
|
288
|
+
|
|
289
|
+
# Verify that sync_findings was called with env client_id
|
|
290
|
+
mock_scanner.sync_findings.assert_called_once()
|
|
291
|
+
call_kwargs = mock_scanner.sync_findings.call_args[1]
|
|
292
|
+
assert call_kwargs["client_id"] == "env_client_id"
|
|
293
|
+
|
|
294
|
+
# ========================================
|
|
295
|
+
# Test add_report_evidence command (lines 310-322)
|
|
296
|
+
# ========================================
|
|
297
|
+
|
|
298
|
+
def test_add_report_evidence_with_none_client_secret(self, runner, mock_wiz_variables):
|
|
299
|
+
"""Test add_report_evidence command when client_secret is None (lines 313-314)."""
|
|
300
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
301
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_report_by_id") as mock_fetch:
|
|
302
|
+
mock_auth.return_value = "test_token"
|
|
303
|
+
mock_fetch.return_value = None
|
|
304
|
+
|
|
305
|
+
result = runner.invoke(
|
|
306
|
+
wiz,
|
|
307
|
+
[
|
|
308
|
+
"add_report_evidence",
|
|
309
|
+
"--evidence_id",
|
|
310
|
+
"123",
|
|
311
|
+
"--report_id",
|
|
312
|
+
"test-report-id",
|
|
313
|
+
# Not providing client_secret
|
|
314
|
+
],
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# Verify wiz_authenticate was called with env secret
|
|
318
|
+
mock_auth.assert_called_once_with(
|
|
319
|
+
client_id="env_client_id",
|
|
320
|
+
client_secret="env_client_secret",
|
|
321
|
+
)
|
|
322
|
+
assert result.exit_code == 0 or "report" in result.output.lower()
|
|
323
|
+
|
|
324
|
+
def test_add_report_evidence_with_none_client_id(self, runner, mock_wiz_variables):
|
|
325
|
+
"""Test add_report_evidence command when client_id is None (lines 315-316)."""
|
|
326
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
327
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_report_by_id") as mock_fetch:
|
|
328
|
+
mock_auth.return_value = "test_token"
|
|
329
|
+
mock_fetch.return_value = None
|
|
330
|
+
|
|
331
|
+
result = runner.invoke(
|
|
332
|
+
wiz,
|
|
333
|
+
[
|
|
334
|
+
"add_report_evidence",
|
|
335
|
+
"--evidence_id",
|
|
336
|
+
"123",
|
|
337
|
+
"--report_id",
|
|
338
|
+
"test-report-id",
|
|
339
|
+
"--client_secret",
|
|
340
|
+
"provided_secret",
|
|
341
|
+
# Not providing client_id
|
|
342
|
+
],
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# Verify wiz_authenticate was called with env client_id
|
|
346
|
+
mock_auth.assert_called_once_with(
|
|
347
|
+
client_id="env_client_id",
|
|
348
|
+
client_secret="provided_secret",
|
|
349
|
+
)
|
|
350
|
+
assert result.exit_code == 0 or "report" in result.output.lower()
|
|
351
|
+
|
|
352
|
+
def test_add_report_evidence_full_flow(self, runner, mock_wiz_variables):
|
|
353
|
+
"""Test add_report_evidence command full flow (lines 318-327)."""
|
|
354
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
355
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_report_by_id") as mock_fetch:
|
|
356
|
+
mock_auth.return_value = "test_token"
|
|
357
|
+
mock_fetch.return_value = None
|
|
358
|
+
|
|
359
|
+
result = runner.invoke(
|
|
360
|
+
wiz,
|
|
361
|
+
[
|
|
362
|
+
"add_report_evidence",
|
|
363
|
+
"--client_id",
|
|
364
|
+
"test_client",
|
|
365
|
+
"--client_secret",
|
|
366
|
+
"test_secret",
|
|
367
|
+
"--evidence_id",
|
|
368
|
+
"456",
|
|
369
|
+
"--report_id",
|
|
370
|
+
"report-789",
|
|
371
|
+
"--report_file_name",
|
|
372
|
+
"custom_report",
|
|
373
|
+
"--report_file_extension",
|
|
374
|
+
"xlsx",
|
|
375
|
+
],
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Verify fetch_report_by_id was called with correct parameters
|
|
379
|
+
mock_fetch.assert_called_once_with(
|
|
380
|
+
"report-789",
|
|
381
|
+
parent_id=456,
|
|
382
|
+
report_file_name="custom_report",
|
|
383
|
+
report_file_extension="xlsx",
|
|
384
|
+
)
|
|
385
|
+
assert result.exit_code == 0
|
|
386
|
+
|
|
387
|
+
# ========================================
|
|
388
|
+
# Test sync_compliance command (lines 433-468)
|
|
389
|
+
# ========================================
|
|
390
|
+
|
|
391
|
+
def test_sync_compliance_list_frameworks_flag(self, runner, mock_wiz_variables):
|
|
392
|
+
"""Test sync_compliance command with --list-frameworks flag (lines 437-440)."""
|
|
393
|
+
result = runner.invoke(
|
|
394
|
+
wiz,
|
|
395
|
+
[
|
|
396
|
+
"sync_compliance",
|
|
397
|
+
"--wiz_project_id",
|
|
398
|
+
"test-project",
|
|
399
|
+
"--regscale_id",
|
|
400
|
+
"123",
|
|
401
|
+
"--list-frameworks",
|
|
402
|
+
],
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# Should output deprecation message and list-frameworks not supported message
|
|
406
|
+
assert "sync_compliance is deprecated" in result.output
|
|
407
|
+
assert "list-frameworks is no longer supported" in result.output
|
|
408
|
+
assert result.exit_code == 0
|
|
409
|
+
|
|
410
|
+
def test_sync_compliance_with_none_or_empty_client_secret(self, runner, mock_wiz_variables):
|
|
411
|
+
"""Test sync_compliance when client_secret is None or empty (lines 443-444)."""
|
|
412
|
+
with patch(
|
|
413
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
414
|
+
) as mock_processor:
|
|
415
|
+
mock_instance = MagicMock()
|
|
416
|
+
mock_processor.return_value = mock_instance
|
|
417
|
+
|
|
418
|
+
result = runner.invoke(
|
|
419
|
+
wiz,
|
|
420
|
+
[
|
|
421
|
+
"sync_compliance",
|
|
422
|
+
"--wiz_project_id",
|
|
423
|
+
"test-project",
|
|
424
|
+
"--regscale_id",
|
|
425
|
+
"123",
|
|
426
|
+
# Not providing client_secret
|
|
427
|
+
],
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
# Verify processor was created with env credentials
|
|
431
|
+
mock_processor.assert_called_once()
|
|
432
|
+
call_kwargs = mock_processor.call_args[1]
|
|
433
|
+
assert call_kwargs["client_secret"] == "env_client_secret"
|
|
434
|
+
assert result.exit_code == 0
|
|
435
|
+
|
|
436
|
+
def test_sync_compliance_with_empty_string_client_secret(self, runner, mock_wiz_variables):
|
|
437
|
+
"""Test sync_compliance when client_secret is empty string (lines 443-444)."""
|
|
438
|
+
with patch(
|
|
439
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
440
|
+
) as mock_processor:
|
|
441
|
+
mock_instance = MagicMock()
|
|
442
|
+
mock_processor.return_value = mock_instance
|
|
443
|
+
|
|
444
|
+
result = runner.invoke(
|
|
445
|
+
wiz,
|
|
446
|
+
[
|
|
447
|
+
"sync_compliance",
|
|
448
|
+
"--wiz_project_id",
|
|
449
|
+
"test-project",
|
|
450
|
+
"--regscale_id",
|
|
451
|
+
"123",
|
|
452
|
+
"--client_secret",
|
|
453
|
+
"", # Empty string
|
|
454
|
+
],
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
# Verify processor was created with env credentials
|
|
458
|
+
mock_processor.assert_called_once()
|
|
459
|
+
call_kwargs = mock_processor.call_args[1]
|
|
460
|
+
assert call_kwargs["client_secret"] == "env_client_secret"
|
|
461
|
+
assert result.exit_code == 0
|
|
462
|
+
|
|
463
|
+
def test_sync_compliance_with_none_or_empty_client_id(self, runner, mock_wiz_variables):
|
|
464
|
+
"""Test sync_compliance when client_id is None or empty (lines 445-446)."""
|
|
465
|
+
with patch(
|
|
466
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
467
|
+
) as mock_processor:
|
|
468
|
+
mock_instance = MagicMock()
|
|
469
|
+
mock_processor.return_value = mock_instance
|
|
470
|
+
|
|
471
|
+
result = runner.invoke(
|
|
472
|
+
wiz,
|
|
473
|
+
[
|
|
474
|
+
"sync_compliance",
|
|
475
|
+
"--wiz_project_id",
|
|
476
|
+
"test-project",
|
|
477
|
+
"--regscale_id",
|
|
478
|
+
"123",
|
|
479
|
+
# Not providing client_id
|
|
480
|
+
],
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
# Verify processor was created with env credentials
|
|
484
|
+
mock_processor.assert_called_once()
|
|
485
|
+
call_kwargs = mock_processor.call_args[1]
|
|
486
|
+
assert call_kwargs["client_id"] == "env_client_id"
|
|
487
|
+
assert result.exit_code == 0
|
|
488
|
+
|
|
489
|
+
def test_sync_compliance_full_flow(self, runner, mock_wiz_variables):
|
|
490
|
+
"""Test sync_compliance command full flow (lines 449-468)."""
|
|
491
|
+
with patch(
|
|
492
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
493
|
+
) as mock_processor:
|
|
494
|
+
mock_instance = MagicMock()
|
|
495
|
+
mock_processor.return_value = mock_instance
|
|
496
|
+
|
|
497
|
+
result = runner.invoke(
|
|
498
|
+
wiz,
|
|
499
|
+
[
|
|
500
|
+
"sync_compliance",
|
|
501
|
+
"--wiz_project_id",
|
|
502
|
+
"test-project",
|
|
503
|
+
"--regscale_id",
|
|
504
|
+
"456",
|
|
505
|
+
"--client_id",
|
|
506
|
+
"test_client",
|
|
507
|
+
"--client_secret",
|
|
508
|
+
"test_secret",
|
|
509
|
+
"--framework_id",
|
|
510
|
+
"wf-id-5",
|
|
511
|
+
"--create-issues",
|
|
512
|
+
"--update-control-status",
|
|
513
|
+
"--create-poams",
|
|
514
|
+
"--refresh",
|
|
515
|
+
"--cache-duration",
|
|
516
|
+
"720",
|
|
517
|
+
],
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Verify processor was created with correct parameters
|
|
521
|
+
mock_processor.assert_called_once()
|
|
522
|
+
call_kwargs = mock_processor.call_args[1]
|
|
523
|
+
assert call_kwargs["plan_id"] == 456
|
|
524
|
+
assert call_kwargs["wiz_project_id"] == "test-project"
|
|
525
|
+
assert call_kwargs["client_id"] == "test_client"
|
|
526
|
+
assert call_kwargs["client_secret"] == "test_secret"
|
|
527
|
+
assert call_kwargs["create_poams"] is True
|
|
528
|
+
assert call_kwargs["create_issues"] is True
|
|
529
|
+
assert call_kwargs["update_control_status"] is True
|
|
530
|
+
assert call_kwargs["force_fresh_report"] is True
|
|
531
|
+
assert call_kwargs["reuse_existing_reports"] is False
|
|
532
|
+
assert call_kwargs["bypass_control_filtering"] is True
|
|
533
|
+
|
|
534
|
+
# Verify process_compliance_sync was called
|
|
535
|
+
mock_instance.process_compliance_sync.assert_called_once()
|
|
536
|
+
assert result.exit_code == 0
|
|
537
|
+
|
|
538
|
+
# ========================================
|
|
539
|
+
# Test compliance_report command (lines 568-594)
|
|
540
|
+
# ========================================
|
|
541
|
+
|
|
542
|
+
def test_compliance_report_with_empty_client_secret(self, runner, mock_wiz_variables):
|
|
543
|
+
"""Test compliance_report when client_secret is empty (lines 571-572)."""
|
|
544
|
+
with patch(
|
|
545
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
546
|
+
) as mock_processor:
|
|
547
|
+
mock_instance = MagicMock()
|
|
548
|
+
mock_processor.return_value = mock_instance
|
|
549
|
+
|
|
550
|
+
result = runner.invoke(
|
|
551
|
+
wiz,
|
|
552
|
+
[
|
|
553
|
+
"compliance_report",
|
|
554
|
+
"--wiz_project_id",
|
|
555
|
+
"test-project",
|
|
556
|
+
"--regscale_id",
|
|
557
|
+
"789",
|
|
558
|
+
"--client_secret",
|
|
559
|
+
"", # Empty string
|
|
560
|
+
],
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
# Verify processor was created with env credentials
|
|
564
|
+
mock_processor.assert_called_once()
|
|
565
|
+
call_kwargs = mock_processor.call_args[1]
|
|
566
|
+
assert call_kwargs["client_secret"] == "env_client_secret"
|
|
567
|
+
assert result.exit_code == 0
|
|
568
|
+
|
|
569
|
+
def test_compliance_report_with_none_client_secret(self, runner, mock_wiz_variables):
|
|
570
|
+
"""Test compliance_report when client_secret is None (lines 571-572)."""
|
|
571
|
+
with patch(
|
|
572
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
573
|
+
) as mock_processor:
|
|
574
|
+
mock_instance = MagicMock()
|
|
575
|
+
mock_processor.return_value = mock_instance
|
|
576
|
+
|
|
577
|
+
result = runner.invoke(
|
|
578
|
+
wiz,
|
|
579
|
+
[
|
|
580
|
+
"compliance_report",
|
|
581
|
+
"--wiz_project_id",
|
|
582
|
+
"test-project",
|
|
583
|
+
"--regscale_id",
|
|
584
|
+
"789",
|
|
585
|
+
# Not providing client_secret
|
|
586
|
+
],
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
# Verify processor was created with env credentials
|
|
590
|
+
mock_processor.assert_called_once()
|
|
591
|
+
call_kwargs = mock_processor.call_args[1]
|
|
592
|
+
assert call_kwargs["client_secret"] == "env_client_secret"
|
|
593
|
+
assert result.exit_code == 0
|
|
594
|
+
|
|
595
|
+
def test_compliance_report_with_empty_client_id(self, runner, mock_wiz_variables):
|
|
596
|
+
"""Test compliance_report when client_id is empty (lines 573-574)."""
|
|
597
|
+
with patch(
|
|
598
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
599
|
+
) as mock_processor:
|
|
600
|
+
mock_instance = MagicMock()
|
|
601
|
+
mock_processor.return_value = mock_instance
|
|
602
|
+
|
|
603
|
+
result = runner.invoke(
|
|
604
|
+
wiz,
|
|
605
|
+
[
|
|
606
|
+
"compliance_report",
|
|
607
|
+
"--wiz_project_id",
|
|
608
|
+
"test-project",
|
|
609
|
+
"--regscale_id",
|
|
610
|
+
"789",
|
|
611
|
+
"--client_id",
|
|
612
|
+
"", # Empty string
|
|
613
|
+
],
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
# Verify processor was created with env credentials
|
|
617
|
+
mock_processor.assert_called_once()
|
|
618
|
+
call_kwargs = mock_processor.call_args[1]
|
|
619
|
+
assert call_kwargs["client_id"] == "env_client_id"
|
|
620
|
+
assert result.exit_code == 0
|
|
621
|
+
|
|
622
|
+
def test_compliance_report_full_flow(self, runner, mock_wiz_variables):
|
|
623
|
+
"""Test compliance_report command full flow (lines 578-594)."""
|
|
624
|
+
with patch(
|
|
625
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
626
|
+
) as mock_processor:
|
|
627
|
+
mock_instance = MagicMock()
|
|
628
|
+
mock_processor.return_value = mock_instance
|
|
629
|
+
|
|
630
|
+
result = runner.invoke(
|
|
631
|
+
wiz,
|
|
632
|
+
[
|
|
633
|
+
"compliance_report",
|
|
634
|
+
"--wiz_project_id",
|
|
635
|
+
"test-project-2",
|
|
636
|
+
"--regscale_id",
|
|
637
|
+
"999",
|
|
638
|
+
"--client_id",
|
|
639
|
+
"custom_client",
|
|
640
|
+
"--client_secret",
|
|
641
|
+
"custom_secret",
|
|
642
|
+
"--report_file_path",
|
|
643
|
+
"/path/to/report.csv",
|
|
644
|
+
"--create-issues",
|
|
645
|
+
"--update-control-status",
|
|
646
|
+
"--create-poams",
|
|
647
|
+
"--no-reuse-existing-reports",
|
|
648
|
+
"--force-fresh-report",
|
|
649
|
+
],
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
# Verify processor was created with correct parameters
|
|
653
|
+
mock_processor.assert_called_once()
|
|
654
|
+
call_kwargs = mock_processor.call_args[1]
|
|
655
|
+
assert call_kwargs["plan_id"] == 999
|
|
656
|
+
assert call_kwargs["wiz_project_id"] == "test-project-2"
|
|
657
|
+
assert call_kwargs["client_id"] == "custom_client"
|
|
658
|
+
assert call_kwargs["client_secret"] == "custom_secret"
|
|
659
|
+
assert call_kwargs["report_file_path"] == "/path/to/report.csv"
|
|
660
|
+
assert call_kwargs["create_poams"] is True
|
|
661
|
+
assert call_kwargs["create_issues"] is True
|
|
662
|
+
assert call_kwargs["update_control_status"] is True
|
|
663
|
+
assert call_kwargs["bypass_control_filtering"] is True
|
|
664
|
+
assert call_kwargs["reuse_existing_reports"] is False
|
|
665
|
+
assert call_kwargs["force_fresh_report"] is True
|
|
666
|
+
|
|
667
|
+
# Verify process_compliance_sync was called
|
|
668
|
+
mock_instance.process_compliance_sync.assert_called_once()
|
|
669
|
+
assert result.exit_code == 0
|
|
670
|
+
|
|
671
|
+
def test_compliance_report_with_defaults(self, runner, mock_wiz_variables):
|
|
672
|
+
"""Test compliance_report command with default values."""
|
|
673
|
+
with patch(
|
|
674
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
675
|
+
) as mock_processor:
|
|
676
|
+
mock_instance = MagicMock()
|
|
677
|
+
mock_processor.return_value = mock_instance
|
|
678
|
+
|
|
679
|
+
result = runner.invoke(
|
|
680
|
+
wiz,
|
|
681
|
+
[
|
|
682
|
+
"compliance_report",
|
|
683
|
+
"--wiz_project_id",
|
|
684
|
+
"test-project-defaults",
|
|
685
|
+
"--regscale_id",
|
|
686
|
+
"111",
|
|
687
|
+
],
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
# Verify processor was created with default values
|
|
691
|
+
mock_processor.assert_called_once()
|
|
692
|
+
call_kwargs = mock_processor.call_args[1]
|
|
693
|
+
assert call_kwargs["create_issues"] is True # Default
|
|
694
|
+
assert call_kwargs["update_control_status"] is True # Default
|
|
695
|
+
assert call_kwargs["create_poams"] is False # Default
|
|
696
|
+
assert call_kwargs["reuse_existing_reports"] is True # Default
|
|
697
|
+
assert call_kwargs["force_fresh_report"] is False # Default
|
|
698
|
+
assert call_kwargs["report_file_path"] is None # Default
|
|
699
|
+
|
|
700
|
+
# Verify process_compliance_sync was called
|
|
701
|
+
mock_instance.process_compliance_sync.assert_called_once()
|
|
702
|
+
assert result.exit_code == 0
|
|
703
|
+
|
|
704
|
+
# ========================================
|
|
705
|
+
# Edge cases and error handling
|
|
706
|
+
# ========================================
|
|
707
|
+
|
|
708
|
+
def test_inventory_with_filter_override(self, runner, mock_wiz_variables, mock_scanner):
|
|
709
|
+
"""Test inventory command with filter_by_override parameter."""
|
|
710
|
+
result = runner.invoke(
|
|
711
|
+
wiz,
|
|
712
|
+
[
|
|
713
|
+
"inventory",
|
|
714
|
+
"--wiz_project_id",
|
|
715
|
+
"test-project",
|
|
716
|
+
"--regscale_ssp_id",
|
|
717
|
+
"2288",
|
|
718
|
+
"--filter_by_override",
|
|
719
|
+
'{"projectId": ["test-123"]}',
|
|
720
|
+
],
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
# Verify sync_assets was called with the filter
|
|
724
|
+
mock_scanner.sync_assets.assert_called_once()
|
|
725
|
+
call_kwargs = mock_scanner.sync_assets.call_args[1]
|
|
726
|
+
assert call_kwargs["filter_by_override"] == '{"projectId": ["test-123"]}'
|
|
727
|
+
assert result.exit_code == 0
|
|
728
|
+
|
|
729
|
+
def test_issues_with_filter_override(
|
|
730
|
+
self,
|
|
731
|
+
runner,
|
|
732
|
+
mock_wiz_variables,
|
|
733
|
+
mock_wiz_issue,
|
|
734
|
+
mock_wiz_auth,
|
|
735
|
+
mock_check_license,
|
|
736
|
+
):
|
|
737
|
+
"""Test issues command with filter_by_override parameter."""
|
|
738
|
+
result = runner.invoke(
|
|
739
|
+
wiz,
|
|
740
|
+
[
|
|
741
|
+
"issues",
|
|
742
|
+
"--wiz_project_id",
|
|
743
|
+
"test-project",
|
|
744
|
+
"--regscale_ssp_id",
|
|
745
|
+
"2288",
|
|
746
|
+
"--filter_by_override",
|
|
747
|
+
'{"severity": ["CRITICAL"]}',
|
|
748
|
+
],
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
# Verify sync_findings was called
|
|
752
|
+
mock_wiz_issue.sync_findings.assert_called_once()
|
|
753
|
+
assert result.exit_code == 0
|
|
754
|
+
|
|
755
|
+
def test_vulnerabilities_with_filter_override(self, runner, mock_wiz_variables, mock_scanner):
|
|
756
|
+
"""Test vulnerabilities command with filter_by_override parameter."""
|
|
757
|
+
result = runner.invoke(
|
|
758
|
+
wiz,
|
|
759
|
+
[
|
|
760
|
+
"vulnerabilities",
|
|
761
|
+
"--wiz_project_id",
|
|
762
|
+
"test-project",
|
|
763
|
+
"--regscale_ssp_id",
|
|
764
|
+
"2288",
|
|
765
|
+
"--filter_by_override",
|
|
766
|
+
'{"type": ["CRITICAL"]}',
|
|
767
|
+
],
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
# Verify sync_findings was called with the filter
|
|
771
|
+
mock_scanner.sync_findings.assert_called_once()
|
|
772
|
+
call_kwargs = mock_scanner.sync_findings.call_args[1]
|
|
773
|
+
assert call_kwargs["filter_by_override"] == '{"type": ["CRITICAL"]}'
|
|
774
|
+
assert result.exit_code == 0
|
|
775
|
+
|
|
776
|
+
def test_attach_sbom_with_default_standard(self, runner, mock_wiz_variables):
|
|
777
|
+
"""Test attach_sbom command with default standard (CycloneDX)."""
|
|
778
|
+
with patch("regscale.integrations.commercial.wizv2.core.auth.wiz_authenticate") as mock_auth:
|
|
779
|
+
with patch("regscale.integrations.commercial.wizv2.utils.fetch_sbom_report") as mock_fetch:
|
|
780
|
+
mock_auth.return_value = "test_token"
|
|
781
|
+
mock_fetch.return_value = None
|
|
782
|
+
|
|
783
|
+
result = runner.invoke(
|
|
784
|
+
wiz,
|
|
785
|
+
[
|
|
786
|
+
"attach_sbom",
|
|
787
|
+
"--regscale_ssp_id",
|
|
788
|
+
"2288",
|
|
789
|
+
"--report_id",
|
|
790
|
+
"test-report-id",
|
|
791
|
+
# Not providing --standard, should default to CycloneDX
|
|
792
|
+
],
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
# Verify fetch_sbom_report was called with default standard
|
|
796
|
+
mock_fetch.assert_called_once()
|
|
797
|
+
call_args = mock_fetch.call_args[1]
|
|
798
|
+
assert call_args["standard"] == "CycloneDX"
|
|
799
|
+
assert result.exit_code == 0
|
|
800
|
+
|
|
801
|
+
def test_sync_compliance_no_create_issues(self, runner, mock_wiz_variables):
|
|
802
|
+
"""Test sync_compliance with --no-create-issues flag."""
|
|
803
|
+
with patch(
|
|
804
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
805
|
+
) as mock_processor:
|
|
806
|
+
mock_instance = MagicMock()
|
|
807
|
+
mock_processor.return_value = mock_instance
|
|
808
|
+
|
|
809
|
+
result = runner.invoke(
|
|
810
|
+
wiz,
|
|
811
|
+
[
|
|
812
|
+
"sync_compliance",
|
|
813
|
+
"--wiz_project_id",
|
|
814
|
+
"test-project",
|
|
815
|
+
"--regscale_id",
|
|
816
|
+
"123",
|
|
817
|
+
"--no-create-issues",
|
|
818
|
+
],
|
|
819
|
+
)
|
|
820
|
+
|
|
821
|
+
# Verify processor was created with create_issues=False
|
|
822
|
+
mock_processor.assert_called_once()
|
|
823
|
+
call_kwargs = mock_processor.call_args[1]
|
|
824
|
+
assert call_kwargs["create_issues"] is False
|
|
825
|
+
assert result.exit_code == 0
|
|
826
|
+
|
|
827
|
+
def test_compliance_report_no_update_control_status(self, runner, mock_wiz_variables):
|
|
828
|
+
"""Test compliance_report with --no-update-control-status flag."""
|
|
829
|
+
with patch(
|
|
830
|
+
"regscale.integrations.commercial.wizv2.compliance_report.WizComplianceReportProcessor"
|
|
831
|
+
) as mock_processor:
|
|
832
|
+
mock_instance = MagicMock()
|
|
833
|
+
mock_processor.return_value = mock_instance
|
|
834
|
+
|
|
835
|
+
result = runner.invoke(
|
|
836
|
+
wiz,
|
|
837
|
+
[
|
|
838
|
+
"compliance_report",
|
|
839
|
+
"--wiz_project_id",
|
|
840
|
+
"test-project",
|
|
841
|
+
"--regscale_id",
|
|
842
|
+
"789",
|
|
843
|
+
"--no-update-control-status",
|
|
844
|
+
],
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
# Verify processor was created with update_control_status=False
|
|
848
|
+
mock_processor.assert_called_once()
|
|
849
|
+
call_kwargs = mock_processor.call_args[1]
|
|
850
|
+
assert call_kwargs["update_control_status"] is False
|
|
851
|
+
assert result.exit_code == 0
|