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,406 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Comprehensive unit tests for compliance status mapping in ComplianceIntegration.
|
|
5
|
+
|
|
6
|
+
These tests ensure that:
|
|
7
|
+
1. ONLY compliance settings from the SSP are used
|
|
8
|
+
2. No defaults are applied when compliance settings exist
|
|
9
|
+
3. The correct status is selected based on framework
|
|
10
|
+
4. The scoring/weight system works correctly
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import unittest
|
|
14
|
+
from unittest.mock import MagicMock, patch, PropertyMock
|
|
15
|
+
from typing import List, Optional
|
|
16
|
+
|
|
17
|
+
from regscale.integrations.compliance_integration import ComplianceIntegration
|
|
18
|
+
from regscale.models.regscale_models import ComplianceSettings, SecurityPlan, ControlImplementation
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MockComplianceIntegration(ComplianceIntegration):
|
|
22
|
+
"""Mock implementation of ComplianceIntegration for testing."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, **kwargs):
|
|
25
|
+
"""Override init to avoid API calls."""
|
|
26
|
+
# Store the values without calling super().__init__
|
|
27
|
+
self.plan_id = kwargs.get("plan_id", 100)
|
|
28
|
+
self.catalog_id = kwargs.get("catalog_id")
|
|
29
|
+
self.framework = kwargs.get("framework", "TEST_FRAMEWORK")
|
|
30
|
+
self.create_issues = kwargs.get("create_issues", False)
|
|
31
|
+
self.update_control_status = kwargs.get("update_control_status", True)
|
|
32
|
+
self.create_poams = kwargs.get("create_poams", False)
|
|
33
|
+
|
|
34
|
+
# Initialize required attributes
|
|
35
|
+
self._compliance_settings = None
|
|
36
|
+
self.scan_date = kwargs.get("scan_date", "2024-01-15")
|
|
37
|
+
self.parent_module = kwargs.get("parent_module", "securityplans")
|
|
38
|
+
|
|
39
|
+
# Initialize the constant properties
|
|
40
|
+
self.NOT_APPLICABLE_LABEL = "Not Applicable"
|
|
41
|
+
self.NOT_APPLICABLE_LOWER = "not applicable"
|
|
42
|
+
self.NOT_APPLICABLE_UNDERSCORE = "not_applicable"
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def module(self) -> str:
|
|
46
|
+
return "test_module"
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def title(self) -> str:
|
|
50
|
+
return "Test Integration"
|
|
51
|
+
|
|
52
|
+
def _get_compliance_items_from_data(self) -> List:
|
|
53
|
+
return []
|
|
54
|
+
|
|
55
|
+
def fetch_compliance_data(self) -> List:
|
|
56
|
+
"""Mock implementation of abstract method."""
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
def create_compliance_item(self, data: dict) -> object:
|
|
60
|
+
"""Mock implementation of abstract method."""
|
|
61
|
+
return MagicMock()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TestComplianceStatusMapping(unittest.TestCase):
|
|
65
|
+
"""Test cases for compliance status mapping logic."""
|
|
66
|
+
|
|
67
|
+
def setUp(self):
|
|
68
|
+
"""Set up test fixtures."""
|
|
69
|
+
# Create mock integration with necessary attributes
|
|
70
|
+
self.integration = MockComplianceIntegration(
|
|
71
|
+
plan_id=100,
|
|
72
|
+
catalog_id=None,
|
|
73
|
+
framework="TEST_FRAMEWORK",
|
|
74
|
+
create_issues=False,
|
|
75
|
+
update_control_status=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def create_mock_compliance_settings(self, title: str, status_labels: List[str]) -> ComplianceSettings:
|
|
79
|
+
"""
|
|
80
|
+
Create mock compliance settings with specified status labels.
|
|
81
|
+
|
|
82
|
+
:param str title: Title of the compliance settings (e.g., "DoD RMF Settings")
|
|
83
|
+
:param List[str] status_labels: List of available status values
|
|
84
|
+
:return: Mock ComplianceSettings object
|
|
85
|
+
"""
|
|
86
|
+
mock_settings = MagicMock(spec=ComplianceSettings)
|
|
87
|
+
mock_settings.title = title
|
|
88
|
+
mock_settings.get_field_labels = MagicMock(return_value=status_labels)
|
|
89
|
+
return mock_settings
|
|
90
|
+
|
|
91
|
+
def test_dod_fail_status_only_uses_compliance_settings(self):
|
|
92
|
+
"""Test that DoD framework ONLY uses status values from compliance settings, not defaults."""
|
|
93
|
+
# Create DoD compliance settings with specific status values
|
|
94
|
+
dod_status_labels = [
|
|
95
|
+
"Implemented",
|
|
96
|
+
"Not Implemented", # This should be selected for FAIL
|
|
97
|
+
"Planned",
|
|
98
|
+
"In Remediation", # This should NOT be selected for DoD
|
|
99
|
+
"Partially Implemented",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
mock_settings = self.create_mock_compliance_settings("DoD RMF Controls", dod_status_labels)
|
|
103
|
+
|
|
104
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
105
|
+
# Get status for FAIL result
|
|
106
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
107
|
+
|
|
108
|
+
# For DoD, it should select "Not Implemented" NOT "In Remediation"
|
|
109
|
+
self.assertEqual(status, "Not Implemented")
|
|
110
|
+
# Ensure get_field_labels was called
|
|
111
|
+
mock_settings.get_field_labels.assert_called_with("implementationStatus")
|
|
112
|
+
|
|
113
|
+
def test_fedramp_fail_status_only_uses_compliance_settings(self):
|
|
114
|
+
"""Test that FedRAMP framework ONLY uses status values from compliance settings."""
|
|
115
|
+
# Create FedRAMP compliance settings with specific status values
|
|
116
|
+
fedramp_status_labels = [
|
|
117
|
+
"Fully Implemented",
|
|
118
|
+
"In Remediation", # This should be selected for FAIL
|
|
119
|
+
"Partially Implemented",
|
|
120
|
+
"Not Implemented",
|
|
121
|
+
"Not Applicable",
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
mock_settings = self.create_mock_compliance_settings("FedRAMP Moderate", fedramp_status_labels)
|
|
125
|
+
|
|
126
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
127
|
+
# Get status for FAIL result
|
|
128
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
129
|
+
|
|
130
|
+
# For FedRAMP, it should select "In Remediation"
|
|
131
|
+
self.assertEqual(status, "In Remediation")
|
|
132
|
+
mock_settings.get_field_labels.assert_called_with("implementationStatus")
|
|
133
|
+
|
|
134
|
+
def test_pass_status_uses_only_compliance_settings(self):
|
|
135
|
+
"""Test that PASS status only uses values from compliance settings."""
|
|
136
|
+
# Test with DoD settings
|
|
137
|
+
dod_status_labels = [
|
|
138
|
+
"Implemented", # Should be selected for PASS
|
|
139
|
+
"Not Implemented",
|
|
140
|
+
"Planned",
|
|
141
|
+
"In Remediation",
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
mock_settings = self.create_mock_compliance_settings("DoD RMF", dod_status_labels)
|
|
145
|
+
|
|
146
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
147
|
+
status = self.integration._get_implementation_status_from_result("Pass")
|
|
148
|
+
self.assertEqual(status, "Implemented")
|
|
149
|
+
|
|
150
|
+
def test_no_default_fallback_when_compliance_settings_exist(self):
|
|
151
|
+
"""Test that the system does NOT fall back to defaults when compliance settings exist."""
|
|
152
|
+
# Create settings with LIMITED status options (no default values)
|
|
153
|
+
limited_status_labels = [
|
|
154
|
+
"Custom Status 1",
|
|
155
|
+
"Custom Status 2",
|
|
156
|
+
"Not Implemented", # Only failure status available
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
mock_settings = self.create_mock_compliance_settings("Custom Framework", limited_status_labels)
|
|
160
|
+
|
|
161
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
162
|
+
# Test FAIL - should use "Not Implemented" from the limited options
|
|
163
|
+
fail_status = self.integration._get_implementation_status_from_result("Fail")
|
|
164
|
+
self.assertEqual(fail_status, "Not Implemented")
|
|
165
|
+
|
|
166
|
+
# Test PASS - should return None or empty since no matching status
|
|
167
|
+
pass_status = self.integration._get_implementation_status_from_result("Pass")
|
|
168
|
+
# Should fall back to default ONLY when no match found
|
|
169
|
+
self.assertIn(pass_status, ["Custom Status 1", "Custom Status 2", "Fully Implemented"])
|
|
170
|
+
|
|
171
|
+
def test_scoring_system_priority(self):
|
|
172
|
+
"""Test that the scoring system correctly prioritizes status values."""
|
|
173
|
+
# Create settings with multiple fail options
|
|
174
|
+
status_labels = [
|
|
175
|
+
"Implemented",
|
|
176
|
+
"Not Implemented",
|
|
177
|
+
"Planned",
|
|
178
|
+
"In Remediation",
|
|
179
|
+
"Partially Implemented",
|
|
180
|
+
"Failed",
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
# Test DoD scoring priorities
|
|
184
|
+
dod_settings = self.create_mock_compliance_settings("DoD RMF Framework", status_labels)
|
|
185
|
+
|
|
186
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=dod_settings):
|
|
187
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
188
|
+
# DoD should prioritize "Not Implemented" over "In Remediation"
|
|
189
|
+
self.assertEqual(status, "Not Implemented")
|
|
190
|
+
|
|
191
|
+
# Test FedRAMP scoring priorities
|
|
192
|
+
fedramp_settings = self.create_mock_compliance_settings("FedRAMP High", status_labels)
|
|
193
|
+
|
|
194
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=fedramp_settings):
|
|
195
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
196
|
+
# FedRAMP should prioritize "In Remediation"
|
|
197
|
+
self.assertEqual(status, "In Remediation")
|
|
198
|
+
|
|
199
|
+
def test_exact_match_vs_partial_match(self):
|
|
200
|
+
"""Test that exact matches are prioritized over partial matches."""
|
|
201
|
+
status_labels = [
|
|
202
|
+
"Implemented",
|
|
203
|
+
"Not Implemented", # Exact match
|
|
204
|
+
"Partially Not Implemented", # Partial match
|
|
205
|
+
"In Remediation",
|
|
206
|
+
"Remediation Required", # Partial match
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
mock_settings = self.create_mock_compliance_settings("Test Framework", status_labels)
|
|
210
|
+
|
|
211
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
212
|
+
# Should select exact "Not Implemented" over partial matches
|
|
213
|
+
with patch.object(self.integration, "_detect_compliance_framework", return_value="DoD"):
|
|
214
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
215
|
+
self.assertEqual(status, "Not Implemented")
|
|
216
|
+
|
|
217
|
+
def test_framework_detection(self):
|
|
218
|
+
"""Test that framework detection correctly identifies different frameworks."""
|
|
219
|
+
test_cases = [
|
|
220
|
+
("DoD RMF Controls", "DoD"),
|
|
221
|
+
("RMF Implementation", "DoD"),
|
|
222
|
+
("Department of Defense", "DoD"),
|
|
223
|
+
("Military Security Controls", "DoD"),
|
|
224
|
+
("FedRAMP Moderate", "FedRAMP"),
|
|
225
|
+
("FedRAMP High Baseline", "FedRAMP"),
|
|
226
|
+
("NIST 800-53 Controls", "NIST"),
|
|
227
|
+
("NIST SP 800-53", "NIST"),
|
|
228
|
+
("FISMA Controls", "NIST"),
|
|
229
|
+
("Custom Framework", "Default"),
|
|
230
|
+
("", "Default"),
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
for title, expected_framework in test_cases:
|
|
234
|
+
mock_settings = self.create_mock_compliance_settings(title, [])
|
|
235
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
236
|
+
detected = self.integration._detect_compliance_framework()
|
|
237
|
+
self.assertEqual(
|
|
238
|
+
detected, expected_framework, f"Failed to detect {expected_framework} from title '{title}'"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def test_no_compliance_settings_falls_back_to_default(self):
|
|
242
|
+
"""Test that when NO compliance settings exist, system uses defaults."""
|
|
243
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=None):
|
|
244
|
+
# Should fall back to default mapping
|
|
245
|
+
fail_status = self.integration._get_implementation_status_from_result("Fail")
|
|
246
|
+
self.assertEqual(fail_status, "In Remediation")
|
|
247
|
+
|
|
248
|
+
pass_status = self.integration._get_implementation_status_from_result("Pass")
|
|
249
|
+
self.assertEqual(pass_status, "Fully Implemented")
|
|
250
|
+
|
|
251
|
+
def test_case_insensitive_matching(self):
|
|
252
|
+
"""Test that status matching is case-insensitive."""
|
|
253
|
+
status_labels = [
|
|
254
|
+
"IMPLEMENTED", # All caps
|
|
255
|
+
"Not Implemented", # Mixed case
|
|
256
|
+
"planned", # Lower case
|
|
257
|
+
"IN REMEDIATION", # All caps with space
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
mock_settings = self.create_mock_compliance_settings("Test", status_labels)
|
|
261
|
+
|
|
262
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
263
|
+
with patch.object(self.integration, "_detect_compliance_framework", return_value="DoD"):
|
|
264
|
+
# Should match "Not Implemented" despite case differences
|
|
265
|
+
status = self.integration._get_implementation_status_from_result("fail") # lowercase fail
|
|
266
|
+
self.assertEqual(status, "Not Implemented")
|
|
267
|
+
|
|
268
|
+
def test_not_applicable_status_mapping(self):
|
|
269
|
+
"""Test that Not Applicable status is correctly mapped."""
|
|
270
|
+
status_labels = [
|
|
271
|
+
"Implemented",
|
|
272
|
+
"Not Implemented",
|
|
273
|
+
"Not Applicable",
|
|
274
|
+
"N/A",
|
|
275
|
+
]
|
|
276
|
+
|
|
277
|
+
mock_settings = self.create_mock_compliance_settings("Test", status_labels)
|
|
278
|
+
|
|
279
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
280
|
+
# Test various forms of not applicable
|
|
281
|
+
for result in ["Not Applicable", "not_applicable", "N/A", "na"]:
|
|
282
|
+
status = self.integration._get_implementation_status_from_result(result)
|
|
283
|
+
self.assertIn(status, ["Not Applicable", "N/A"])
|
|
284
|
+
|
|
285
|
+
def test_empty_status_labels(self):
|
|
286
|
+
"""Test behavior when compliance settings have no status labels."""
|
|
287
|
+
mock_settings = self.create_mock_compliance_settings("Empty Settings", [])
|
|
288
|
+
|
|
289
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
290
|
+
# Should fall back to defaults when no labels available
|
|
291
|
+
fail_status = self.integration._get_implementation_status_from_result("Fail")
|
|
292
|
+
self.assertEqual(fail_status, "In Remediation")
|
|
293
|
+
|
|
294
|
+
def test_update_implementation_status_integration(self):
|
|
295
|
+
"""Test the full integration of status update with compliance settings."""
|
|
296
|
+
# Create a mock control implementation with required attributes
|
|
297
|
+
mock_impl = MagicMock(spec=ControlImplementation)
|
|
298
|
+
mock_impl.id = 123
|
|
299
|
+
mock_impl.status = "Old Status" # Use 'status' not 'implementationStatus'
|
|
300
|
+
mock_impl.responsibility = "Test Responsibility"
|
|
301
|
+
mock_impl.implementation = "Test implementation details"
|
|
302
|
+
mock_impl.save = MagicMock()
|
|
303
|
+
|
|
304
|
+
# Create DoD compliance settings
|
|
305
|
+
dod_status_labels = [
|
|
306
|
+
"Implemented",
|
|
307
|
+
"Not Implemented",
|
|
308
|
+
"Planned",
|
|
309
|
+
"In Remediation",
|
|
310
|
+
]
|
|
311
|
+
mock_settings = self.create_mock_compliance_settings("DoD RMF", dod_status_labels)
|
|
312
|
+
|
|
313
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
314
|
+
# Update status for a FAIL result
|
|
315
|
+
self.integration._update_implementation_status(mock_impl, "Fail")
|
|
316
|
+
|
|
317
|
+
# Verify the status was set to "Not Implemented" for DoD
|
|
318
|
+
self.assertEqual(mock_impl.status, "Not Implemented")
|
|
319
|
+
mock_impl.save.assert_called_once()
|
|
320
|
+
|
|
321
|
+
def test_scoring_with_similar_labels(self):
|
|
322
|
+
"""Test scoring when multiple similar labels exist."""
|
|
323
|
+
status_labels = [
|
|
324
|
+
"Implemented",
|
|
325
|
+
"Fully Implemented",
|
|
326
|
+
"Partially Implemented",
|
|
327
|
+
"Not Implemented",
|
|
328
|
+
"Not Yet Implemented",
|
|
329
|
+
"Implementation Planned",
|
|
330
|
+
]
|
|
331
|
+
|
|
332
|
+
mock_settings = self.create_mock_compliance_settings("Test", status_labels)
|
|
333
|
+
|
|
334
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
335
|
+
# For PASS, should prefer "Implemented" over "Fully Implemented"
|
|
336
|
+
pass_status = self.integration._get_implementation_status_from_result("Pass")
|
|
337
|
+
self.assertEqual(pass_status, "Implemented")
|
|
338
|
+
|
|
339
|
+
# For FAIL with DoD, should prefer "Not Implemented"
|
|
340
|
+
with patch.object(self.integration, "_detect_compliance_framework", return_value="DoD"):
|
|
341
|
+
fail_status = self.integration._get_implementation_status_from_result("Fail")
|
|
342
|
+
self.assertEqual(fail_status, "Not Implemented")
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class TestComplianceStatusMappingEdgeCases(unittest.TestCase):
|
|
346
|
+
"""Test edge cases and error conditions in status mapping."""
|
|
347
|
+
|
|
348
|
+
def setUp(self):
|
|
349
|
+
"""Set up test fixtures."""
|
|
350
|
+
self.integration = MockComplianceIntegration(
|
|
351
|
+
plan_id=100,
|
|
352
|
+
catalog_id=None,
|
|
353
|
+
framework="TEST_FRAMEWORK",
|
|
354
|
+
create_issues=False,
|
|
355
|
+
update_control_status=True,
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
def test_get_field_labels_exception(self):
|
|
359
|
+
"""Test behavior when get_field_labels throws an exception."""
|
|
360
|
+
mock_settings = MagicMock(spec=ComplianceSettings)
|
|
361
|
+
mock_settings.title = "Test Settings"
|
|
362
|
+
mock_settings.get_field_labels.side_effect = Exception("Database error")
|
|
363
|
+
|
|
364
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
365
|
+
# Should fall back to default when exception occurs
|
|
366
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
367
|
+
self.assertEqual(status, "In Remediation") # Default fail status
|
|
368
|
+
|
|
369
|
+
def test_none_result_input(self):
|
|
370
|
+
"""Test behavior with None or empty result input."""
|
|
371
|
+
mock_settings = MagicMock(spec=ComplianceSettings)
|
|
372
|
+
mock_settings.title = "Test"
|
|
373
|
+
mock_settings.get_field_labels.return_value = ["Implemented", "Not Implemented"]
|
|
374
|
+
|
|
375
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
376
|
+
# Test with None
|
|
377
|
+
status = self.integration._get_implementation_status_from_result(None)
|
|
378
|
+
self.assertIsNotNone(status) # Should handle gracefully
|
|
379
|
+
|
|
380
|
+
# Test with empty string
|
|
381
|
+
status = self.integration._get_implementation_status_from_result("")
|
|
382
|
+
self.assertIsNotNone(status) # Should handle gracefully
|
|
383
|
+
|
|
384
|
+
def test_special_characters_in_labels(self):
|
|
385
|
+
"""Test handling of special characters in status labels."""
|
|
386
|
+
status_labels = [
|
|
387
|
+
"Implemented (Full)",
|
|
388
|
+
"Not-Implemented",
|
|
389
|
+
"In_Remediation",
|
|
390
|
+
"Planned/Scheduled",
|
|
391
|
+
]
|
|
392
|
+
|
|
393
|
+
mock_settings = MagicMock(spec=ComplianceSettings)
|
|
394
|
+
mock_settings.title = "Test"
|
|
395
|
+
mock_settings.get_field_labels.return_value = status_labels
|
|
396
|
+
|
|
397
|
+
with patch.object(self.integration, "_get_compliance_settings", return_value=mock_settings):
|
|
398
|
+
# Should handle special characters in matching
|
|
399
|
+
with patch.object(self.integration, "_detect_compliance_framework", return_value="DoD"):
|
|
400
|
+
status = self.integration._get_implementation_status_from_result("Fail")
|
|
401
|
+
# Should still match "Not-Implemented" despite hyphen
|
|
402
|
+
self.assertIn(status, status_labels)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
if __name__ == "__main__":
|
|
406
|
+
unittest.main()
|