From 525d8d339c747e2a560b804a30f0fccc38dcd869 Mon Sep 17 00:00:00 2001 From: tdruez Date: Mon, 5 Aug 2024 18:53:26 +0400 Subject: [PATCH] Remove the user requirement on the Vulnerability model #138 Signed-off-by: tdruez --- .../commands/fetchvulnerabilities.py | 18 +++--------- ...emove_vulnerability_created_by_and_more.py | 21 ++++++++++++++ component_catalog/models.py | 29 +++++++++++++++---- 3 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 component_catalog/migrations/0008_remove_vulnerability_created_by_and_more.py diff --git a/component_catalog/management/commands/fetchvulnerabilities.py b/component_catalog/management/commands/fetchvulnerabilities.py index e84a3dad..83bf7957 100644 --- a/component_catalog/management/commands/fetchvulnerabilities.py +++ b/component_catalog/management/commands/fetchvulnerabilities.py @@ -6,7 +6,6 @@ # See https://aboutcode.org for more information about AboutCode FOSS projects. # - from django.core.management.base import CommandError from component_catalog.models import Component @@ -14,7 +13,6 @@ from component_catalog.models import Vulnerability from dejacode_toolkit.vulnerablecode import VulnerableCode from dje.management.commands import DataspacedCommand -from dje.models import DejacodeUser from dje.utils import chunked @@ -23,11 +21,8 @@ class Command(DataspacedCommand): def handle(self, *args, **options): super().handle(*args, **options) - # chunk_size=10 -> make this configurable and see figure out best default + # TODO: chunk_size=10 -> make this configurable and see figure out best default - # TODO: Consider making the user optional on the Vulnerability model as its - # automatically collected - user = DejacodeUser.objects.scope(self.dataspace).all()[0] vulnerablecode = VulnerableCode(self.dataspace) if not self.dataspace.enable_vulnerablecodedb_access: @@ -63,17 +58,12 @@ def handle(self, *args, **options): if not affected_packages: raise CommandError("Could not find package!") - # django.db.utils.IntegrityError: duplicate key value violates unique - # constraint "component_catalog_vulnerability_vulnerability_id_key" - # DETAIL: Key (vulnerability_id)=(VCID-311z-mwbu-aaac) already exists. - for vulnerability in affected_by_vulnerabilities: - if vulnerability_qs.filter( - vulnerability_id=vulnerability["vulnerability_id"] - ).exists(): + vulnerability_id = vulnerability["vulnerability_id"] + if vulnerability_qs.filter(vulnerability_id=vulnerability_id).exists(): continue # -> TODO: Update from data in that case? Vulnerability.create_from_data( - user=user, + dataspace=self.dataspace, data=vulnerability, affected_packages=affected_packages, ) diff --git a/component_catalog/migrations/0008_remove_vulnerability_created_by_and_more.py b/component_catalog/migrations/0008_remove_vulnerability_created_by_and_more.py new file mode 100644 index 00000000..872f9e5a --- /dev/null +++ b/component_catalog/migrations/0008_remove_vulnerability_created_by_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 5.0.6 on 2024-08-05 13:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('component_catalog', '0007_vulnerability_affected_components_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='vulnerability', + name='created_by', + ), + migrations.RemoveField( + model_name='vulnerability', + name='last_modified_by', + ), + ] diff --git a/component_catalog/models.py b/component_catalog/models.py index 2ba0cea2..221bbd44 100644 --- a/component_catalog/models.py +++ b/component_catalog/models.py @@ -64,6 +64,7 @@ from dje.models import DataspacedQuerySet from dje.models import ExternalReferenceMixin from dje.models import History +from dje.models import HistoryDateFieldsMixin from dje.models import HistoryFieldsMixin from dje.models import ParentChildModelMixin from dje.models import ParentChildRelationshipModel @@ -2514,12 +2515,16 @@ def __str__(self): return f"<{self.component}>: {self.package}" -class Vulnerability(HistoryFieldsMixin, DataspacedModel): +class Vulnerability(HistoryDateFieldsMixin, DataspacedModel): """ A software vulnerability with a unique identifier and alternate aliases. Adapted from the VulnerabeCode models at https://github.com/nexB/vulnerablecode/blob/main/vulnerabilities/models.py#L164 + + Note that this model implements the HistoryDateFieldsMixin but not the + HistoryUserFieldsMixin as the Vulnerability records are usually created + automatically on object addition or during schedule tasks. """ vulnerability_id = models.CharField( @@ -2584,14 +2589,26 @@ def add_affected_components(self, components): @classmethod def create_from_data( - cls, user, data, validate=False, affected_packages=None, affected_components=None + cls, dataspace, data, validate=False, affected_packages=None, affected_components=None ): - vulnerability = super().create_from_data(user, data, validate=validate) + # TODO: Remove duplication with super() + model_fields = cls.model_fields() + cleaned_data = { + field_name: value + for field_name, value in data.items() + if field_name in model_fields and value not in EMPTY_VALUES + } + + instance = cls(dataspace=dataspace, **cleaned_data) + + if validate: + instance.full_clean() + instance.save() if affected_packages: - vulnerability.add_affected_packages(affected_packages) + instance.add_affected_packages(affected_packages) if affected_components: - vulnerability.add_affected_component(affected_components) + instance.add_affected_component(affected_components) - return vulnerability + return instance