Skip to content

Commit f05bb8c

Browse files
committed
Use to_dict, add docs, infer as function name
The refactors are based on #525 (review) - class Inference: order should be the logic order from most important to least important fields - class Improver: docs - data_source.py: Use to_dict() than json() - models: Advisory: docs - improvers/nginx.py: Removed, relevant improvers will now reside inside importer module. In this case, importers/nginx.py - black formatting Signed-off-by: Hritik Vijay <hritikxx8@gmail.com>
1 parent 38f5872 commit f05bb8c

8 files changed

Lines changed: 64 additions & 89 deletions

File tree

vulnerabilities/data_inference.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ class Inference:
3030
relationship is to be inserted into the database
3131
"""
3232

33+
vulnerability_id: str
3334
confidence: int
3435
summary: Optional[str] = None
35-
vulnerability_id: Optional[str] = None
3636
affected_packages: List[PackageURL] = dataclasses.field(default_factory=list)
3737
fixed_packages: List[PackageURL] = dataclasses.field(default_factory=list)
3838
references: List[Reference] = dataclasses.field(default_factory=list)
@@ -47,9 +47,12 @@ def __post_init__(self):
4747

4848
class Improver:
4949
"""
50-
All improvers should inherit this class and implement inferences method to return
51-
new inferences for packages or vulnerabilities
50+
All improvers must inherit this class and implement the infer method to
51+
return new inferences for packages or vulnerabilities
5252
"""
5353

54-
def inferences(self) -> List[Inference]:
54+
def infer(self) -> List[Inference]:
55+
"""
56+
Implement this method to generate and return Inferences
57+
"""
5558
raise NotImplementedError

vulnerabilities/data_source.py

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,19 @@ class AffectedPackage:
8181
# the version specifier contains the version scheme as is: semver:>=1,3,4
8282
version_specifier: VersionSpecifier
8383

84-
def json(self):
84+
def to_dict(self):
8585
# TODO: VersionSpecifier.__str__ is not working
8686
# https://github.com/nexB/univers/issues/7
8787
# Adjust following code when it is fixed
8888
scheme = self.version_specifier.scheme
8989
ranges = ",".join(
9090
[f"{rng.operator}{rng.version.value}" for rng in self.version_specifier.ranges]
9191
)
92-
return json.dumps({"package": self.package, "version_specifier": f"{scheme}:{ranges}"})
92+
return {"package": self.package, "version_specifier": f"{scheme}:{ranges}"}
9393

9494
@staticmethod
95-
def from_json(affected_package_json):
96-
obj = json.loads(affected_package_json)
97-
affected_package = AffectedPackage(**obj)
95+
def from_dict(affected_package_dict):
96+
affected_package = AffectedPackage(**affected_package_dict)
9897
package = PackageURL(*affected_package.package)
9998
version_specifier = VersionSpecifier.from_version_spec_string(
10099
affected_package.version_specifier
@@ -117,33 +116,29 @@ class AdvisoryData:
117116
affected_packages: List[AffectedPackage] = dataclasses.field(default_factory=list)
118117
fixed_packages: List[AffectedPackage] = dataclasses.field(default_factory=list)
119118
references: List[Reference] = dataclasses.field(default_factory=list)
120-
date_published: Optional[str] = None
119+
date_published: Optional[datetime.date] = None
121120

122121
def normalized(self):
123122
...
124123

125-
def serializable(self, o):
126-
if isinstance(o, AffectedPackage):
127-
return o.json()
128-
if isinstance(o, Reference):
129-
return vars(o)
130-
if isinstance(o, datetime):
131-
return o.isoformat()
132-
133-
return json.JSONEncoder.default(self, o)
134-
135-
def json(self):
136-
return json.dumps(vars(self), default=self.serializable)
124+
def to_dict(self):
125+
return {
126+
"summary": self.summary,
127+
"vulnerability_id": self.vulnerability_id,
128+
"affected_packages": [pkg.to_dict() for pkg in self.affected_packages],
129+
"fixed_packages": [pkg.to_dict() for pkg in self.fixed_packages],
130+
"references": [vars(ref) for ref in self.references],
131+
"date_published": self.date_published.isoformat(),
132+
}
137133

138134
@staticmethod
139-
def from_json(advisory_data_json: str):
140-
obj = json.loads(advisory_data_json)
141-
advisory_data = AdvisoryData(**obj)
135+
def from_dict(advisory_data_dict: str):
136+
advisory_data = AdvisoryData(**advisory_data_dict)
142137
advisory_data.affected_packages = [
143-
AffectedPackage.from_json(p) for p in advisory_data.affected_packages
138+
AffectedPackage.from_dict(p) for p in advisory_data.affected_packages
144139
]
145140
advisory_data.fixed_packages = [
146-
AffectedPackage.from_json(p) for p in advisory_data.fixed_packages
141+
AffectedPackage.from_dict(p) for p in advisory_data.fixed_packages
147142
]
148143
advisory_data.references = [Reference(**ref) for ref in advisory_data.references]
149144
return advisory_data

vulnerabilities/import_runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def process_advisories(source: str, advisory_data: Set[AdvisoryData]) -> None:
124124
date_published=data.date_published,
125125
date_collected=datetime.datetime.now(tz=datetime.timezone.utc),
126126
source=source,
127-
data=data.json(),
127+
data=json.dumps(data.to_dict()),
128128
)
129129
)
130130

vulnerabilities/improve_runner.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ def run(self) -> None:
3838
def process_inferences(source: str, inferences: Set[Inference]):
3939
bulk_create_vuln_pkg_refs = set()
4040
for inference in inferences:
41-
vuln, vuln_created = _get_or_create_vulnerability(inference.vulnerability_id, inference.summary)
41+
vuln, vuln_created = _get_or_create_vulnerability(
42+
inference.vulnerability_id, inference.summary
43+
)
4244
for vuln_ref in inference.references:
4345
ref, _ = models.VulnerabilityReference.objects.get_or_create(
4446
vulnerability=vuln, reference_id=vuln_ref.reference_id, url=vuln_ref.url
@@ -77,9 +79,7 @@ def process_inferences(source: str, inferences: Set[Inference]):
7779
)
7880

7981

80-
def _get_or_create_vulnerability(
81-
vulnerability_id, summary
82-
) -> Tuple[models.Vulnerability, bool]:
82+
def _get_or_create_vulnerability(vulnerability_id, summary) -> Tuple[models.Vulnerability, bool]:
8383

8484
vuln, created = models.Vulnerability.objects.get_or_create(
8585
vulnerability_id=vulnerability_id

vulnerabilities/improvers/default.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
from typing import List
23
from itertools import chain
34

@@ -11,14 +12,15 @@
1112
from vulnerabilities.data_inference import MAX_CONFIDENCE
1213
from vulnerabilities.models import Advisory
1314

15+
1416
class DefaultImprover(Improver):
1517
def inferences(self) -> List[Inference]:
1618
advisories = Advisory.objects.all()
1719

1820
inferences = []
1921

2022
for advisory in advisories:
21-
advisory_data = AdvisoryData.from_json(advisory.data)
23+
advisory_data = AdvisoryData.from_dict(json.loads(advisory.data))
2224

2325
affected_packages = chain.from_iterable(
2426
[exact_purls(pkg) for pkg in advisory_data.affected_packages]
@@ -55,7 +57,7 @@ def exact_purls(pkg: AffectedPackage) -> List[PackageURL]:
5557
purls = []
5658
for rng in vs.ranges:
5759
if "=" in rng.operator and not "!" in rng.operator:
58-
purl = pkg.package._replace(version = rng.version.value)
60+
purl = pkg.package._replace(version=rng.version.value)
5961
purls.append(purl)
6062

6163
return purls

vulnerabilities/improvers/nginx.py

Lines changed: 0 additions & 44 deletions
This file was deleted.

vulnerabilities/models.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,19 @@ class Meta:
320320

321321

322322
class Advisory(models.Model):
323-
date_published = models.DateField()
324-
date_collected = models.DateField()
325-
source = models.CharField(max_length=100)
326-
improved_on = models.DateTimeField(null=True)
327-
improved_times = models.IntegerField(default=0)
328-
# data would contain a data_source.AdvisoryData
329-
data = models.JSONField()
323+
"""
324+
An advisory directly obtained from upstream without any modifications.
325+
"""
326+
327+
date_published = models.DateField(help_text="Date of publication of the advisory")
328+
date_collected = models.DateField(help_text="Date on which the advisory was collected")
329+
source = models.CharField(
330+
max_length=100,
331+
help_text="Fully qualified name of the importer prefixed with the module name importing the advisory. Eg: vulnerabilities.importers.nginx.NginxDataSource",
332+
)
333+
date_improved = models.DateTimeField(
334+
null=True, help_text="Latest date on which the advisory was improved by an improver"
335+
)
336+
data = models.JSONField(
337+
help_text="Contents of data_source.AdvisoryData serialized as a JSON object"
338+
)

vulnerabilities/views.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,14 @@ def request_to_queryset(request):
7474
models.Package.objects.all()
7575
.filter(name__icontains=package_name, type__icontains=package_type)
7676
.annotate(
77-
vulnerability_count=Count("vulnerabilities", filter=Q(vulnerabilities__packagerelatedvulnerability__fix=False)),
78-
patched_vulnerability_count=Count("vulnerabilities",filter=Q(vulnerabilities__packagerelatedvulnerability__fix=True)),
77+
vulnerability_count=Count(
78+
"vulnerabilities",
79+
filter=Q(vulnerabilities__packagerelatedvulnerability__fix=False),
80+
),
81+
patched_vulnerability_count=Count(
82+
"vulnerabilities",
83+
filter=Q(vulnerabilities__packagerelatedvulnerability__fix=True),
84+
),
7985
)
8086
.prefetch_related()
8187
)
@@ -102,8 +108,12 @@ def request_to_vulnerabilities(request):
102108
vuln_id = request.GET["vuln_id"]
103109
return list(
104110
models.Vulnerability.objects.filter(vulnerability_id__icontains=vuln_id).annotate(
105-
vulnerable_package_count=Count("packages", filter=Q(packagerelatedvulnerability__fix=False)),
106-
patched_package_count=Count("packages", filter=Q(packagerelatedvulnerability__fix=True)),
111+
vulnerable_package_count=Count(
112+
"packages", filter=Q(packagerelatedvulnerability__fix=False)
113+
),
114+
patched_package_count=Count(
115+
"packages", filter=Q(packagerelatedvulnerability__fix=True)
116+
),
107117
)
108118
)
109119

0 commit comments

Comments
 (0)