2929from django .core .validators import MaxValueValidator
3030from django .core .validators import MinValueValidator
3131from django .db import models
32+ from django .utils .http import int_to_base36
3233from packageurl import PackageURL
3334from packageurl .contrib .django .models import PackageURLMixin
3435
@@ -47,12 +48,12 @@ class Vulnerability(models.Model):
4748 stored as ``Alias``.
4849 """
4950
50- vulnerability_id = models .UUIDField (
51- default = uuid .uuid4 ,
52- editable = False ,
51+ vulnerability_id = models .CharField (
5352 unique = True ,
54- help_text = "Unique identifier for a vulnerability in this database, assigned automatically. "
55- "In the external representation it is prefixed with VULCOID-" ,
53+ blank = True ,
54+ max_length = 20 ,
55+ help_text = "Unique identifier for a vulnerability in the external representation. "
56+ "It is prefixed with VULCOID-" ,
5657 )
5758
5859 summary = models .TextField (
@@ -63,28 +64,42 @@ class Vulnerability(models.Model):
6364 references = models .ManyToManyField (
6465 to = "VulnerabilityReference" , through = "VulnerabilityRelatedReference"
6566 )
67+ packages = models .ManyToManyField (
68+ to = "Package" ,
69+ through = "PackageRelatedVulnerability" ,
70+ )
6671
67- @property
68- def vulcoid (self ):
69- return f"VULCOID-{ self .vulnerability_id } "
72+ def save (self , * args , ** kwargs ):
73+ super ().save (* args , ** kwargs )
74+ if not self .vulnerability_id :
75+ self .vulnerability_id = f"VULCOID-{ int_to_base36 (self .id ).upper ()} "
76+ super ().save (update_fields = ["vulnerability_id" ])
7077
7178 @property
7279 def vulnerable_to (self ):
7380 """
7481 Return packages that are vulnerable to this vulnerability.
7582 """
76- return self .packages .filter (vulnerabilities__packagerelatedvulnerability__fix = False )
83+ return self .packages .filter (packagerelatedvulnerability__fix = False )
7784
7885 @property
7986 def resolved_to (self ):
8087 """
8188 Returns packages that first received patch against this vulnerability
8289 in their particular version history.
8390 """
84- return self .packages .filter (vulnerabilities__packagerelatedvulnerability__fix = True )
91+ return self .packages .filter (packagerelatedvulnerability__fix = True )
92+
93+ @property
94+ def alias (self ):
95+ """
96+ Returns packages that first received patch against this vulnerability
97+ in their particular version history.
98+ """
99+ return self .aliases .all ()
85100
86101 def __str__ (self ):
87- return self .vulcoid
102+ return self .vulnerability_id
88103
89104 class Meta :
90105 verbose_name_plural = "Vulnerabilities"
@@ -150,10 +165,7 @@ class Package(PackageURLMixin):
150165 """
151166
152167 vulnerabilities = models .ManyToManyField (
153- to = "Vulnerability" ,
154- through = "PackageRelatedVulnerability" ,
155- through_fields = ("package" , "vulnerability" ),
156- related_name = "packages" ,
168+ to = "Vulnerability" , through = "PackageRelatedVulnerability"
157169 )
158170
159171 # Remove the `qualifers` and `set_package_url` overrides after
@@ -218,8 +230,14 @@ def __str__(self):
218230class PackageRelatedVulnerability (models .Model ):
219231
220232 # TODO: Fix related_name
221- package = models .ForeignKey (Package , on_delete = models .CASCADE , related_name = "package" )
222- vulnerability = models .ForeignKey (Vulnerability , on_delete = models .CASCADE )
233+ package = models .ForeignKey (
234+ Package ,
235+ on_delete = models .CASCADE ,
236+ )
237+ vulnerability = models .ForeignKey (
238+ Vulnerability ,
239+ on_delete = models .CASCADE ,
240+ )
223241 created_by = models .CharField (
224242 max_length = 100 ,
225243 blank = True ,
0 commit comments