From 51a5b6166a2dea65fa8be4b4b17baa71d165ac82 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Tue, 19 Aug 2025 13:39:32 -0400 Subject: [PATCH] Refactor failing policies total on Host endpoint (#31906) For #29795 Refactored the way we compute the number of failing policies to avoid discrepancies due to either read replica delays or due to async nature of the failing policy computation stored in host issues. --- changes/29795-deleted-policies-still-showing | 1 + server/service/hosts.go | 14 ++++++++++++-- server/service/integration_core_test.go | 6 ++---- 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 changes/29795-deleted-policies-still-showing diff --git a/changes/29795-deleted-policies-still-showing b/changes/29795-deleted-policies-still-showing new file mode 100644 index 0000000000..64b35388ce --- /dev/null +++ b/changes/29795-deleted-policies-still-showing @@ -0,0 +1 @@ +* Refactored the way failing policies are computed on Host end-point to avoid discrepancies due to read replica delays and async computation. \ No newline at end of file diff --git a/server/service/hosts.go b/server/service/hosts.go index a6045d481e..199f1236ae 100644 --- a/server/service/hosts.go +++ b/server/service/hosts.go @@ -1215,14 +1215,24 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f if err != nil { return nil, ctxerr.Wrap(ctx, err, "get policies for host") } - if hp == nil { hp = []*fleet.HostPolicy{} } - policies = &hp } + // Calculate the number of failing policies for the host based on the returned policies to + // avoid discrepancies due to read replica delay. + var failingPolicies uint64 + if policies != nil { + for _, p := range *policies { + if p != nil && p.Response == "fail" { + failingPolicies++ + } + } + } + host.HostIssues.FailingPoliciesCount = failingPolicies + // If Fleet MDM is enabled and configured, we want to include MDM profiles, // disk encryption status, and macOS setup details for non-linux hosts. ac, err := svc.ds.AppConfig(ctx) diff --git a/server/service/integration_core_test.go b/server/service/integration_core_test.go index ae98fa2fa2..62ba1ba503 100644 --- a/server/service/integration_core_test.go +++ b/server/service/integration_core_test.go @@ -2970,11 +2970,11 @@ func (s *integrationTestSuite) TestHostDetailsUpdatesStaleHostIssues() { hosts := s.createHosts(t, "linux") host := hosts[0] - stalePolicyCount, staleIssuesCount, freshPolicyCount, freshIssueCount := uint64(50), uint64(500), uint64(0), uint64(0) + staleIssuesCount, freshIssueCount := uint64(500), uint64(0) // create host_issues for it with stale data mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error { _, err := q.ExecContext(ctx, - `INSERT INTO host_issues (host_id, failing_policies_count, total_issues_count) VALUES (?, ?, ?)`, host.ID, stalePolicyCount, staleIssuesCount) + `INSERT INTO host_issues (host_id, total_issues_count) VALUES (?, ?)`, host.ID, staleIssuesCount) return err }) @@ -2982,7 +2982,6 @@ func (s *integrationTestSuite) TestHostDetailsUpdatesStaleHostIssues() { hostResp := getHostResponse{} s.DoJSON("GET", fmt.Sprintf("/api/v1/fleet/hosts/%d", host.ID), nil, http.StatusOK, &hostResp) - require.Equal(t, hostResp.Host.HostIssues.FailingPoliciesCount, stalePolicyCount) require.Equal(t, hostResp.Host.HostIssues.TotalIssuesCount, staleIssuesCount) // set updated_at to longer than minute ago @@ -2993,7 +2992,6 @@ func (s *integrationTestSuite) TestHostDetailsUpdatesStaleHostIssues() { }) // hit endpoint: should have been updated this time s.DoJSON("GET", fmt.Sprintf("/api/v1/fleet/hosts/%d", host.ID), nil, http.StatusOK, &hostResp) - require.Equal(t, hostResp.Host.HostIssues.FailingPoliciesCount, freshPolicyCount) require.Equal(t, hostResp.Host.HostIssues.TotalIssuesCount, freshIssueCount) }