11#
2- # Copyright (c) 2017 nexB Inc. and others. All rights reserved.
2+ # Copyright (c) nexB Inc. and others. All rights reserved.
33# http://nexb.com and https://github.com/nexB/vulnerablecode/
44# The VulnerableCode software is licensed under the Apache License version 2.0.
55# Data generated with VulnerableCode require an acknowledgment.
1818# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
1919# VulnerableCode should be considered or used as legal advice. Consult an Attorney
2020# for any legal advice.
21- # VulnerableCode is a free software code scanning tool from nexB Inc. and others.
21+ # VulnerableCode is a free software tool from nexB Inc. and others.
2222# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2323
2424import importlib
@@ -39,75 +39,87 @@ class Vulnerability(models.Model):
3939 A software vulnerability with minimal information. Identifiers other than CVE ID are stored as
4040 VulnerabilityReference.
4141 """
42- cve_id = models .CharField (
43- max_length = 50 , help_text = 'CVE ID' , unique = True , null = True )
44- summary = models .TextField (
45- help_text = 'Summary of the vulnerability' , blank = True )
46- cvss = models .FloatField (max_length = 100 , help_text = 'CVSS Score' , null = True )
42+
43+ cve_id = models .CharField (max_length = 50 , help_text = "CVE ID" , unique = True , null = True )
44+ summary = models .TextField (help_text = "Summary of the vulnerability" , blank = True )
45+ cvss = models .FloatField (max_length = 100 , help_text = "CVSS Score" , null = True )
4746
4847 @property
4948 def vulnerable_to (self ):
50- return self .packagerelatedvulnerability_set .filter (is_vulnerable = True ).select_related ()
49+ qs = PackageRelatedVulnerability .objects .filter (
50+ vulnerability_id = self .id , is_vulnerable = True
51+ ).select_related ("package" )
52+ return [rel .package for rel in qs ]
5153
5254 @property
5355 def resolved_to (self ):
54- return self .packagerelatedvulnerability_set .filter (is_vulnerable = False ).select_related ()
56+ qs = PackageRelatedVulnerability .objects .filter (
57+ vulnerability_id = self .id , is_vulnerable = False
58+ ).select_related ("package" )
59+ return [rel .package for rel in qs ]
5560
5661 def __str__ (self ):
5762 return self .cve_id or self .summary
5863
5964 class Meta :
60- verbose_name_plural = ' Vulnerabilities'
65+ verbose_name_plural = " Vulnerabilities"
6166
6267
6368class VulnerabilityReference (models .Model ):
6469 """
6570 A reference to a vulnerability such as a security advisory from a Linux distribution or language
6671 package manager.
6772 """
68- vulnerability = models .ForeignKey (
69- Vulnerability , on_delete = models .CASCADE )
70- source = models .CharField (
71- max_length = 50 , help_text = 'Source(s) name eg:NVD' , blank = True )
73+
74+ vulnerability = models .ForeignKey (Vulnerability , on_delete = models .CASCADE )
75+ source = models .CharField (max_length = 50 , help_text = "Source(s) name eg:NVD" , blank = True )
7276 reference_id = models .CharField (
73- max_length = 50 , help_text = ' Reference ID, eg:DSA-4465-1' , blank = True )
74- url = models . URLField (
75- max_length = 1024 , help_text = ' URL of Vulnerability data' , blank = True )
77+ max_length = 50 , help_text = " Reference ID, eg:DSA-4465-1" , blank = True
78+ )
79+ url = models . URLField ( max_length = 1024 , help_text = " URL of Vulnerability data" , blank = True )
7680
7781 class Meta :
78- unique_together = (' vulnerability' , ' source' , ' reference_id' , ' url' )
82+ unique_together = (" vulnerability" , " source" , " reference_id" , " url" )
7983
8084 def __str__ (self ):
81- return f' { self .source } { self .reference_id } { self .url } '
85+ return f" { self .source } { self .reference_id } { self .url } "
8286
8387
8488class Package (PackageURLMixin ):
8589 """
8690 A software package with links to relevant vulnerabilities.
8791 """
92+
8893 vulnerabilities = models .ManyToManyField (
89- to = 'Vulnerability' , through = 'PackageRelatedVulnerability' )
94+ to = "Vulnerability" , through = "PackageRelatedVulnerability"
95+ )
9096
9197 @property
9298 def vulnerable_to (self ):
93- return self .packagerelatedvulnerability_set .filter (is_vulnerable = True ).select_related ()
99+ qs = PackageRelatedVulnerability .objects .filter (
100+ package_id = self .id , is_vulnerable = True
101+ ).select_related ("vulnerability" )
102+ return [rel .vulnerability for rel in qs ]
94103
95104 @property
96105 def resolved_to (self ):
97- return self .packagerelatedvulnerability_set .filter (is_vulnerable = False ).select_related ()
106+ qs = PackageRelatedVulnerability .objects .filter (
107+ package_id = self .id , is_vulnerable = False
108+ ).select_related ("vulnerability" )
109+ return [rel .vulnerability for rel in qs ]
98110
99111 class Meta :
100- unique_together = (' name' , ' namespace' , ' type' ,
101- 'version' , 'qualifiers' , 'subpath' )
112+ unique_together = (" name" , " namespace" , " type" , "version" , "qualifiers" , "subpath" )
113+
102114 # Remove the `qualifers` and `set_package_url` overrides after
103115 # https://github.com/package-url/packageurl-python/pull/35 gets merged
104116 qualifiers = pgfields .JSONField (
105117 default = dict ,
106118 help_text = _ (
107- ' Extra qualifying data for a package such as the name of an OS, '
108- ' architecture, distro, etc.'
119+ " Extra qualifying data for a package such as the name of an OS, "
120+ " architecture, distro, etc."
109121 ),
110- null = True
122+ null = True ,
111123 )
112124
113125 def set_package_url (self , package_url ):
@@ -123,8 +135,7 @@ def set_package_url(self, package_url):
123135 model_field = self ._meta .get_field (field_name )
124136
125137 if value and len (value ) > model_field .max_length :
126- raise ValidationError (
127- _ ('Value too long for field "{}".' .format (field_name )))
138+ raise ValidationError (_ ('Value too long for field "{}".' .format (field_name )))
128139
129140 setattr (self , field_name , value or None )
130141
@@ -142,7 +153,7 @@ class Meta:
142153 # Technically 'is_vulnerable' doesn't belong here. The idea is to
143154 # later filter out for a pairs of ('package', 'vulnerability') which have both
144155 # values of 'is_vulnerable' and ping the data providers to resolve such entries.
145- unique_together = (' package' , ' vulnerability' , ' is_vulnerable' )
156+ unique_together = (" package" , " vulnerability" , " is_vulnerable" )
146157
147158
148159class ImportProblem (models .Model ):
@@ -155,26 +166,23 @@ class Importer(models.Model):
155166 Metadata and pointer to the implementation for a source of vulnerability data (aka security
156167 advisories)
157168 """
158- name = models . CharField ( max_length = 100 , unique = True ,
159- help_text = ' Name of the importer' )
169+
170+ name = models . CharField ( max_length = 100 , unique = True , help_text = " Name of the importer" )
160171
161172 license = models .CharField (
162- max_length = 100 ,
163- blank = True ,
164- help_text = 'License of the vulnerability data' ,
173+ max_length = 100 , blank = True , help_text = "License of the vulnerability data" ,
165174 )
166175
167- last_run = models .DateTimeField (
168- null = True , help_text = 'UTC Timestamp of the last run' )
176+ last_run = models .DateTimeField (null = True , help_text = "UTC Timestamp of the last run" )
169177
170178 data_source = models .CharField (
171179 max_length = 100 ,
172- help_text = ' Name of the data source implementation importable from vulnerabilities.importers'
180+ help_text = " Name of the data source implementation importable from vulnerabilities.importers" , # nopep8
173181 )
174182 data_source_cfg = pgfields .JSONField (
175183 null = False ,
176184 default = dict ,
177- help_text = ' Implementation-specific configuration for the data source' ,
185+ help_text = " Implementation-specific configuration for the data source" ,
178186 )
179187
180188 def make_data_source (self , batch_size : int , cutoff_date : datetime = None ) -> DataSource :
@@ -184,7 +192,7 @@ def make_data_source(self, batch_size: int, cutoff_date: datetime = None) -> Dat
184192 batch_size - max. number of records to return on each iteration
185193 cutoff_date - optional timestamp of the oldest data to include in the import
186194 """
187- importers_module = importlib .import_module (' vulnerabilities.importers' )
195+ importers_module = importlib .import_module (" vulnerabilities.importers" )
188196 klass = getattr (importers_module , self .data_source )
189197
190198 ds = klass (
0 commit comments