Skip to content

Commit 5080ea3

Browse files
committed
Remove the weaknesses table header
Fix expected_files tests Fix all test cases Add CWE support for NVD importer Fix migration conflict Add Weakness model Fix requirements.txt , Fix migration conflict Add cwe name instead of Hyperlinks Add nexB/cwe package Fix test , remove empty lines Add CWE in the new UI Signed-off-by: ziadhany <ziadhany2016@gmail.com>
1 parent 40a3974 commit 5080ea3

File tree

63 files changed

+1451
-664
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1451
-664
lines changed

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,5 @@ drf-spectacular-sidecar==2022.10.1
120120
drf-spectacular==0.24.2
121121
coreapi==2.3.3
122122
coreschema==0.0.4
123-
itypes==1.2.0
123+
itypes==1.2.0
124+
cwe2==2.0.0

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ install_requires =
8484
Markdown>=3.3.0
8585
dateparser>=1.1.1
8686
cvss>=2.4
87+
cwe2>=2.0.0
8788

8889
# networking
8990
GitPython>=3.1.17

vulnerabilities/import_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def process_advisories(advisory_datas: Iterable[AdvisoryData], importer_name: st
6161
affected_packages=[pkg.to_dict() for pkg in data.affected_packages],
6262
references=[ref.to_dict() for ref in data.references],
6363
date_published=data.date_published,
64+
weaknesses=data.weaknesses,
6465
defaults={
6566
"created_by": importer_name,
6667
"date_collected": datetime.datetime.now(tz=datetime.timezone.utc),

vulnerabilities/importer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ class AdvisoryData:
246246
affected_packages: List[AffectedPackage] = dataclasses.field(default_factory=list)
247247
references: List[Reference] = dataclasses.field(default_factory=list)
248248
date_published: Optional[datetime.datetime] = None
249+
weaknesses: List[int] = dataclasses.field(default_factory=list)
249250

250251
def __post_init__(self):
251252
if self.date_published and not self.date_published.tzinfo:
@@ -258,6 +259,7 @@ def to_dict(self):
258259
"affected_packages": [pkg.to_dict() for pkg in self.affected_packages],
259260
"references": [ref.to_dict() for ref in self.references],
260261
"date_published": self.date_published.isoformat() if self.date_published else None,
262+
"weaknesses": self.weaknesses,
261263
}
262264

263265
@classmethod
@@ -273,6 +275,7 @@ def from_dict(cls, advisory_data):
273275
"date_published": datetime.datetime.fromisoformat(date_published)
274276
if date_published
275277
else None,
278+
"weaknesses": advisory_data["weaknesses"],
276279
}
277280
return cls(**transformed)
278281

vulnerabilities/importers/nvd.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from vulnerabilities.importer import Importer
2121
from vulnerabilities.importer import Reference
2222
from vulnerabilities.importer import VulnerabilitySeverity
23+
from vulnerabilities.utils import get_cwe_id
2324
from vulnerabilities.utils import get_item
2425

2526

@@ -236,6 +237,25 @@ def is_related_to_hardware(self):
236237
"""
237238
return any(is_related_to_hardware(cpe) for cpe in self.cpes)
238239

240+
@property
241+
def weaknesses(self):
242+
"""
243+
Return a list of CWE IDs like: [119, 189]
244+
"""
245+
weaknesses = []
246+
for weaknesses_item in (
247+
get_item(self.cve_item, "cve", "problemtype", "problemtype_data") or []
248+
):
249+
weaknesses_description = weaknesses_item.get("description") or []
250+
for weaknesses_value in weaknesses_description:
251+
cwe_id = (
252+
weaknesses_value.get("value") if weaknesses_value.get("lang") == "en" else None
253+
)
254+
if cwe_id in ["NVD-CWE-Other", "NVD-CWE-noinfo"] or not cwe_id:
255+
continue # Skip Invalid CWE
256+
weaknesses.append(get_cwe_id(cwe_id))
257+
return weaknesses
258+
239259
def to_advisory(self):
240260
"""
241261
Return an AdvisoryData object from this CVE item
@@ -245,6 +265,7 @@ def to_advisory(self):
245265
summary=self.summary,
246266
references=self.references,
247267
date_published=dateparser.parse(self.cve_item.get("publishedDate")),
268+
weaknesses=self.weaknesses,
248269
)
249270

250271

vulnerabilities/improve_runner.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from vulnerabilities.models import VulnerabilityReference
2525
from vulnerabilities.models import VulnerabilityRelatedReference
2626
from vulnerabilities.models import VulnerabilitySeverity
27+
from vulnerabilities.models import Weakness
2728

2829
logger = logging.getLogger(__name__)
2930

@@ -133,6 +134,11 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
133134
fix=True,
134135
).update_or_create()
135136

137+
if inference.weaknesses and vulnerability:
138+
for cwe_id in inference.weaknesses:
139+
cwe_obj, created = Weakness.objects.get_or_create(cwe_id=cwe_id)
140+
cwe_obj.vulnerabilities.add(vulnerability)
141+
cwe_obj.save()
136142
advisory.date_improved = datetime.now(timezone.utc)
137143
advisory.save()
138144

vulnerabilities/improver.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Inference:
4242
affected_purls: Optional[List[PackageURL]] = dataclasses.field(default_factory=list)
4343
fixed_purl: PackageURL = None
4444
references: List[Reference] = dataclasses.field(default_factory=list)
45+
weaknesses: List[int] = dataclasses.field(default_factory=list)
4546

4647
def __post_init__(self):
4748
if self.confidence > MAX_CONFIDENCE or self.confidence < 0:
@@ -54,6 +55,7 @@ def __post_init__(self):
5455
or self.affected_purls
5556
or self.fixed_purl
5657
or self.references
58+
or self.weaknesses
5759
)
5860

5961
versionless_purls = []
@@ -82,6 +84,7 @@ def to_dict(self):
8284
"affected_purls": [affected_purl.to_dict() for affected_purl in self.affected_purls],
8385
"fixed_purl": self.fixed_purl.to_dict() if self.fixed_purl else None,
8486
"references": [ref.to_dict() for ref in self.references],
87+
"weaknesses": self.weaknesses,
8588
}
8689

8790
@classmethod
@@ -97,6 +100,7 @@ def from_advisory_data(cls, advisory_data, confidence, fixed_purl, affected_purl
97100
affected_purls=affected_purls or [],
98101
fixed_purl=fixed_purl,
99102
references=advisory_data.references,
103+
weaknesses=advisory_data.weaknesses,
100104
)
101105

102106

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 4.0.7 on 2023-01-01 20:25
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('vulnerabilities', '0036_alter_package_package_url_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='advisory',
15+
name='weaknesses',
16+
field=models.JSONField(blank=True, default=list, help_text='A list of CWE ids'),
17+
),
18+
migrations.CreateModel(
19+
name='Weakness',
20+
fields=[
21+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22+
('cwe_id', models.IntegerField(help_text='CWE id')),
23+
('vulnerabilities', models.ManyToManyField(related_name='weaknesses', to='vulnerabilities.vulnerability')),
24+
],
25+
),
26+
]

vulnerabilities/models.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import logging
1313
from contextlib import suppress
1414

15+
from cwe2.database import Database
1516
from django.contrib.auth import get_user_model
1617
from django.contrib.auth.models import UserManager
1718
from django.core import exceptions
@@ -249,6 +250,28 @@ def get_related_purls(self):
249250
return [p.package_url for p in self.packages.distinct().all()]
250251

251252

253+
class Weakness(models.Model):
254+
"""
255+
A Common Weakness Enumeration model
256+
"""
257+
258+
cwe_id = models.IntegerField(help_text="CWE id")
259+
vulnerabilities = models.ManyToManyField(Vulnerability, related_name="weaknesses")
260+
db = Database()
261+
262+
@property
263+
def name(self):
264+
"""Return the weakness's name."""
265+
weakness = self.db.get(self.cwe_id)
266+
return weakness.name
267+
268+
@property
269+
def description(self):
270+
"""Return the weakness's description."""
271+
weakness = self.db.get(self.cwe_id)
272+
return weakness.description
273+
274+
252275
class VulnerabilityReferenceQuerySet(BaseQuerySet):
253276
def for_cpe(self):
254277
"""
@@ -661,7 +684,6 @@ def update_or_create(self):
661684

662685

663686
class VulnerabilitySeverity(models.Model):
664-
665687
reference = models.ForeignKey(VulnerabilityReference, on_delete=models.CASCADE)
666688

667689
scoring_system_choices = tuple(
@@ -773,6 +795,7 @@ class Advisory(models.Model):
773795
date_published = models.DateTimeField(
774796
blank=True, null=True, help_text="UTC Date of publication of the advisory"
775797
)
798+
weaknesses = models.JSONField(blank=True, default=list, help_text="A list of CWE ids")
776799
date_collected = models.DateTimeField(help_text="UTC Date on which the advisory was collected")
777800
date_improved = models.DateTimeField(
778801
blank=True,
@@ -805,6 +828,7 @@ def to_advisory_data(self) -> AdvisoryData:
805828
affected_packages=[AffectedPackage.from_dict(pkg) for pkg in self.affected_packages],
806829
references=[Reference.from_dict(ref) for ref in self.references],
807830
date_published=self.date_published,
831+
weaknesses=self.weaknesses,
808832
)
809833

810834

vulnerabilities/templates/vulnerability_details.html

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@
116116
</table>
117117
</div>
118118

119-
120119
<div class="has-text-weight-bold tab-nested-div ml-1 mb-1 mt-6">
121120
Fixed by packages ({{ fixed_by_packages|length }})
122121
</div>
@@ -174,6 +173,32 @@
174173
{% endif %}
175174
</table>
176175
</div>
176+
177+
<div class="has-text-weight-bold tab-nested-div ml-1 mb-1 mt-6">
178+
Weaknesses ({{ weaknesses|length }})
179+
</div>
180+
<div class="tab-nested-div">
181+
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth gray-header-border">
182+
{% for weakness in weaknesses %}
183+
<tr>
184+
<td class="wrap-strings">CWE-{{ weakness.cwe_id }}</td>
185+
<td class="wrap-strings">
186+
<a href="https://cwe.mitre.org/data/definitions/{{ weakness.cwe_id }}.html" target="_blank"
187+
title="CWE-{{ weakness.cwe_id }} : description: {{weakness.description}}">
188+
{{ weakness.name }} <i class="fa fa-external-link fa_link_custom"></i>
189+
</a>
190+
</td>
191+
192+
</tr>
193+
{% empty %}
194+
<tr>
195+
<td colspan="3">
196+
There are no known CWE.
197+
</td>
198+
</tr>
199+
{% endfor %}
200+
</table>
201+
</div>
177202
</div>
178203

179204
<div class="tab-div content" data-content="references">

0 commit comments

Comments
 (0)