From 2a9c6e8ed34b0f4f34fd7e5de8ec7fcb38865797 Mon Sep 17 00:00:00 2001 From: Echo Date: Thu, 30 Apr 2026 01:11:23 +0000 Subject: [PATCH] fix: patch poller UPSERT and host_patch_data unique constraint BUG-14: Patch poller was INSERT-ing a new row every poll cycle instead of UPSERT-ing, creating 51 duplicate rows in host_patch_data for a single host. Changes: - patch_poller.rs: Changed INSERT to INSERT...ON CONFLICT (host_id) DO UPDATE so each host only has one row that gets updated on each poll - Migration 006: Added UNIQUE constraint on host_id, cleaned up 50 duplicate rows keeping only the latest polled_at per host The dashboard showing 174 pending patches and 0% compliance is expected behavior - the patch data was collected before the job ran and the poller runs every 30 minutes. The next poll cycle will refresh the data. --- crates/pm-worker/src/patch_poller.rs | 8 +++++++- migrations/006_host_patch_data_unique.sql | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 migrations/006_host_patch_data_unique.sql diff --git a/crates/pm-worker/src/patch_poller.rs b/crates/pm-worker/src/patch_poller.rs index c16b64a..6b039d5 100644 --- a/crates/pm-worker/src/patch_poller.rs +++ b/crates/pm-worker/src/patch_poller.rs @@ -156,12 +156,18 @@ async fn poll_host_patches( .filter(|p| !p.cve_ids.is_empty()) .count() as i32; - // Insert into host_patch_data. + // Upsert into host_patch_data (one row per host, latest poll wins). if let Err(e) = sqlx::query( r#" INSERT INTO host_patch_data (host_id, available_patches, installed_packages, patch_count, cve_count) VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (host_id) DO UPDATE SET + available_patches = EXCLUDED.available_patches, + installed_packages = EXCLUDED.installed_packages, + patch_count = EXCLUDED.patch_count, + cve_count = EXCLUDED.cve_count, + polled_at = NOW() "#, ) .bind(host.id) diff --git a/migrations/006_host_patch_data_unique.sql b/migrations/006_host_patch_data_unique.sql new file mode 100644 index 0000000..b28698a --- /dev/null +++ b/migrations/006_host_patch_data_unique.sql @@ -0,0 +1,12 @@ +-- Migration 006: Add UNIQUE constraint on host_id in host_patch_data +-- Clean up duplicate rows (keep latest polled_at per host) before adding constraint. + +-- Step 1: Delete duplicate rows, keeping only the most recent poll per host +DELETE FROM host_patch_data a +USING host_patch_data b +WHERE a.host_id = b.host_id + AND a.polled_at < b.polled_at; + +-- Step 2: Add UNIQUE constraint on host_id +ALTER TABLE host_patch_data + ADD CONSTRAINT host_patch_data_host_id_key UNIQUE (host_id);