Add detected_as status updates for false-positive (FP) vulnerability flags

What does this MR do and why?

This MR introduces a batched background migration to backfill status values for existing vulnerability_flags records related to AI SAST false-positive detection, set to default value not_started.

It also ensures that detected_as_fp and detected_as_not_fp statuses are correctly set based on the stored confidence_score, aligning historical records with the updated status model.

See: #585703 (comment 3000299851)

Status Condition
detected_as_fp confidence_score >= 0.6
detected_as_not_fp confidence_score < 0.6
not_started confidence_score == 0

References

Issue: Implement status handling for AI SAST false-pos... (#593705 - closed)

DBLab: https://console.postgres.ai/gitlab/gitlab-production-sec/sessions/48793/commands/146211

SQL query
UPDATE vulnerability_flags
SET status = CASE
    WHEN confidence_score < 0.6 THEN 3
    ELSE 2
END
WHERE id IN (
    SELECT id
    FROM vulnerability_flags
    WHERE id >= 1
      AND id <= 1000
    ORDER BY id ASC
)
  AND flag_type = 0
  AND confidence_score > 0;

Comment: #585703 (comment 3000299851)

Screenshots or screen recordings

Before After
before after

How to set up and validate locally

Set up Elasticsearch and enable SaaS mode

Enable and configure Elasticsearch

Follow the official GDK Elasticsearch setup guide:
https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/elasticsearch.md


Simulate GitLab SaaS mode

To test vulnerability management features locally, configure GDK to simulate GitLab SaaS.

You can either run the console with SaaS simulation enabled:

GITLAB_SIMULATE_SAAS=1 bundle exec rails console

Or add the following to your gdk.yml (see https://docs.gitlab.com/development/ee_features/#simulate-a-saas-instance):

env:
  GITLAB_SIMULATE_SAAS: "1"

Then restart GDK:

gdk restart

Ensure feature flag enabled

Feature.enabled?(:ai_experiment_sast_fp_detection, Group.find_by!(path: 'gitlab-org'))
# => true

Run the Elasticsearch migration

Use your migration version and re-indexing:

Elastic::DataMigrationService[20260126065229].migrate

Vulnerabilities::Read.all.each { |v| ::Elastic::ProcessBookkeepingService.track!(Search::Elastic::References::Vulnerability.new(v.vulnerability_id, "group_#{v.project.namespace.root_ancestor.id}")) }

Elastic::ProcessBookkeepingService.new.execute

Check completion:

Elastic::DataMigrationService.migration_has_finished?(
  :add_false_positive_detected_as_fp_to_vulnerability
)
# => true

query {
  project(fullPath: "Project") {
    vulnerabilities {
      nodes {
        id
        latestFlag {
          id
          status
        }
      }
    }
  }
}

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Ugo Nnanna Okeadu

Merge request reports

Loading