Convert Vulnerability objects to Vulnerabilities::Read before ES queue

What does this MR do and why?

Converts Vulnerability objects to Vulnerabilities::Read records before pushing to the Elasticsearch processing queue. This prepares for the Vulnerabilities Across Contexts feature where a single vulnerability can have multiple context-specific read entries.

All changes are gated behind the convert_vulnerability_to_read_for_es_queue feature flag. When disabled, existing behavior is preserved.

Changes

New Elastic::VulnerabilitiesSearch concern (ee/app/models/concerns/elastic/vulnerabilities_search.rb)

  • Replaces direct Elastic::ApplicationVersionedSearch inclusion on Vulnerability
  • Overrides maintain_elasticsearch_create, maintain_elasticsearch_update, and maintain_elasticsearch_destroy to track vulnerability_read instead of the vulnerability itself when the feature flag is enabled
  • Caches vulnerability_read in a before_destroy callback to avoid a race condition with DB cascade delete (vulnerability_reads has ON DELETE CASCADE on vulnerability_id, so the read is gone by after_commit time)

BulkEsOperationService updates (ee/app/services/vulnerabilities/bulk_es_operation_service.rb)

  • When processing Vulnerability relations, splits eligible records into convertable (flag enabled) and non-convertable, tracking reads and vulnerabilities in separate ProcessBookkeepingService.track! calls
  • Preloads vulnerability_read association alongside existing preloads
  • Shares preloaded project from Vulnerability to its vulnerability_read via association(:project).target to avoid N+1 queries (they share the same project_id but maintain separate association caches)

RemoveFromProjectService updates (ee/app/services/vulnerabilities/removal/remove_from_project_service.rb)

  • Replaces BulkEsOperationService usage with direct ProcessBookkeepingService.track!(*es_references) call
  • New build_es_references method captures elastic reference strings before deletion, choosing Vulnerabilities::Read or Vulnerability records based on the feature flag
  • Uses association(:project).target = project and NamespaceRootAncestorPreloader to avoid N+1 queries

EE::Vulnerability model (ee/app/models/ee/vulnerability.rb)

  • Includes Elastic::VulnerabilitiesSearch instead of Elastic::ApplicationVersionedSearch
  • Adds convert_to_read_enabled? method
  • Removes extend ::Gitlab::Utils::Override (no longer needed since override :use_elasticsearch? moved to the new concern)

Feature flag (ee/config/feature_flags/wip/convert_vulnerability_to_read_for_es_queue.yml)

  • New WIP feature flag gating the conversion

Specs updated

  • vulnerabilities_search_spec.rb — Full spec for the new concern (create/update/destroy callbacks, caching, flag-disabled fallback)
  • bulk_es_operation_service_spec.rb — Tests for read conversion, non-conversion for Read relations, N+1 checks, flag-disabled context, indexing-disabled context
  • remove_from_project_service_spec.rb — Tests using elastic_reference expectations, flag-disabled context
  • vulnerability_spec.rb — Parameterized shared example with expected_es_tracked_object defaulting to vulnerability.vulnerability_read, flag-disabled context

Issue: #591435

How to set up and validate locally

  1. Enable the feature flag:
    Feature.enable(:convert_vulnerability_to_read_for_es_queue)
  2. Create or update a vulnerability — observe that Vulnerabilities::Read records are tracked in the ES bookkeeping queue instead of Vulnerability records
  3. Disable the flag and verify the original Vulnerability tracking behavior is preserved

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 Schmil Monderer

Merge request reports

Loading