diff --git a/manage.py b/manage.py index 2bbaaa57c..78e780e65 100755 --- a/manage.py +++ b/manage.py @@ -1,6 +1,9 @@ #!/usr/bin/env python if __name__ == "__main__": + import site + site.addsitedir(r"C:\Users\Mohammed Anas\AppData\Roaming\Python\Python314\site-packages") + from vulnerablecode import command_line command_line() diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index d994b297d..784ebeb26 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -263,7 +263,9 @@ def get_severity_range_score(self, instance): if s.scoring_system == EPSS.identifier: continue - if s.scoring_elements and s.scoring_system in SCORING_SYSTEMS: + if s.scoring_elements_data: + severity_vectors.append(s.scoring_elements_data) + elif s.scoring_elements and s.scoring_system in SCORING_SYSTEMS: try: vector_values = SCORING_SYSTEMS[s.scoring_system].get(s.scoring_elements) severity_vectors.append(vector_values) diff --git a/vulnerabilities/migrations/0105_packagecommitpatch_patch_and_more.py b/vulnerabilities/migrations/0105_packagecommitpatch_patch_and_more.py index 5b1337422..92e08c2a1 100644 --- a/vulnerabilities/migrations/0105_packagecommitpatch_patch_and_more.py +++ b/vulnerabilities/migrations/0105_packagecommitpatch_patch_and_more.py @@ -100,7 +100,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="patch", constraint=models.CheckConstraint( - check=models.Q( + condition=models.Q( models.Q( ("patch_url__isnull", False), models.Q(("patch_url", ""), _negated=True) ), diff --git a/vulnerabilities/migrations/0106_alter_advisoryreference_url_and_more.py b/vulnerabilities/migrations/0106_alter_advisoryreference_url_and_more.py index cd13721e9..fabd67f9c 100644 --- a/vulnerabilities/migrations/0106_alter_advisoryreference_url_and_more.py +++ b/vulnerabilities/migrations/0106_alter_advisoryreference_url_and_more.py @@ -40,7 +40,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="advisoryseverity", constraint=models.CheckConstraint( - check=models.Q( + condition=models.Q( models.Q(("value__isnull", False), models.Q(("value", ""), _negated=True)), models.Q( ("scoring_elements__isnull", False), diff --git a/vulnerabilities/migrations/0112_vulnerabilityseverity_scoring_elements_data.py b/vulnerabilities/migrations/0112_vulnerabilityseverity_scoring_elements_data.py new file mode 100644 index 000000000..a2f830935 --- /dev/null +++ b/vulnerabilities/migrations/0112_vulnerabilityseverity_scoring_elements_data.py @@ -0,0 +1,42 @@ +# Generated by Django 6.0.1 on 2026-01-27 10:41 + +from django.db import migrations, models + + +from vulnerabilities.severity_systems import SCORING_SYSTEMS +from cvss.exceptions import CVSS2MalformedError +from cvss.exceptions import CVSS3MalformedError +from cvss.exceptions import CVSS4MalformedError + +def backfill_scoring_data(apps, schema_editor): + VulnerabilitySeverity = apps.get_model('vulnerabilities', 'VulnerabilitySeverity') + for vs in VulnerabilitySeverity.objects.all(): + if vs.scoring_elements and vs.scoring_system in SCORING_SYSTEMS: + try: + vs.scoring_elements_data = SCORING_SYSTEMS[vs.scoring_system].get( + vs.scoring_elements + ) + except ( + CVSS2MalformedError, + CVSS3MalformedError, + CVSS4MalformedError, + NotImplementedError, + Exception, + ): + vs.scoring_elements_data = {} + vs.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('vulnerabilities', '0111_alter_advisoryseverity_scoring_system_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='vulnerabilityseverity', + name='scoring_elements_data', + field=models.JSONField(blank=True, default=dict, help_text='The parsed data from the scoring elements.'), + ), + migrations.RunPython(backfill_scoring_data, migrations.RunPython.noop), + ] diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 451db71eb..203eabcd2 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -208,6 +208,12 @@ class VulnerabilitySeverity(models.Model): help_text="Supporting scoring elements used to compute the score values. " "For example a CVSS vector string as used to compute a CVSS score.", ) + + scoring_elements_data = models.JSONField( + default=dict, + blank=True, + help_text="The parsed data from the scoring elements." + ) published_at = models.DateTimeField( blank=True, null=True, help_text="UTC Date of publication of the vulnerability severity" @@ -215,6 +221,22 @@ class VulnerabilitySeverity(models.Model): objects = BaseQuerySet.as_manager() + def save(self, *args, **kwargs): + if self.scoring_elements and self.scoring_system in SCORING_SYSTEMS: + try: + self.scoring_elements_data = SCORING_SYSTEMS[self.scoring_system].get( + self.scoring_elements + ) + except ( + CVSS2MalformedError, + CVSS3MalformedError, + CVSS4MalformedError, + NotImplementedError, + Exception, + ): + self.scoring_elements_data = {} + super().save(*args, **kwargs) + class Meta: verbose_name_plural = "Vulnerability severities" ordering = ["url", "scoring_system", "value"] @@ -2590,7 +2612,7 @@ class Meta: unique_together = ("url", "scoring_system", "value", "scoring_elements", "published_at") constraints = [ models.CheckConstraint( - check=( + condition=( Q(value__isnull=False) & ~Q(value="") | Q(scoring_elements__isnull=False) & ~Q(scoring_elements="") ), @@ -2788,7 +2810,7 @@ class Meta: unique_together = ["patch_checksum", "patch_url"] constraints = [ models.CheckConstraint( - check=( + condition=( Q(patch_url__isnull=False) & ~Q(patch_url="") | Q(patch_text__isnull=False) & ~Q(patch_text="") ),