Associate CVE enrichments for security findings

What does this MR do and why?

This change introduces the ability to store CVE enrichment data for security findings. When security reports are processed, findings with CVE identifiers will have corresponding Security::FindingEnrichment records created or updated.

This links security findings to detailed CVE information which will be used to enforce security policies KEV and EPSS filter.

If package enrichment data is not available for a CVE record, we still create e Security::FindingEnrichment record so that we can enforce security policies with unknown KEV and EPSS attributes. Ref: &16311 (comment 2965079503)

Spike MR: #581332

References

MR to create finding enrichment model: !216984 (merged)

Database Queries

Upserting Security Finding Enrichments

  INSERT INTO "security_finding_enrichments" 
    ("project_id","finding_uuid","cve_enrichment_id","cve","created_at","updated_at") 
  VALUES 
    (185, 'dea0c6d6-8b27-4fbf-83fd-d227f18a9fc8', 158915, 'CVE-2021-38938', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (185, '46a06646-e978-49b9-9b59-40dde3bc7b21', 295211, 'CVE-2024-49977', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
  ON CONFLICT ("finding_uuid","cve") 
  DO UPDATE SET 
    updated_at = (CASE WHEN ("security_finding_enrichments"."project_id" IS NOT DISTINCT FROM excluded."project_id" 
                          AND "security_finding_enrichments"."cve_enrichment_id" IS NOT DISTINCT FROM excluded."cve_enrichment_id") 
                      THEN "security_finding_enrichments".updated_at 
                      ELSE CURRENT_TIMESTAMP END),
    "project_id" = excluded."project_id",
    "cve_enrichment_id" = excluded."cve_enrichment_id"
  RETURNING "id"
Query Plan on Local
Insert on security_finding_enrichments  (cost=0.00..0.03 rows=2 width=88) (actual time=0.094..0.100 rows=2 loops=1)
  Conflict Resolution: UPDATE
  Conflict Arbiter Indexes: index_sec_finding_enrichments_on_finding_and_cve
  Tuples Inserted: 0
  Conflicting Tuples: 2
  Buffers: shared hit=10
  ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=88) (actual time=0.015..0.016 rows=2 loops=1)
        Buffers: shared hit=2
Planning Time: 0.062 ms
Execution Time: 0.121 ms

Finding CVEs

SELECT "pm_cve_enrichment".* FROM "pm_cve_enrichment" WHERE "pm_cve_enrichment"."cve" IN ('CVE-2021-38938', 'CVE-2024-49977', 'CVE-2018-2713', 'CVE-2010-3199', 'CVE-2015-2840', 'CVE-2016-10975', 'CVE-2021-28460', 'CVE-2001-0057', 'CVE-2018-19141', 'CVE-2024-51528', 'CVE-1999-1171', 'CVE-2025-2353', 'CVE-2004-2335', 'CVE-2018-0462', 'CVE-2017-4604', 'CVE-2022-20954', 'CVE-2017-14198', 'CVE-2008-6112', 'CVE-2018-18772', 'CVE-2015-6495', 'CVE-2001-0163', 'CVE-2018-17469', 'CVE-2009-1820', 'CVE-2024-53007', 'CVE-2023-6046', 'CVE-1999-1235', 'CVE-2018-15144', 'CVE-2010-3200', 'CVE-2015-7775', 'CVE-2024-27655', 'CVE-2024-39563', 'CVE-2024-39564', 'CVE-2024-40986', 'CVE-2025-30123', 'CVE-2024-0467', 'CVE-2020-1190', 'CVE-2015-6175', 'CVE-2009-3490', 'CVE-2024-39565', 'CVE-2001-0164', 'CVE-2018-2888', 'CVE-2014-9259', 'CVE-2024-10044', 'CVE-2001-1415', 'CVE-2015-6621', 'CVE-2019-5589', 'CVE-2016-10704', 'CVE-2016-10705', 'CVE-1999-0348', 'CVE-2025-62454')

https://console.postgres.ai/gitlab/gitlab-production-main/sessions/46833/commands/142328

Screenshots or screen recordings

Before After

How to set up and validate locally

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.

Related to #516814

Edited by Imam Hossain

Merge request reports

Loading