@@ -2,6 +2,7 @@ package queue
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
67 "sync"
78 "sync/atomic"
@@ -183,6 +184,22 @@ func (aq *AlertQueue) processAlert(workerID int, item *Item) {
183184 return
184185 }
185186
187+ // Skip alerts already tagged "False positive". Manual path carries Tags
188+ // in AlertFields; gRPC path has none (proto lacks the field) so look up
189+ // the alert doc from ES. Fail-open if the lookup fails.
190+ tags := alertFields .Tags
191+ if len (tags ) == 0 && ! item .IsManual {
192+ tags = fetchAlertTags (alertFields .Id )
193+ }
194+ if hasFalsePositiveTag (tags ) {
195+ catcher .Info ("Skipping LLM: alert tagged False positive" , map [string ]any {
196+ "process" : "plugin_com.utmstack.soc-ai" ,
197+ "alert_id" : alertFields .Id ,
198+ })
199+ atomic .AddInt64 (& aq .processedCount , 1 )
200+ return
201+ }
202+
186203 // Check connection to LLM endpoint
187204 if config .GetConfig ().URL != "" {
188205 if err := utils .ConnectionChecker (config .GetConfig ().URL ); err != nil {
@@ -210,6 +227,30 @@ func (aq *AlertQueue) processAlert(workerID int, item *Item) {
210227 atomic .AddInt64 (& aq .processedCount , 1 )
211228}
212229
230+ // Matches backend Constants.FALSE_POSITIVE_TAG exactly.
231+ const falsePositiveTag = "False positive"
232+
233+ func hasFalsePositiveTag (tags []string ) bool {
234+ for _ , t := range tags {
235+ if t == falsePositiveTag {
236+ return true
237+ }
238+ }
239+ return false
240+ }
241+
242+ func fetchAlertTags (id string ) []string {
243+ result , err := elastic .ElasticSearchWithLimit (config .ALERT_INDEX_PATTERN , "id" , id , 1 )
244+ if err != nil {
245+ return nil
246+ }
247+ var alerts []schema.AlertFields
248+ if err := json .Unmarshal (result , & alerts ); err != nil || len (alerts ) == 0 {
249+ return nil
250+ }
251+ return alerts [0 ].Tags
252+ }
253+
213254func (aq * AlertQueue ) metricsLogger () {
214255 ticker := time .NewTicker (time .Minute )
215256 defer ticker .Stop ()
0 commit comments