From 480fecf6ac29f1f5587c40b133e48aa6c8ef7fb0 Mon Sep 17 00:00:00 2001
From: Tushar Goel <tushar.goel.dav@gmail.com>
Date: Fri, 28 Mar 2025 12:44:04 +0530
Subject: [PATCH 1/5] Add pipeline for adding advisory ID and tests

Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
---
 vulnerabilities/importer.py                   | 15 ++++++
 vulnerabilities/importers/apache_httpd.py     |  6 +++
 vulnerabilities/importers/apache_kafka.py     |  6 +++
 vulnerabilities/importers/apache_tomcat.py    |  6 +++
 vulnerabilities/importers/archlinux.py        |  6 +++
 vulnerabilities/importers/curl.py             |  6 +++
 vulnerabilities/importers/debian.py           |  6 +++
 vulnerabilities/importers/debian_oval.py      |  6 +++
 vulnerabilities/importers/elixir_security.py  |  6 +++
 vulnerabilities/importers/epss.py             |  6 +++
 vulnerabilities/importers/fireeye.py          |  6 +++
 vulnerabilities/importers/gentoo.py           |  6 +++
 vulnerabilities/importers/istio.py            |  6 +++
 vulnerabilities/importers/mozilla.py          |  6 +++
 vulnerabilities/importers/openssl.py          |  9 ++++
 vulnerabilities/importers/oss_fuzz.py         |  6 +++
 vulnerabilities/importers/postgresql.py       |  6 +++
 .../importers/project_kb_msr2019.py           |  6 +++
 vulnerabilities/importers/redhat.py           |  6 +++
 vulnerabilities/importers/retiredotnet.py     |  6 +++
 vulnerabilities/importers/ruby.py             |  6 +++
 vulnerabilities/importers/xen.py              |  6 +++
 .../migrations/0091_advisory_advisory_id.py   | 22 ++++++++
 vulnerabilities/models.py                     | 14 +++--
 vulnerabilities/pipelines/__init__.py         | 16 ++++++
 vulnerabilities/pipelines/add_advisory_id.py  | 53 +++++++++++++++++++
 .../pipelines/alpine_linux_importer.py        |  6 +++
 vulnerabilities/pipelines/github_importer.py  | 10 ++++
 vulnerabilities/pipelines/gitlab_importer.py  | 12 +++++
 vulnerabilities/pipelines/nginx_importer.py   |  6 +++
 vulnerabilities/pipelines/npm_importer.py     |  6 +++
 vulnerabilities/pipelines/nvd_importer.py     |  7 +++
 vulnerabilities/pipelines/pypa_importer.py    |  6 +++
 vulnerabilities/pipelines/pysec_importer.py   |  6 +++
 .../tests/test_add_advisory_pipeline.py       | 27 ++++++++++
 35 files changed, 331 insertions(+), 4 deletions(-)
 create mode 100644 vulnerabilities/migrations/0091_advisory_advisory_id.py
 create mode 100644 vulnerabilities/pipelines/add_advisory_id.py
 create mode 100644 vulnerabilities/tests/test_add_advisory_pipeline.py

diff --git a/vulnerabilities/importer.py b/vulnerabilities/importer.py
index 933c19edc..2c32e02df 100644
--- a/vulnerabilities/importer.py
+++ b/vulnerabilities/importer.py
@@ -377,6 +377,21 @@ class Importer:
     # It needs to be unique and immutable
     importer_name = ""
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        raise NotImplementedError
+
+    def get_cve_id(self, aliases: list[str]) -> str:
+        """
+        Return the CVE ID for the given aliases.
+        """
+        for alias in aliases:
+            if alias.startswith("CVE-"):
+                return alias
+        return None
+
     def __init__(self):
         if not self.spdx_license_expression:
             raise Exception(f"Cannot run importer {self!r} without a license")
diff --git a/vulnerabilities/importers/apache_httpd.py b/vulnerabilities/importers/apache_httpd.py
index 75099ab8f..bd486a3db 100644
--- a/vulnerabilities/importers/apache_httpd.py
+++ b/vulnerabilities/importers/apache_httpd.py
@@ -38,6 +38,12 @@ class ApacheHTTPDImporter(Importer):
     license_url = "https://www.apache.org/licenses/LICENSE-2.0"
     importer_name = "Apache HTTPD Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self):
         links = fetch_links(self.base_url)
         for link in links:
diff --git a/vulnerabilities/importers/apache_kafka.py b/vulnerabilities/importers/apache_kafka.py
index 27c244b2a..880091088 100644
--- a/vulnerabilities/importers/apache_kafka.py
+++ b/vulnerabilities/importers/apache_kafka.py
@@ -102,6 +102,12 @@ def fetch_advisory_page(self):
         page = requests.get(self.GH_PAGE_URL)
         return page.content
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self):
         advisory_page = self.fetch_advisory_page(self)
 
diff --git a/vulnerabilities/importers/apache_tomcat.py b/vulnerabilities/importers/apache_tomcat.py
index 9d371ee7d..0c1df66b8 100644
--- a/vulnerabilities/importers/apache_tomcat.py
+++ b/vulnerabilities/importers/apache_tomcat.py
@@ -120,6 +120,12 @@ class ApacheTomcatImporter(Importer):
     license_url = "https://www.apache.org/licenses/LICENSE-2.0"
     importer_name = "Apache Tomcat Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def fetch_advisory_pages(self):
         """
         Yield the content of each HTML page containing version-related security data.
diff --git a/vulnerabilities/importers/archlinux.py b/vulnerabilities/importers/archlinux.py
index 640fb24dc..259f14d7c 100644
--- a/vulnerabilities/importers/archlinux.py
+++ b/vulnerabilities/importers/archlinux.py
@@ -30,6 +30,12 @@ class ArchlinuxImporter(Importer):
     license_url = "https://github.com/archlinux/arch-security-tracker/blob/master/LICENSE"
     importer_name = "Arch Linux Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def fetch(self) -> Iterable[Mapping]:
         response = fetch_response(self.url)
         return response.json()
diff --git a/vulnerabilities/importers/curl.py b/vulnerabilities/importers/curl.py
index a7f5e86fa..4c26966fb 100644
--- a/vulnerabilities/importers/curl.py
+++ b/vulnerabilities/importers/curl.py
@@ -39,6 +39,12 @@ class CurlImporter(Importer):
     importer_name = "Curl Importer"
     api_url = "https://curl.se/docs/vuln.json"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def fetch(self) -> Iterable[Mapping]:
         response = fetch_response(self.api_url)
         return response.json()
diff --git a/vulnerabilities/importers/debian.py b/vulnerabilities/importers/debian.py
index 7d1ae2071..09cb7b360 100644
--- a/vulnerabilities/importers/debian.py
+++ b/vulnerabilities/importers/debian.py
@@ -82,6 +82,12 @@ class DebianImporter(Importer):
     api_url = "https://security-tracker.debian.org/tracker/data/json"
     importer_name = "Debian Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def get_response(self):
         response = requests.get(self.api_url)
         if response.status_code == 200:
diff --git a/vulnerabilities/importers/debian_oval.py b/vulnerabilities/importers/debian_oval.py
index f5a747a11..b6e892131 100644
--- a/vulnerabilities/importers/debian_oval.py
+++ b/vulnerabilities/importers/debian_oval.py
@@ -56,6 +56,12 @@ class DebianOvalImporter(OvalImporter):
     """
     importer_name = "Debian Oval Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         # we could avoid setting translations, and have it
diff --git a/vulnerabilities/importers/elixir_security.py b/vulnerabilities/importers/elixir_security.py
index 3fe0ec15b..a8ec776ef 100644
--- a/vulnerabilities/importers/elixir_security.py
+++ b/vulnerabilities/importers/elixir_security.py
@@ -41,6 +41,12 @@ def advisory_data(self) -> Set[AdvisoryData]:
             if self.vcs_response:
                 self.vcs_response.delete()
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def process_file(self, file, base_path):
         relative_path = str(file.relative_to(base_path)).strip("/")
         advisory_url = (
diff --git a/vulnerabilities/importers/epss.py b/vulnerabilities/importers/epss.py
index 982229e09..3f7ab1943 100644
--- a/vulnerabilities/importers/epss.py
+++ b/vulnerabilities/importers/epss.py
@@ -29,6 +29,12 @@ class EPSSImporter(Importer):
     spdx_license_expression = "unknown"
     importer_name = "EPSS Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         response = urllib.request.urlopen(self.advisory_url)
         with gzip.open(response, "rb") as f:
diff --git a/vulnerabilities/importers/fireeye.py b/vulnerabilities/importers/fireeye.py
index 03fb3a8d5..03a217ee7 100644
--- a/vulnerabilities/importers/fireeye.py
+++ b/vulnerabilities/importers/fireeye.py
@@ -35,6 +35,12 @@ class FireyeImporter(Importer):
     repo_url = "git+https://github.com/mandiant/Vulnerability-Disclosures"
     importer_name = "FireEye Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
             self.vcs_response = self.clone(repo_url=self.repo_url)
diff --git a/vulnerabilities/importers/gentoo.py b/vulnerabilities/importers/gentoo.py
index 2f569cdf1..a487dcf35 100644
--- a/vulnerabilities/importers/gentoo.py
+++ b/vulnerabilities/importers/gentoo.py
@@ -33,6 +33,12 @@ class GentooImporter(Importer):
     license_url = "https://creativecommons.org/licenses/by-sa/4.0/"
     importer_name = "Gentoo Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
             self.clone(repo_url=self.repo_url)
diff --git a/vulnerabilities/importers/istio.py b/vulnerabilities/importers/istio.py
index 8f9f6334a..0ea6fa1a3 100644
--- a/vulnerabilities/importers/istio.py
+++ b/vulnerabilities/importers/istio.py
@@ -44,6 +44,12 @@ class IstioImporter(Importer):
     repo_url = "git+https://github.com/istio/istio.io/"
     importer_name = "Istio Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Set[AdvisoryData]:
         try:
             self.clone(repo_url=self.repo_url)
diff --git a/vulnerabilities/importers/mozilla.py b/vulnerabilities/importers/mozilla.py
index 8eea10370..f1ba95d92 100644
--- a/vulnerabilities/importers/mozilla.py
+++ b/vulnerabilities/importers/mozilla.py
@@ -39,6 +39,12 @@ class MozillaImporter(Importer):
     repo_url = "git+https://github.com/mozilla/foundation-security-advisories/"
     importer_name = "Mozilla Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
             self.clone(self.repo_url)
diff --git a/vulnerabilities/importers/openssl.py b/vulnerabilities/importers/openssl.py
index b71206418..ec56a0dee 100644
--- a/vulnerabilities/importers/openssl.py
+++ b/vulnerabilities/importers/openssl.py
@@ -35,6 +35,15 @@ class OpensslImporter(Importer):
     url = "https://www.openssl.org/news/vulnerabilities.xml"
     importer_name = "OpenSSL Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        for alias in aliases:
+            if alias.startswith("VC-OPENSSL-"):
+                return alias
+        return None
+
     def fetch(self):
         response = requests.get(url=self.url)
         if not response.status_code == 200:
diff --git a/vulnerabilities/importers/oss_fuzz.py b/vulnerabilities/importers/oss_fuzz.py
index 63b879990..22cf6eca5 100644
--- a/vulnerabilities/importers/oss_fuzz.py
+++ b/vulnerabilities/importers/oss_fuzz.py
@@ -26,6 +26,12 @@ class OSSFuzzImporter(Importer):
     url = "git+https://github.com/google/oss-fuzz-vulns"
     importer_name = "OSS Fuzz Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
             self.clone(repo_url=self.url)
diff --git a/vulnerabilities/importers/postgresql.py b/vulnerabilities/importers/postgresql.py
index 70ab1bfe9..9e9a861cc 100644
--- a/vulnerabilities/importers/postgresql.py
+++ b/vulnerabilities/importers/postgresql.py
@@ -30,6 +30,12 @@ class PostgreSQLImporter(Importer):
     spdx_license_expression = "PostgreSQL"
     importer_name = "PostgreSQL Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self):
         known_urls = {self.root_url}
         visited_urls = set()
diff --git a/vulnerabilities/importers/project_kb_msr2019.py b/vulnerabilities/importers/project_kb_msr2019.py
index a006b1353..0e928b52b 100644
--- a/vulnerabilities/importers/project_kb_msr2019.py
+++ b/vulnerabilities/importers/project_kb_msr2019.py
@@ -24,6 +24,12 @@ class ProjectKBMSRImporter(Importer):
     license_url = "https://github.com/SAP/project-kb/blob/main/LICENSE.txt"
     importer_name = "ProjectKB MSRImporter"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self):
         raw_data = fetch_and_read_from_csv(self.url)
         yield from self.to_advisories(raw_data)
diff --git a/vulnerabilities/importers/redhat.py b/vulnerabilities/importers/redhat.py
index 68e3d5062..b04f9a3ae 100644
--- a/vulnerabilities/importers/redhat.py
+++ b/vulnerabilities/importers/redhat.py
@@ -67,6 +67,12 @@ class RedhatImporter(Importer):
     license_url = "https://access.redhat.com/documentation/en-us/red_hat_security_data_api/1.0/html/red_hat_security_data_api/legal-notice"
     importer_name = "RedHat Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         for redhat_cves in fetch_cves():
             for redhat_cve in redhat_cves:
diff --git a/vulnerabilities/importers/retiredotnet.py b/vulnerabilities/importers/retiredotnet.py
index 139ecd1af..e6474277f 100644
--- a/vulnerabilities/importers/retiredotnet.py
+++ b/vulnerabilities/importers/retiredotnet.py
@@ -44,6 +44,12 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
             if self.vcs_response:
                 self.vcs_response.delete()
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     @staticmethod
     def vuln_id_from_desc(desc):
         cve_regex = re.compile(r"CVE-\d+-\d+")
diff --git a/vulnerabilities/importers/ruby.py b/vulnerabilities/importers/ruby.py
index 268419587..695c1be84 100644
--- a/vulnerabilities/importers/ruby.py
+++ b/vulnerabilities/importers/ruby.py
@@ -72,6 +72,12 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
             if self.vcs_response:
                 self.vcs_response.delete()
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
 
 def parse_ruby_advisory(record, schema_type, advisory_url):
     """
diff --git a/vulnerabilities/importers/xen.py b/vulnerabilities/importers/xen.py
index a0cafa324..232b2e3d5 100644
--- a/vulnerabilities/importers/xen.py
+++ b/vulnerabilities/importers/xen.py
@@ -46,6 +46,12 @@ class XenImporter(Importer):
     """
     importer_name = "Xen Importer"
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisory_data(self):
         data = fetch_response(self.url).json()
         # The data looks like this
diff --git a/vulnerabilities/migrations/0091_advisory_advisory_id.py b/vulnerabilities/migrations/0091_advisory_advisory_id.py
new file mode 100644
index 000000000..ee457986c
--- /dev/null
+++ b/vulnerabilities/migrations/0091_advisory_advisory_id.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.2.17 on 2025-03-28 06:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("vulnerabilities", "0090_migrate_advisory_aliases"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="advisory",
+            name="advisory_id",
+            field=models.CharField(
+                blank=True,
+                help_text="An advisory id, such as CVE-123-345 when available",
+                max_length=100,
+            ),
+        ),
+    ]
diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py
index dba205500..2af1bf55b 100644
--- a/vulnerabilities/models.py
+++ b/vulnerabilities/models.py
@@ -1323,6 +1323,16 @@ class Advisory(models.Model):
         null=False,
         help_text="A 64 character unique identifier for the content of the advisory since we use sha256 as hex",
     )
+
+    advisory_id = models.CharField(
+        max_length=100,
+        blank=True,
+        help_text="An advisory id, such as CVE-123-345 when available",
+    )
+    url = models.URLField(
+        blank=True,
+        help_text="Link to the advisory on the upstream website",
+    )
     aliases = models.ManyToManyField(
         Alias,
         through="AdvisoryRelatedAlias",
@@ -1354,10 +1364,6 @@ class Advisory(models.Model):
         "module name importing the advisory. Eg:"
         "vulnerabilities.pipeline.nginx_importer.NginxImporterPipeline",
     )
-    url = models.URLField(
-        blank=True,
-        help_text="Link to the advisory on the upstream website",
-    )
 
     objects = AdvisoryQuerySet.as_manager()
 
diff --git a/vulnerabilities/pipelines/__init__.py b/vulnerabilities/pipelines/__init__.py
index d74db9f35..634f5e9bc 100644
--- a/vulnerabilities/pipelines/__init__.py
+++ b/vulnerabilities/pipelines/__init__.py
@@ -132,6 +132,22 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
         """
         raise NotImplementedError
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        raise NotImplementedError
+
+    @classmethod
+    def get_cve_id(cls, aliases: list[str]) -> str:
+        """
+        Return the CVE ID for the given aliases.
+        """
+        for alias in aliases:
+            if alias.startswith("CVE-"):
+                return alias
+
     def advisories_count(self) -> int:
         """
         Return the estimated AdvisoryData to be yielded by ``collect_advisories``.
diff --git a/vulnerabilities/pipelines/add_advisory_id.py b/vulnerabilities/pipelines/add_advisory_id.py
new file mode 100644
index 000000000..da0ce68bc
--- /dev/null
+++ b/vulnerabilities/pipelines/add_advisory_id.py
@@ -0,0 +1,53 @@
+# Copyright (c) nexB Inc. and others. All rights reserved.
+# VulnerableCode is a trademark of nexB Inc.
+# SPDX-License-Identifier: Apache-2.0
+# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
+# See https://github.com/aboutcode-org/vulnerablecode for support or download.
+# See https://aboutcode.org for more information about nexB OSS projects.
+#
+
+from aboutcode.pipeline import LoopProgress
+from django.db import transaction
+
+from vulnerabilities.importers import IMPORTERS_REGISTRY
+from vulnerabilities.models import Advisory
+from vulnerabilities.models import Alias
+from vulnerabilities.pipelines import VulnerableCodePipeline
+
+
+class AddAdvisoryID(VulnerableCodePipeline):
+    """
+    Pipeline to map CVEs from VulnerabilitySeverity to corresponding Advisories with CVSS3.1 scores.
+    """
+
+    pipeline_id = "add_advisory_id"
+
+    @classmethod
+    def steps(cls):
+        return (cls.add_advisory_id,)
+
+    def add_advisory_id(self):
+
+        advisories = Advisory.objects.all()
+
+        advisories_to_update = []
+
+        batch_size = 500
+
+        progress = LoopProgress(total_iterations=advisories.count(), logger=self.log)
+
+        for advisory in progress.iter(advisories.iterator(chunk_size=batch_size)):
+            importer_name = advisory.created_by
+            aliases = Alias.objects.filter(advisories=advisory).values_list("alias", flat=True)
+            advisory_id = IMPORTERS_REGISTRY[importer_name].get_advisory_id(aliases=aliases)
+            advisory.advisory_id = advisory_id
+            advisories_to_update.append(advisory)
+            if len(advisories_to_update) >= batch_size:
+                self.do_bulk_update(advisories_to_update)
+                advisories_to_update = []
+        self.do_bulk_update(advisories_to_update)
+        self.log(f"Pipeline [{self.pipeline_name}] completed.")
+
+    def do_bulk_update(self, advisories_to_update):
+        Advisory.objects.bulk_update(advisories_to_update, ["advisory_id"])
+        self.log(f"Updated {len(advisories_to_update)} advisories with advisory_id.")
diff --git a/vulnerabilities/pipelines/alpine_linux_importer.py b/vulnerabilities/pipelines/alpine_linux_importer.py
index 5657ee4d2..4c349572d 100644
--- a/vulnerabilities/pipelines/alpine_linux_importer.py
+++ b/vulnerabilities/pipelines/alpine_linux_importer.py
@@ -45,6 +45,12 @@ def steps(cls):
             cls.import_new_advisories,
         )
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisories_count(self) -> int:
         return 0
 
diff --git a/vulnerabilities/pipelines/github_importer.py b/vulnerabilities/pipelines/github_importer.py
index 66c457824..e1075bef0 100644
--- a/vulnerabilities/pipelines/github_importer.py
+++ b/vulnerabilities/pipelines/github_importer.py
@@ -59,6 +59,16 @@ def steps(cls):
         # "GO": "golang",
     }
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        # return GHSA ID from the aliases
+        for alias in aliases:
+            if alias.startswith("GHSA-"):
+                return alias
+        return self.get_cve_id(aliases)
+
     def advisories_count(self):
         advisory_query = """
         query{
diff --git a/vulnerabilities/pipelines/gitlab_importer.py b/vulnerabilities/pipelines/gitlab_importer.py
index 4f25c4d94..117c8323a 100644
--- a/vulnerabilities/pipelines/gitlab_importer.py
+++ b/vulnerabilities/pipelines/gitlab_importer.py
@@ -66,6 +66,18 @@ def steps(cls):
 
     gitlab_scheme_by_purl_type = {v: k for k, v in purl_type_by_gitlab_scheme.items()}
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        for alias in aliases:
+            if alias.startswith("GMS-"):
+                return alias
+        for alias in aliases:
+            if alias.startswith("CVE-"):
+                return alias
+        return None
+
     def clone(self):
         self.log(f"Cloning `{self.repo_url}`")
         self.vcs_response = fetch_via_vcs(self.repo_url)
diff --git a/vulnerabilities/pipelines/nginx_importer.py b/vulnerabilities/pipelines/nginx_importer.py
index c5e017033..bb3727e78 100644
--- a/vulnerabilities/pipelines/nginx_importer.py
+++ b/vulnerabilities/pipelines/nginx_importer.py
@@ -46,6 +46,12 @@ def fetch(self):
         self.log(f"Fetch `{self.url}`")
         self.advisory_data = requests.get(self.url).text
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def advisories_count(self):
         return self.advisory_data.count("<li><p>")
 
diff --git a/vulnerabilities/pipelines/npm_importer.py b/vulnerabilities/pipelines/npm_importer.py
index 7b6d3aba2..0295adb9b 100644
--- a/vulnerabilities/pipelines/npm_importer.py
+++ b/vulnerabilities/pipelines/npm_importer.py
@@ -48,6 +48,12 @@ def steps(cls):
             cls.clean_downloads,
         )
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def clone(self):
         self.log(f"Cloning `{self.repo_url}`")
         self.vcs_response = fetch_via_vcs(self.repo_url)
diff --git a/vulnerabilities/pipelines/nvd_importer.py b/vulnerabilities/pipelines/nvd_importer.py
index 645b9f442..41302b3f5 100644
--- a/vulnerabilities/pipelines/nvd_importer.py
+++ b/vulnerabilities/pipelines/nvd_importer.py
@@ -68,6 +68,13 @@ class NVDImporterPipeline(VulnerableCodeBaseImporterPipeline):
     """
     importer_name = "NVD Importer"
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return cls.get_cve_id(aliases)
+
     @classmethod
     def steps(cls):
         return (
diff --git a/vulnerabilities/pipelines/pypa_importer.py b/vulnerabilities/pipelines/pypa_importer.py
index aebafacf4..c33d91a62 100644
--- a/vulnerabilities/pipelines/pypa_importer.py
+++ b/vulnerabilities/pipelines/pypa_importer.py
@@ -37,6 +37,12 @@ def steps(cls):
             cls.clean_downloads,
         )
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def clone(self):
         self.log(f"Cloning `{self.repo_url}`")
         self.vcs_response = fetch_via_vcs(self.repo_url)
diff --git a/vulnerabilities/pipelines/pysec_importer.py b/vulnerabilities/pipelines/pysec_importer.py
index 32a9fd896..7d8f6dbe4 100644
--- a/vulnerabilities/pipelines/pysec_importer.py
+++ b/vulnerabilities/pipelines/pysec_importer.py
@@ -36,6 +36,12 @@ def steps(cls):
             cls.import_new_advisories,
         )
 
+    def get_advisory_id(self, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return self.get_cve_id(aliases)
+
     def fetch_zip(self):
         self.log(f"Fetching `{self.url}`")
         self.advisory_zip = requests.get(self.url).content
diff --git a/vulnerabilities/tests/test_add_advisory_pipeline.py b/vulnerabilities/tests/test_add_advisory_pipeline.py
new file mode 100644
index 000000000..e23cce8eb
--- /dev/null
+++ b/vulnerabilities/tests/test_add_advisory_pipeline.py
@@ -0,0 +1,27 @@
+from datetime import datetime
+
+import pytest
+
+from vulnerabilities.importer import AffectedPackage
+from vulnerabilities.importers import nvd_importer
+from vulnerabilities.models import Advisory
+from vulnerabilities.models import Alias
+from vulnerabilities.pipelines import add_advisory_id
+from vulnerabilities.pipes.advisory import get_or_create_aliases
+
+
+@pytest.mark.django_db
+class TestAddAdvisoryPipeline:
+    def test_add_advisory_id(self):
+        aliases = get_or_create_aliases(["CVE-2021-1234"])
+        advisory = Advisory.objects.create(
+            unique_content_id="test-unique-content-id1",
+            created_by=nvd_importer.NVDImporterPipeline.pipeline_id,
+            summary="TEST",
+            date_collected=datetime.now(),
+            url="https://test.com/source",
+        )
+        advisory.aliases.add(*aliases)
+        add_advisory_id.AddAdvisoryID().add_advisory_id()
+        advisory.refresh_from_db()
+        assert advisory.advisory_id == "CVE-2021-1234"

From 4cc772fc9a3eec5c2b75950e135f34cbf021de04 Mon Sep 17 00:00:00 2001
From: Tushar Goel <tushar.goel.dav@gmail.com>
Date: Fri, 28 Mar 2025 12:45:33 +0530
Subject: [PATCH 2/5] Fix tests

Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
---
 vulnerabilities/importer.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/vulnerabilities/importer.py b/vulnerabilities/importer.py
index 2c32e02df..a386102e2 100644
--- a/vulnerabilities/importer.py
+++ b/vulnerabilities/importer.py
@@ -377,13 +377,15 @@ class Importer:
     # It needs to be unique and immutable
     importer_name = ""
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
         raise NotImplementedError
 
-    def get_cve_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_cve_id(cls, aliases: list[str]) -> str:
         """
         Return the CVE ID for the given aliases.
         """

From 47d1f409a18858669bce69dce288735fa6ff758e Mon Sep 17 00:00:00 2001
From: Tushar Goel <tushar.goel.dav@gmail.com>
Date: Fri, 28 Mar 2025 13:18:27 +0530
Subject: [PATCH 3/5] Test all importers for advisory ID

Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
---
 vulnerabilities/importers/apache_httpd.py     |  5 +--
 vulnerabilities/importers/apache_kafka.py     |  5 +--
 vulnerabilities/importers/apache_tomcat.py    |  5 +--
 vulnerabilities/importers/archlinux.py        |  5 +--
 vulnerabilities/importers/curl.py             |  5 +--
 vulnerabilities/importers/debian.py           |  5 +--
 vulnerabilities/importers/debian_oval.py      |  5 +--
 vulnerabilities/importers/elixir_security.py  |  5 +--
 vulnerabilities/importers/epss.py             |  5 +--
 vulnerabilities/importers/fireeye.py          |  5 +--
 vulnerabilities/importers/gentoo.py           |  5 +--
 vulnerabilities/importers/github_osv.py       | 10 ++++++
 vulnerabilities/importers/istio.py            |  5 +--
 vulnerabilities/importers/mozilla.py          |  5 +--
 vulnerabilities/importers/openssl.py          |  5 +--
 vulnerabilities/importers/oss_fuzz.py         |  5 +--
 vulnerabilities/importers/postgresql.py       |  5 +--
 .../importers/project_kb_msr2019.py           |  5 +--
 vulnerabilities/importers/redhat.py           |  5 +--
 vulnerabilities/importers/retiredotnet.py     |  5 +--
 vulnerabilities/importers/ruby.py             | 16 +++++----
 vulnerabilities/importers/suse_oval.py        |  7 ++++
 vulnerabilities/importers/suse_scores.py      |  7 ++++
 vulnerabilities/importers/ubuntu.py           |  7 ++++
 vulnerabilities/importers/ubuntu_usn.py       |  7 ++++
 vulnerabilities/importers/vulnrichment.py     |  7 ++++
 vulnerabilities/importers/xen.py              |  5 +--
 vulnerabilities/pipelines/add_advisory_id.py  |  2 ++
 .../pipelines/alpine_linux_importer.py        |  5 +--
 vulnerabilities/pipelines/github_importer.py  |  5 +--
 vulnerabilities/pipelines/gitlab_importer.py  |  3 +-
 vulnerabilities/pipelines/nginx_importer.py   |  5 +--
 vulnerabilities/pipelines/npm_importer.py     |  5 +--
 vulnerabilities/pipelines/pypa_importer.py    |  5 +--
 vulnerabilities/pipelines/pysec_importer.py   |  5 +--
 .../tests/test_add_advisory_pipeline.py       | 34 +++++++++++--------
 36 files changed, 157 insertions(+), 73 deletions(-)

diff --git a/vulnerabilities/importers/apache_httpd.py b/vulnerabilities/importers/apache_httpd.py
index bd486a3db..9dee86041 100644
--- a/vulnerabilities/importers/apache_httpd.py
+++ b/vulnerabilities/importers/apache_httpd.py
@@ -38,11 +38,12 @@ class ApacheHTTPDImporter(Importer):
     license_url = "https://www.apache.org/licenses/LICENSE-2.0"
     importer_name = "Apache HTTPD Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self):
         links = fetch_links(self.base_url)
diff --git a/vulnerabilities/importers/apache_kafka.py b/vulnerabilities/importers/apache_kafka.py
index 880091088..f14f383b5 100644
--- a/vulnerabilities/importers/apache_kafka.py
+++ b/vulnerabilities/importers/apache_kafka.py
@@ -102,11 +102,12 @@ def fetch_advisory_page(self):
         page = requests.get(self.GH_PAGE_URL)
         return page.content
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self):
         advisory_page = self.fetch_advisory_page(self)
diff --git a/vulnerabilities/importers/apache_tomcat.py b/vulnerabilities/importers/apache_tomcat.py
index 0c1df66b8..4e5498c15 100644
--- a/vulnerabilities/importers/apache_tomcat.py
+++ b/vulnerabilities/importers/apache_tomcat.py
@@ -120,11 +120,12 @@ class ApacheTomcatImporter(Importer):
     license_url = "https://www.apache.org/licenses/LICENSE-2.0"
     importer_name = "Apache Tomcat Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def fetch_advisory_pages(self):
         """
diff --git a/vulnerabilities/importers/archlinux.py b/vulnerabilities/importers/archlinux.py
index 259f14d7c..bf2364056 100644
--- a/vulnerabilities/importers/archlinux.py
+++ b/vulnerabilities/importers/archlinux.py
@@ -30,11 +30,12 @@ class ArchlinuxImporter(Importer):
     license_url = "https://github.com/archlinux/arch-security-tracker/blob/master/LICENSE"
     importer_name = "Arch Linux Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def fetch(self) -> Iterable[Mapping]:
         response = fetch_response(self.url)
diff --git a/vulnerabilities/importers/curl.py b/vulnerabilities/importers/curl.py
index 4c26966fb..ef321dbb6 100644
--- a/vulnerabilities/importers/curl.py
+++ b/vulnerabilities/importers/curl.py
@@ -39,11 +39,12 @@ class CurlImporter(Importer):
     importer_name = "Curl Importer"
     api_url = "https://curl.se/docs/vuln.json"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def fetch(self) -> Iterable[Mapping]:
         response = fetch_response(self.api_url)
diff --git a/vulnerabilities/importers/debian.py b/vulnerabilities/importers/debian.py
index 09cb7b360..583f0c602 100644
--- a/vulnerabilities/importers/debian.py
+++ b/vulnerabilities/importers/debian.py
@@ -82,11 +82,12 @@ class DebianImporter(Importer):
     api_url = "https://security-tracker.debian.org/tracker/data/json"
     importer_name = "Debian Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def get_response(self):
         response = requests.get(self.api_url)
diff --git a/vulnerabilities/importers/debian_oval.py b/vulnerabilities/importers/debian_oval.py
index b6e892131..20dc1aff7 100644
--- a/vulnerabilities/importers/debian_oval.py
+++ b/vulnerabilities/importers/debian_oval.py
@@ -56,11 +56,12 @@ class DebianOvalImporter(OvalImporter):
     """
     importer_name = "Debian Oval Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
diff --git a/vulnerabilities/importers/elixir_security.py b/vulnerabilities/importers/elixir_security.py
index a8ec776ef..70183c3e6 100644
--- a/vulnerabilities/importers/elixir_security.py
+++ b/vulnerabilities/importers/elixir_security.py
@@ -41,11 +41,12 @@ def advisory_data(self) -> Set[AdvisoryData]:
             if self.vcs_response:
                 self.vcs_response.delete()
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def process_file(self, file, base_path):
         relative_path = str(file.relative_to(base_path)).strip("/")
diff --git a/vulnerabilities/importers/epss.py b/vulnerabilities/importers/epss.py
index 3f7ab1943..1c3d5b22f 100644
--- a/vulnerabilities/importers/epss.py
+++ b/vulnerabilities/importers/epss.py
@@ -29,11 +29,12 @@ class EPSSImporter(Importer):
     spdx_license_expression = "unknown"
     importer_name = "EPSS Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
         response = urllib.request.urlopen(self.advisory_url)
diff --git a/vulnerabilities/importers/fireeye.py b/vulnerabilities/importers/fireeye.py
index 03a217ee7..53bf246f5 100644
--- a/vulnerabilities/importers/fireeye.py
+++ b/vulnerabilities/importers/fireeye.py
@@ -35,11 +35,12 @@ class FireyeImporter(Importer):
     repo_url = "git+https://github.com/mandiant/Vulnerability-Disclosures"
     importer_name = "FireEye Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
diff --git a/vulnerabilities/importers/gentoo.py b/vulnerabilities/importers/gentoo.py
index a487dcf35..8b8df30f6 100644
--- a/vulnerabilities/importers/gentoo.py
+++ b/vulnerabilities/importers/gentoo.py
@@ -33,11 +33,12 @@ class GentooImporter(Importer):
     license_url = "https://creativecommons.org/licenses/by-sa/4.0/"
     importer_name = "Gentoo Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
diff --git a/vulnerabilities/importers/github_osv.py b/vulnerabilities/importers/github_osv.py
index f0490044e..1b6c0ebbe 100644
--- a/vulnerabilities/importers/github_osv.py
+++ b/vulnerabilities/importers/github_osv.py
@@ -25,6 +25,16 @@ class GithubOSVImporter(Importer):
     repo_url = "git+https://github.com/github/advisory-database/"
     importer_name = "GithubOSV Importer"
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        for alias in aliases:
+            if alias.startswith("GHSA"):
+                return alias
+        return cls.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         supported_ecosystems = [
             "pypi",
diff --git a/vulnerabilities/importers/istio.py b/vulnerabilities/importers/istio.py
index 0ea6fa1a3..209a8f7a1 100644
--- a/vulnerabilities/importers/istio.py
+++ b/vulnerabilities/importers/istio.py
@@ -44,11 +44,12 @@ class IstioImporter(Importer):
     repo_url = "git+https://github.com/istio/istio.io/"
     importer_name = "Istio Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Set[AdvisoryData]:
         try:
diff --git a/vulnerabilities/importers/mozilla.py b/vulnerabilities/importers/mozilla.py
index f1ba95d92..10862ddb3 100644
--- a/vulnerabilities/importers/mozilla.py
+++ b/vulnerabilities/importers/mozilla.py
@@ -39,11 +39,12 @@ class MozillaImporter(Importer):
     repo_url = "git+https://github.com/mozilla/foundation-security-advisories/"
     importer_name = "Mozilla Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
diff --git a/vulnerabilities/importers/openssl.py b/vulnerabilities/importers/openssl.py
index ec56a0dee..86f2c9b36 100644
--- a/vulnerabilities/importers/openssl.py
+++ b/vulnerabilities/importers/openssl.py
@@ -35,14 +35,15 @@ class OpensslImporter(Importer):
     url = "https://www.openssl.org/news/vulnerabilities.xml"
     importer_name = "OpenSSL Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
         for alias in aliases:
             if alias.startswith("VC-OPENSSL-"):
                 return alias
-        return None
+        return cls.get_cve_id(aliases)
 
     def fetch(self):
         response = requests.get(url=self.url)
diff --git a/vulnerabilities/importers/oss_fuzz.py b/vulnerabilities/importers/oss_fuzz.py
index 22cf6eca5..39eba36ba 100644
--- a/vulnerabilities/importers/oss_fuzz.py
+++ b/vulnerabilities/importers/oss_fuzz.py
@@ -26,11 +26,12 @@ class OSSFuzzImporter(Importer):
     url = "git+https://github.com/google/oss-fuzz-vulns"
     importer_name = "OSS Fuzz Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
diff --git a/vulnerabilities/importers/postgresql.py b/vulnerabilities/importers/postgresql.py
index 9e9a861cc..fed2bb68d 100644
--- a/vulnerabilities/importers/postgresql.py
+++ b/vulnerabilities/importers/postgresql.py
@@ -30,11 +30,12 @@ class PostgreSQLImporter(Importer):
     spdx_license_expression = "PostgreSQL"
     importer_name = "PostgreSQL Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self):
         known_urls = {self.root_url}
diff --git a/vulnerabilities/importers/project_kb_msr2019.py b/vulnerabilities/importers/project_kb_msr2019.py
index 0e928b52b..ebf6f0e4a 100644
--- a/vulnerabilities/importers/project_kb_msr2019.py
+++ b/vulnerabilities/importers/project_kb_msr2019.py
@@ -24,11 +24,12 @@ class ProjectKBMSRImporter(Importer):
     license_url = "https://github.com/SAP/project-kb/blob/main/LICENSE.txt"
     importer_name = "ProjectKB MSRImporter"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self):
         raw_data = fetch_and_read_from_csv(self.url)
diff --git a/vulnerabilities/importers/redhat.py b/vulnerabilities/importers/redhat.py
index b04f9a3ae..8cd08aa16 100644
--- a/vulnerabilities/importers/redhat.py
+++ b/vulnerabilities/importers/redhat.py
@@ -67,11 +67,12 @@ class RedhatImporter(Importer):
     license_url = "https://access.redhat.com/documentation/en-us/red_hat_security_data_api/1.0/html/red_hat_security_data_api/legal-notice"
     importer_name = "RedHat Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
         for redhat_cves in fetch_cves():
diff --git a/vulnerabilities/importers/retiredotnet.py b/vulnerabilities/importers/retiredotnet.py
index e6474277f..1469c1eff 100644
--- a/vulnerabilities/importers/retiredotnet.py
+++ b/vulnerabilities/importers/retiredotnet.py
@@ -44,11 +44,12 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
             if self.vcs_response:
                 self.vcs_response.delete()
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     @staticmethod
     def vuln_id_from_desc(desc):
diff --git a/vulnerabilities/importers/ruby.py b/vulnerabilities/importers/ruby.py
index 695c1be84..537d557a4 100644
--- a/vulnerabilities/importers/ruby.py
+++ b/vulnerabilities/importers/ruby.py
@@ -52,6 +52,16 @@ class RubyImporter(Importer):
     SOFTWARE.
     """
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        for alias in aliases:
+            if alias.startswith("GHSA-"):
+                return alias
+        return cls.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
             self.clone(self.repo_url)
@@ -72,12 +82,6 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
             if self.vcs_response:
                 self.vcs_response.delete()
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
-        """
-        Return the Advisory ID for the given aliases.
-        """
-        return self.get_cve_id(aliases)
-
 
 def parse_ruby_advisory(record, schema_type, advisory_url):
     """
diff --git a/vulnerabilities/importers/suse_oval.py b/vulnerabilities/importers/suse_oval.py
index 0722682f7..8c10d4e88 100644
--- a/vulnerabilities/importers/suse_oval.py
+++ b/vulnerabilities/importers/suse_oval.py
@@ -26,6 +26,13 @@ def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.translations = {"less than": "<", "equals": "=", "greater than or equal": ">="}
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return cls.get_cve_id(aliases)
+
     def _fetch(self):
         page = requests.get(self.base_url).text
         soup = BeautifulSoup(page, "lxml")
diff --git a/vulnerabilities/importers/suse_scores.py b/vulnerabilities/importers/suse_scores.py
index b7f2089ac..9dc891160 100644
--- a/vulnerabilities/importers/suse_scores.py
+++ b/vulnerabilities/importers/suse_scores.py
@@ -26,6 +26,13 @@ class SUSESeverityScoreImporter(Importer):
     license_url = "https://ftp.suse.com/pub/projects/security/yaml/LICENSE"
     importer_name = "SUSE Severity Score Importer"
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return cls.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         score_data = fetch_yaml(URL)
         yield from self.to_advisory(score_data)
diff --git a/vulnerabilities/importers/ubuntu.py b/vulnerabilities/importers/ubuntu.py
index e47515b93..02f01a85e 100644
--- a/vulnerabilities/importers/ubuntu.py
+++ b/vulnerabilities/importers/ubuntu.py
@@ -63,6 +63,13 @@ class UbuntuImporter(OvalImporter):
     """
     importer_name = "Ubuntu OVAL Importer"
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return cls.get_cve_id(aliases)
+
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         # we could avoid setting translations, and have it
diff --git a/vulnerabilities/importers/ubuntu_usn.py b/vulnerabilities/importers/ubuntu_usn.py
index 1aa247ec6..d4c747623 100644
--- a/vulnerabilities/importers/ubuntu_usn.py
+++ b/vulnerabilities/importers/ubuntu_usn.py
@@ -64,6 +64,13 @@ class UbuntuUSNImporter(Importer):
     """
     importer_name = "Ubuntu USN Importer"
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return cls.get_cve_id(aliases)
+
     def advisory_data(self):
         usn_db = fetch(self.db_url)
         yield from self.to_advisories(usn_db=usn_db)
diff --git a/vulnerabilities/importers/vulnrichment.py b/vulnerabilities/importers/vulnrichment.py
index 9eb4d3bcb..32fd8155d 100644
--- a/vulnerabilities/importers/vulnrichment.py
+++ b/vulnerabilities/importers/vulnrichment.py
@@ -25,6 +25,13 @@ class VulnrichImporter(Importer):
     repo_url = "git+https://github.com/cisagov/vulnrichment.git"
     importer_name = "Vulnrichment"
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        return cls.get_cve_id(aliases)
+
     def advisory_data(self) -> Iterable[AdvisoryData]:
         try:
             vcs_response = self.clone(repo_url=self.repo_url)
diff --git a/vulnerabilities/importers/xen.py b/vulnerabilities/importers/xen.py
index 232b2e3d5..aa31fa6d5 100644
--- a/vulnerabilities/importers/xen.py
+++ b/vulnerabilities/importers/xen.py
@@ -46,11 +46,12 @@ class XenImporter(Importer):
     """
     importer_name = "Xen Importer"
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisory_data(self):
         data = fetch_response(self.url).json()
diff --git a/vulnerabilities/pipelines/add_advisory_id.py b/vulnerabilities/pipelines/add_advisory_id.py
index da0ce68bc..8f19abf6c 100644
--- a/vulnerabilities/pipelines/add_advisory_id.py
+++ b/vulnerabilities/pipelines/add_advisory_id.py
@@ -40,6 +40,8 @@ def add_advisory_id(self):
             importer_name = advisory.created_by
             aliases = Alias.objects.filter(advisories=advisory).values_list("alias", flat=True)
             advisory_id = IMPORTERS_REGISTRY[importer_name].get_advisory_id(aliases=aliases)
+            if advisory_id is None:
+                continue
             advisory.advisory_id = advisory_id
             advisories_to_update.append(advisory)
             if len(advisories_to_update) >= batch_size:
diff --git a/vulnerabilities/pipelines/alpine_linux_importer.py b/vulnerabilities/pipelines/alpine_linux_importer.py
index 4c349572d..23392558f 100644
--- a/vulnerabilities/pipelines/alpine_linux_importer.py
+++ b/vulnerabilities/pipelines/alpine_linux_importer.py
@@ -45,11 +45,12 @@ def steps(cls):
             cls.import_new_advisories,
         )
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisories_count(self) -> int:
         return 0
diff --git a/vulnerabilities/pipelines/github_importer.py b/vulnerabilities/pipelines/github_importer.py
index e1075bef0..b26076a89 100644
--- a/vulnerabilities/pipelines/github_importer.py
+++ b/vulnerabilities/pipelines/github_importer.py
@@ -59,7 +59,8 @@ def steps(cls):
         # "GO": "golang",
     }
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
@@ -67,7 +68,7 @@ def get_advisory_id(self, aliases: list[str]) -> str:
         for alias in aliases:
             if alias.startswith("GHSA-"):
                 return alias
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisories_count(self):
         advisory_query = """
diff --git a/vulnerabilities/pipelines/gitlab_importer.py b/vulnerabilities/pipelines/gitlab_importer.py
index 117c8323a..b9507e4a0 100644
--- a/vulnerabilities/pipelines/gitlab_importer.py
+++ b/vulnerabilities/pipelines/gitlab_importer.py
@@ -66,7 +66,8 @@ def steps(cls):
 
     gitlab_scheme_by_purl_type = {v: k for k, v in purl_type_by_gitlab_scheme.items()}
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
diff --git a/vulnerabilities/pipelines/nginx_importer.py b/vulnerabilities/pipelines/nginx_importer.py
index bb3727e78..e1aae0c61 100644
--- a/vulnerabilities/pipelines/nginx_importer.py
+++ b/vulnerabilities/pipelines/nginx_importer.py
@@ -46,11 +46,12 @@ def fetch(self):
         self.log(f"Fetch `{self.url}`")
         self.advisory_data = requests.get(self.url).text
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def advisories_count(self):
         return self.advisory_data.count("<li><p>")
diff --git a/vulnerabilities/pipelines/npm_importer.py b/vulnerabilities/pipelines/npm_importer.py
index 0295adb9b..d4d26c6ee 100644
--- a/vulnerabilities/pipelines/npm_importer.py
+++ b/vulnerabilities/pipelines/npm_importer.py
@@ -48,11 +48,12 @@ def steps(cls):
             cls.clean_downloads,
         )
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def clone(self):
         self.log(f"Cloning `{self.repo_url}`")
diff --git a/vulnerabilities/pipelines/pypa_importer.py b/vulnerabilities/pipelines/pypa_importer.py
index c33d91a62..a90600552 100644
--- a/vulnerabilities/pipelines/pypa_importer.py
+++ b/vulnerabilities/pipelines/pypa_importer.py
@@ -37,11 +37,12 @@ def steps(cls):
             cls.clean_downloads,
         )
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def clone(self):
         self.log(f"Cloning `{self.repo_url}`")
diff --git a/vulnerabilities/pipelines/pysec_importer.py b/vulnerabilities/pipelines/pysec_importer.py
index 7d8f6dbe4..03564a427 100644
--- a/vulnerabilities/pipelines/pysec_importer.py
+++ b/vulnerabilities/pipelines/pysec_importer.py
@@ -36,11 +36,12 @@ def steps(cls):
             cls.import_new_advisories,
         )
 
-    def get_advisory_id(self, aliases: list[str]) -> str:
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
-        return self.get_cve_id(aliases)
+        return cls.get_cve_id(aliases)
 
     def fetch_zip(self):
         self.log(f"Fetching `{self.url}`")
diff --git a/vulnerabilities/tests/test_add_advisory_pipeline.py b/vulnerabilities/tests/test_add_advisory_pipeline.py
index e23cce8eb..4edbeef9a 100644
--- a/vulnerabilities/tests/test_add_advisory_pipeline.py
+++ b/vulnerabilities/tests/test_add_advisory_pipeline.py
@@ -2,10 +2,10 @@
 
 import pytest
 
-from vulnerabilities.importer import AffectedPackage
+from vulnerabilities.importers import IMPORTERS_REGISTRY
 from vulnerabilities.importers import nvd_importer
 from vulnerabilities.models import Advisory
-from vulnerabilities.models import Alias
+from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipeline
 from vulnerabilities.pipelines import add_advisory_id
 from vulnerabilities.pipes.advisory import get_or_create_aliases
 
@@ -13,15 +13,21 @@
 @pytest.mark.django_db
 class TestAddAdvisoryPipeline:
     def test_add_advisory_id(self):
-        aliases = get_or_create_aliases(["CVE-2021-1234"])
-        advisory = Advisory.objects.create(
-            unique_content_id="test-unique-content-id1",
-            created_by=nvd_importer.NVDImporterPipeline.pipeline_id,
-            summary="TEST",
-            date_collected=datetime.now(),
-            url="https://test.com/source",
-        )
-        advisory.aliases.add(*aliases)
-        add_advisory_id.AddAdvisoryID().add_advisory_id()
-        advisory.refresh_from_db()
-        assert advisory.advisory_id == "CVE-2021-1234"
+        for importer in IMPORTERS_REGISTRY.values():
+            if issubclass(importer, VulnerableCodeBaseImporterPipeline):
+                created_by = importer.pipeline_id
+            else:
+                created_by = importer.qualified_name
+            aliases = get_or_create_aliases(["CVE-2021-1234"])
+            advisory = Advisory.objects.create(
+                unique_content_id="test-unique-content-id1",
+                created_by=created_by,
+                summary="TEST",
+                date_collected=datetime.now(),
+                url="https://test.com/source",
+                advisory_id="TEST",
+            )
+            advisory.aliases.add(*aliases)
+            add_advisory_id.AddAdvisoryID().add_advisory_id()
+            advisory.refresh_from_db()
+            assert advisory.advisory_id == "CVE-2021-1234"

From dd228b55707ab8860956466e3876e2765cbbb639 Mon Sep 17 00:00:00 2001
From: Tushar Goel <tushar.goel.dav@gmail.com>
Date: Tue, 15 Apr 2025 14:36:31 +0530
Subject: [PATCH 4/5] Add advisory ID

Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
---
 vulnerabilities/importer.py                         | 1 +
 vulnerabilities/importers/archlinux.py              | 6 +++++-
 vulnerabilities/importers/fireeye.py                | 3 +++
 vulnerabilities/importers/gentoo.py                 | 7 ++++++-
 vulnerabilities/importers/istio.py                  | 7 ++++++-
 vulnerabilities/importers/mozilla.py                | 7 ++++++-
 vulnerabilities/importers/redhat.py                 | 7 ++++++-
 vulnerabilities/importers/ubuntu_usn.py             | 7 ++++++-
 vulnerabilities/importers/xen.py                    | 6 +++++-
 vulnerabilities/pipelines/__init__.py               | 9 +++++++++
 vulnerabilities/pipelines/add_advisory_id.py        | 9 ++++++++-
 vulnerabilities/pipelines/pypa_importer.py          | 3 +++
 vulnerabilities/pipelines/pysec_importer.py         | 3 +++
 vulnerabilities/tests/test_add_advisory_pipeline.py | 1 +
 14 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/vulnerabilities/importer.py b/vulnerabilities/importer.py
index a386102e2..c64dfccaa 100644
--- a/vulnerabilities/importer.py
+++ b/vulnerabilities/importer.py
@@ -376,6 +376,7 @@ class Importer:
     vcs_response: VCSResponse = None
     # It needs to be unique and immutable
     importer_name = ""
+    requires_reference_for_advisory_id = False
 
     @classmethod
     def get_advisory_id(cls, aliases: list[str]) -> str:
diff --git a/vulnerabilities/importers/archlinux.py b/vulnerabilities/importers/archlinux.py
index bf2364056..9207ebe5a 100644
--- a/vulnerabilities/importers/archlinux.py
+++ b/vulnerabilities/importers/archlinux.py
@@ -29,12 +29,16 @@ class ArchlinuxImporter(Importer):
     spdx_license_expression = "MIT"
     license_url = "https://github.com/archlinux/arch-security-tracker/blob/master/LICENSE"
     importer_name = "Arch Linux Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            if ref.get("reference_id").startswith("AVG-"):
+                return ref.get("reference_id")
         return cls.get_cve_id(aliases)
 
     def fetch(self) -> Iterable[Mapping]:
diff --git a/vulnerabilities/importers/fireeye.py b/vulnerabilities/importers/fireeye.py
index 53bf246f5..3b4acd9f7 100644
--- a/vulnerabilities/importers/fireeye.py
+++ b/vulnerabilities/importers/fireeye.py
@@ -40,6 +40,9 @@ def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for alias in aliases:
+            if alias.startswith("MNDT-"):
+                return alias
         return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
diff --git a/vulnerabilities/importers/gentoo.py b/vulnerabilities/importers/gentoo.py
index 8b8df30f6..6aa8a4b81 100644
--- a/vulnerabilities/importers/gentoo.py
+++ b/vulnerabilities/importers/gentoo.py
@@ -32,12 +32,17 @@ class GentooImporter(Importer):
     # under the [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/) license.
     license_url = "https://creativecommons.org/licenses/by-sa/4.0/"
     importer_name = "Gentoo Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            ref_id = ref.get("reference_id")
+            if ref_id and ref_id.startswith("GLSA-"):
+                return ref_id
         return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
diff --git a/vulnerabilities/importers/istio.py b/vulnerabilities/importers/istio.py
index 209a8f7a1..17e5529bd 100644
--- a/vulnerabilities/importers/istio.py
+++ b/vulnerabilities/importers/istio.py
@@ -43,12 +43,17 @@ class IstioImporter(Importer):
     license_url = "https://github.com/istio/istio.io/blob/master/LICENSE"
     repo_url = "git+https://github.com/istio/istio.io/"
     importer_name = "Istio Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            ref_id = ref.get("reference_id")
+            if ref_id and ref_id.startswith("ISTIO-"):
+                return ref_id
         return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Set[AdvisoryData]:
diff --git a/vulnerabilities/importers/mozilla.py b/vulnerabilities/importers/mozilla.py
index 10862ddb3..93776c4f7 100644
--- a/vulnerabilities/importers/mozilla.py
+++ b/vulnerabilities/importers/mozilla.py
@@ -38,12 +38,17 @@ class MozillaImporter(Importer):
     license_url = "https://github.com/mozilla/foundation-security-advisories/blob/master/LICENSE"
     repo_url = "git+https://github.com/mozilla/foundation-security-advisories/"
     importer_name = "Mozilla Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            ref_id = ref.get("reference_id")
+            if ref_id and ref_id.lower().startswith("mfsa"):
+                return ref_id
         return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
diff --git a/vulnerabilities/importers/redhat.py b/vulnerabilities/importers/redhat.py
index 8cd08aa16..b5dac67ed 100644
--- a/vulnerabilities/importers/redhat.py
+++ b/vulnerabilities/importers/redhat.py
@@ -66,12 +66,17 @@ class RedhatImporter(Importer):
     spdx_license_expression = "CC-BY-4.0"
     license_url = "https://access.redhat.com/documentation/en-us/red_hat_security_data_api/1.0/html/red_hat_security_data_api/legal-notice"
     importer_name = "RedHat Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            ref_id = ref.get("reference_id")
+            if ref_id and ref_id.lower().startswith("RHSA-"):
+                return ref_id
         return cls.get_cve_id(aliases)
 
     def advisory_data(self) -> Iterable[AdvisoryData]:
diff --git a/vulnerabilities/importers/ubuntu_usn.py b/vulnerabilities/importers/ubuntu_usn.py
index d4c747623..f32da51e0 100644
--- a/vulnerabilities/importers/ubuntu_usn.py
+++ b/vulnerabilities/importers/ubuntu_usn.py
@@ -63,12 +63,17 @@ class UbuntuUSNImporter(Importer):
     Thanks
     """
     importer_name = "Ubuntu USN Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            reference_id = ref.get("reference_id")
+            if reference_id and reference_id.startswith("USN-"):
+                return reference_id
         return cls.get_cve_id(aliases)
 
     def advisory_data(self):
diff --git a/vulnerabilities/importers/xen.py b/vulnerabilities/importers/xen.py
index aa31fa6d5..18c336bf3 100644
--- a/vulnerabilities/importers/xen.py
+++ b/vulnerabilities/importers/xen.py
@@ -45,12 +45,16 @@ class XenImporter(Importer):
      -George
     """
     importer_name = "Xen Importer"
+    requires_reference_for_advisory_id = True
 
     @classmethod
-    def get_advisory_id(cls, aliases: list[str]) -> str:
+    def get_advisory_id(cls, aliases: list[str], references: list[dict]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for ref in references:
+            if ref.get("reference_id").startswith("XSA-"):
+                return ref.get("reference_id")
         return cls.get_cve_id(aliases)
 
     def advisory_data(self):
diff --git a/vulnerabilities/pipelines/__init__.py b/vulnerabilities/pipelines/__init__.py
index 634f5e9bc..b1b9860f5 100644
--- a/vulnerabilities/pipelines/__init__.py
+++ b/vulnerabilities/pipelines/__init__.py
@@ -13,6 +13,7 @@
 from timeit import default_timer as timer
 from traceback import format_exc as traceback_format_exc
 from typing import Iterable
+from typing import Optional
 
 from aboutcode.pipeline import BasePipeline
 from aboutcode.pipeline import LoopProgress
@@ -114,6 +115,7 @@ class VulnerableCodeBaseImporterPipeline(VulnerableCodePipeline):
     repo_url = None
     importer_name = None
     advisory_confidence = MAX_CONFIDENCE
+    requires_reference_for_advisory_id = False
 
     @classmethod
     def steps(cls):
@@ -132,6 +134,13 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
         """
         raise NotImplementedError
 
+    @classmethod
+    def get_advisory_id(cls, aliases: list[str], references: Optional[list[dict]] = None) -> str:
+        """
+        Return the Advisory ID for the given aliases.
+        """
+        raise NotImplementedError
+
     @classmethod
     def get_advisory_id(cls, aliases: list[str]) -> str:
         """
diff --git a/vulnerabilities/pipelines/add_advisory_id.py b/vulnerabilities/pipelines/add_advisory_id.py
index 8f19abf6c..5a24fee4a 100644
--- a/vulnerabilities/pipelines/add_advisory_id.py
+++ b/vulnerabilities/pipelines/add_advisory_id.py
@@ -39,10 +39,17 @@ def add_advisory_id(self):
         for advisory in progress.iter(advisories.iterator(chunk_size=batch_size)):
             importer_name = advisory.created_by
             aliases = Alias.objects.filter(advisories=advisory).values_list("alias", flat=True)
-            advisory_id = IMPORTERS_REGISTRY[importer_name].get_advisory_id(aliases=aliases)
+            references = advisory.references
+            importer = IMPORTERS_REGISTRY[importer_name]
+            if not importer.requires_reference_for_advisory_id:
+                advisory_id = importer.get_advisory_id(aliases=aliases)
+            else:
+                advisory_id = importer.get_advisory_id(aliases=aliases, references=references)
             if advisory_id is None:
                 continue
             advisory.advisory_id = advisory_id
+            aliases = Alias.objects.filter(advisories=advisory).exclude(alias=advisory_id)
+            advisory.aliases.set(aliases)
             advisories_to_update.append(advisory)
             if len(advisories_to_update) >= batch_size:
                 self.do_bulk_update(advisories_to_update)
diff --git a/vulnerabilities/pipelines/pypa_importer.py b/vulnerabilities/pipelines/pypa_importer.py
index a90600552..520cb8655 100644
--- a/vulnerabilities/pipelines/pypa_importer.py
+++ b/vulnerabilities/pipelines/pypa_importer.py
@@ -42,6 +42,9 @@ def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for alias in aliases:
+            if alias.lower().startswith("pysec-"):
+                return alias
         return cls.get_cve_id(aliases)
 
     def clone(self):
diff --git a/vulnerabilities/pipelines/pysec_importer.py b/vulnerabilities/pipelines/pysec_importer.py
index 03564a427..d9611c621 100644
--- a/vulnerabilities/pipelines/pysec_importer.py
+++ b/vulnerabilities/pipelines/pysec_importer.py
@@ -41,6 +41,9 @@ def get_advisory_id(cls, aliases: list[str]) -> str:
         """
         Return the Advisory ID for the given aliases.
         """
+        for alias in aliases:
+            if alias.startswith("PYSEC-"):
+                return alias
         return cls.get_cve_id(aliases)
 
     def fetch_zip(self):
diff --git a/vulnerabilities/tests/test_add_advisory_pipeline.py b/vulnerabilities/tests/test_add_advisory_pipeline.py
index 4edbeef9a..1c0fb4220 100644
--- a/vulnerabilities/tests/test_add_advisory_pipeline.py
+++ b/vulnerabilities/tests/test_add_advisory_pipeline.py
@@ -31,3 +31,4 @@ def test_add_advisory_id(self):
             add_advisory_id.AddAdvisoryID().add_advisory_id()
             advisory.refresh_from_db()
             assert advisory.advisory_id == "CVE-2021-1234"
+            assert advisory.aliases.count() == 0

From e8d411a4f4a4664047eaa9ddb049108fdd2d2871 Mon Sep 17 00:00:00 2001
From: Tushar Goel <tushar.goel.dav@gmail.com>
Date: Tue, 15 Apr 2025 15:42:14 +0530
Subject: [PATCH 5/5] Add logging

Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
---
 vulnerabilities/pipelines/add_advisory_id.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/vulnerabilities/pipelines/add_advisory_id.py b/vulnerabilities/pipelines/add_advisory_id.py
index 5a24fee4a..92405e66b 100644
--- a/vulnerabilities/pipelines/add_advisory_id.py
+++ b/vulnerabilities/pipelines/add_advisory_id.py
@@ -45,7 +45,8 @@ def add_advisory_id(self):
                 advisory_id = importer.get_advisory_id(aliases=aliases)
             else:
                 advisory_id = importer.get_advisory_id(aliases=aliases, references=references)
-            if advisory_id is None:
+            if not advisory_id:
+                self.log(f"Advisory {advisory.id} does not have an advisory ID. Skipping.")
                 continue
             advisory.advisory_id = advisory_id
             aliases = Alias.objects.filter(advisories=advisory).exclude(alias=advisory_id)