fix(fleet-sync): clear stale policy_evaluation on replica sync swap (#971)

Replicated scan policies always insert with fresh ids on the replica
side. Any vulnerability_scans.policy_evaluation row referencing the
prior set was instantly stale the moment the swap completed, so the
replica's UI would surface violations from a policy that no longer
exists.

replaceReplicatedScanPolicies now calls clearOrphanPolicyEvaluations()
inside the same transaction as the delete + inserts, so the cleanup
commits atomically with the row swap. Local-only policies and their
cached evaluations remain untouched.

CVE suppressions do not have an analogous cache (suppressions are
applied at read time, never persisted on scan rows), so
replaceReplicatedCveSuppressions does not need a sibling call.

Tests:
- database-replicated-policies.test.ts: stale policy_evaluation
  cleared after a swap; local-policy evaluation preserved across
  swaps.
- Full backend suite: 1783 pass / 5 skipped.
This commit is contained in:
Anso
2026-05-07 13:26:00 -04:00
committed by GitHub
parent 33b15d6cba
commit f8c75aa6cd
2 changed files with 159 additions and 0 deletions
+7
View File
@@ -3612,6 +3612,12 @@ export class DatabaseService {
* Replace all policies that were replicated from a control node with the
* provided rows in a single transaction. Local-only policies (created on
* this instance directly) are left untouched.
*
* Replicated policies always insert with fresh ids on the replica, so any
* `vulnerability_scans.policy_evaluation` row pointing at a replicated
* policy from the previous push refers to a now-deleted id. Clear those
* orphaned cache entries inside the same transaction so a replica's UI
* stops showing violations from a policy that no longer exists.
*/
public replaceReplicatedScanPolicies(rows: ScanPolicy[]): void {
const now = Date.now();
@@ -3635,6 +3641,7 @@ export class DatabaseService {
p.updated_at ?? now,
);
}
this.clearOrphanPolicyEvaluations();
});
txn(rows);
}