3636from api .db_router import MainRouter
3737from api .models import (
3838 AttackSurfaceOverview ,
39+ ComplianceOverviewSummary ,
40+ ComplianceRequirementOverview ,
3941 Finding ,
4042 Integration ,
4143 Invitation ,
5658 Scan ,
5759 ScanSummary ,
5860 StateChoices ,
61+ StatusChoices ,
5962 Task ,
6063 TenantAPIKey ,
6164 ThreatScoreSnapshot ,
@@ -5820,16 +5823,44 @@ def test_invalid_provider_group_id(
58205823
58215824@pytest .mark .django_db
58225825class TestComplianceOverviewViewSet :
5823- def test_compliance_overview_list_none (self , authenticated_client ):
5826+ @pytest .fixture (autouse = True )
5827+ def mock_backfill_task (self ):
5828+ with patch ("api.v1.views.backfill_compliance_summaries_task.delay" ) as mock :
5829+ yield mock
5830+
5831+ def test_compliance_overview_list_none (
5832+ self ,
5833+ authenticated_client ,
5834+ tenants_fixture ,
5835+ providers_fixture ,
5836+ mock_backfill_task ,
5837+ ):
5838+ tenant = tenants_fixture [0 ]
5839+ provider = providers_fixture [0 ]
5840+ scan = Scan .objects .create (
5841+ name = "empty-compliance-scan" ,
5842+ provider = provider ,
5843+ trigger = Scan .TriggerChoices .MANUAL ,
5844+ state = StateChoices .COMPLETED ,
5845+ tenant = tenant ,
5846+ )
5847+
58245848 response = authenticated_client .get (
58255849 reverse ("complianceoverview-list" ),
5826- {"filter[scan_id]" : "8d20ac7d-4cbc-435e-85f4-359be37af821" },
5850+ {"filter[scan_id]" : str ( scan . id ) },
58275851 )
58285852 assert response .status_code == status .HTTP_200_OK
58295853 assert len (response .json ()["data" ]) == 0
5854+ mock_backfill_task .assert_called_once ()
5855+ _ , kwargs = mock_backfill_task .call_args
5856+ assert kwargs ["scan_id" ] == str (scan .id )
5857+ assert str (kwargs ["tenant_id" ]) == str (tenant .id )
58305858
58315859 def test_compliance_overview_list (
5832- self , authenticated_client , compliance_requirements_overviews_fixture
5860+ self ,
5861+ authenticated_client ,
5862+ compliance_requirements_overviews_fixture ,
5863+ mock_backfill_task ,
58335864 ):
58345865 # List compliance overviews with existing data
58355866 requirement_overview1 = compliance_requirements_overviews_fixture [0 ]
@@ -5859,6 +5890,90 @@ def test_compliance_overview_list(
58595890 assert "requirements_failed" in attributes
58605891 assert "requirements_manual" in attributes
58615892 assert "total_requirements" in attributes
5893+ mock_backfill_task .assert_called_once ()
5894+ _ , kwargs = mock_backfill_task .call_args
5895+ assert kwargs ["scan_id" ] == scan_id
5896+
5897+ def test_compliance_overview_list_uses_preaggregated_summaries (
5898+ self ,
5899+ authenticated_client ,
5900+ tenants_fixture ,
5901+ providers_fixture ,
5902+ mock_backfill_task ,
5903+ ):
5904+ tenant = tenants_fixture [0 ]
5905+ provider = providers_fixture [0 ]
5906+ scan = Scan .objects .create (
5907+ name = "preaggregated-scan" ,
5908+ provider = provider ,
5909+ trigger = Scan .TriggerChoices .MANUAL ,
5910+ state = StateChoices .COMPLETED ,
5911+ tenant = tenant ,
5912+ )
5913+
5914+ ComplianceRequirementOverview .objects .create (
5915+ tenant = tenant ,
5916+ scan = scan ,
5917+ compliance_id = "cis_1.4_aws" ,
5918+ framework = "CIS-1.4-AWS" ,
5919+ version = "1.4" ,
5920+ description = "CIS AWS Foundations Benchmark v1.4.0" ,
5921+ region = "eu-west-1" ,
5922+ requirement_id = "framework-metadata" ,
5923+ requirement_status = StatusChoices .PASS ,
5924+ passed_checks = 1 ,
5925+ failed_checks = 0 ,
5926+ total_checks = 1 ,
5927+ )
5928+
5929+ ComplianceOverviewSummary .objects .create (
5930+ tenant = tenant ,
5931+ scan = scan ,
5932+ compliance_id = "cis_1.4_aws" ,
5933+ requirements_passed = 5 ,
5934+ requirements_failed = 1 ,
5935+ requirements_manual = 2 ,
5936+ total_requirements = 8 ,
5937+ )
5938+
5939+ response = authenticated_client .get (
5940+ reverse ("complianceoverview-list" ),
5941+ {"filter[scan_id]" : str (scan .id )},
5942+ )
5943+
5944+ assert response .status_code == status .HTTP_200_OK
5945+ data = response .json ()["data" ]
5946+ assert len (data ) == 1
5947+ overview = data [0 ]
5948+ assert overview ["id" ] == "cis_1.4_aws"
5949+ assert overview ["attributes" ]["requirements_passed" ] == 5
5950+ assert overview ["attributes" ]["requirements_failed" ] == 1
5951+ assert overview ["attributes" ]["requirements_manual" ] == 2
5952+ assert overview ["attributes" ]["total_requirements" ] == 8
5953+ assert "framework" in overview ["attributes" ]
5954+ assert "version" in overview ["attributes" ]
5955+ mock_backfill_task .assert_not_called ()
5956+
5957+ def test_compliance_overview_region_filter_skips_backfill (
5958+ self ,
5959+ authenticated_client ,
5960+ compliance_requirements_overviews_fixture ,
5961+ mock_backfill_task ,
5962+ ):
5963+ requirement_overview = compliance_requirements_overviews_fixture [0 ]
5964+ scan_id = str (requirement_overview .scan .id )
5965+
5966+ response = authenticated_client .get (
5967+ reverse ("complianceoverview-list" ),
5968+ {
5969+ "filter[scan_id]" : scan_id ,
5970+ "filter[region]" : requirement_overview .region ,
5971+ },
5972+ )
5973+
5974+ assert response .status_code == status .HTTP_200_OK
5975+ assert len (response .json ()["data" ]) >= 1
5976+ mock_backfill_task .assert_not_called ()
58625977
58635978 def test_compliance_overview_metadata (
58645979 self , authenticated_client , compliance_requirements_overviews_fixture
@@ -6012,6 +6127,11 @@ def test_compliance_overview_task_management_integration(
60126127 requirement_overview1 = compliance_requirements_overviews_fixture [0 ]
60136128 scan_id = str (requirement_overview1 .scan .id )
60146129
6130+ # Remove existing compliance data so the view falls back to task checks
6131+ scan = requirement_overview1 .scan
6132+ ComplianceOverviewSummary .objects .filter (scan = scan ).delete ()
6133+ ComplianceRequirementOverview .objects .filter (scan = scan ).delete ()
6134+
60156135 # Mock a running task
60166136 with patch .object (
60176137 ComplianceOverviewViewSet , "get_task_response_if_running"
@@ -6039,6 +6159,11 @@ def test_compliance_overview_task_failed_exception(
60396159 requirement_overview1 = compliance_requirements_overviews_fixture [0 ]
60406160 scan_id = str (requirement_overview1 .scan .id )
60416161
6162+ # Remove existing compliance data so the view falls back to task checks
6163+ scan = requirement_overview1 .scan
6164+ ComplianceOverviewSummary .objects .filter (scan = scan ).delete ()
6165+ ComplianceRequirementOverview .objects .filter (scan = scan ).delete ()
6166+
60426167 # Mock a failed task
60436168 with patch .object (
60446169 ComplianceOverviewViewSet , "get_task_response_if_running"
@@ -6062,6 +6187,8 @@ def test_compliance_overview_task_failed_exception(
60626187 ("framework" , "framework" , 1 ),
60636188 ("version" , "version" , 1 ),
60646189 ("region" , "region" , 1 ),
6190+ ("region__in" , "region" , 1 ),
6191+ ("region.in" , "region" , 1 ),
60656192 ],
60666193 )
60676194 def test_compliance_overview_filters (
0 commit comments