Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…boutcode-org#708

Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
  • Loading branch information
TG1999 committed Apr 22, 2022
1 parent 47f6ae6 commit 8835388
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 33 deletions.
29 changes: 24 additions & 5 deletions vulnerabilities/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from rest_framework.decorators import action
from rest_framework.response import Response

from vulnerabilities.models import Alias
from vulnerabilities.models import Package
from vulnerabilities.models import Vulnerability
from vulnerabilities.models import VulnerabilityReference
Expand All @@ -47,7 +48,7 @@ class VulnerabilityReferenceSerializer(serializers.ModelSerializer):

class Meta:
model = VulnerabilityReference
fields = ["reference_id", "url", "scores"]
fields = ["url", "reference_id", "scores"]


class MinimalPackageSerializer(serializers.HyperlinkedModelSerializer):
Expand All @@ -74,18 +75,36 @@ class Meta:
fields = ["url", "vulnerability_id", "references", "summary"]


class AliasSerializer(serializers.HyperlinkedModelSerializer):
"""
Used for nesting inside package focused APIs.
"""

class Meta:
model = Alias
fields = ["alias"]


class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer):

resolved_packages = MinimalPackageSerializer(many=True, source="resolved_to", read_only=True)
unresolved_packages = MinimalPackageSerializer(
many=True, source="vulnerable_to", read_only=True
)
affected_packages = MinimalPackageSerializer(many=True, source="vulnerable_to", read_only=True)

references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
alias = AliasSerializer(many=True)

class Meta:
model = Vulnerability
fields = "__all__"
fields = [
"url",
"vulcoid",
"summary",
"alias",
"vulnerability_id",
"resolved_packages",
"affected_packages",
"references",
]


class PackageSerializer(serializers.HyperlinkedModelSerializer):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 4.0.3 on 2022-04-15 19:16

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('vulnerabilities', '0009_alter_advisory_summary_and_more'),
]

operations = [
migrations.AddField(
model_name='vulnerability',
name='packages',
field=models.ManyToManyField(through='vulnerabilities.PackageRelatedVulnerability', to='vulnerabilities.package'),
),
migrations.AlterField(
model_name='package',
name='vulnerabilities',
field=models.ManyToManyField(through='vulnerabilities.PackageRelatedVulnerability', to='vulnerabilities.vulnerability'),
),
migrations.AlterField(
model_name='packagerelatedvulnerability',
name='package',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='vulnerabilities.package'),
),
]
39 changes: 30 additions & 9 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from django.core.validators import MaxValueValidator
from django.core.validators import MinValueValidator
from django.db import models
from django.utils.http import int_to_base36
from packageurl import PackageURL
from packageurl.contrib.django.models import PackageURLMixin

Expand Down Expand Up @@ -60,24 +61,37 @@ class Vulnerability(models.Model):
blank=True,
)

packages = models.ManyToManyField(
to="Package",
through="PackageRelatedVulnerability",
)

@property
def vulcoid(self):
return f"VULCOID-{self.vulnerability_id}"
return f"VULCOID-{int_to_base36(self.id).upper()}"

@property
def vulnerable_to(self):
"""
Return packages that are vulnerable to this vulnerability.
"""
return self.packages.filter(vulnerabilities__packagerelatedvulnerability__fix=False)
return self.packages.filter(packagerelatedvulnerability__fix=False)

@property
def resolved_to(self):
"""
Returns packages that first received patch against this vulnerability
in their particular version history.
"""
return self.packages.filter(vulnerabilities__packagerelatedvulnerability__fix=True)
return self.packages.filter(packagerelatedvulnerability__fix=True)

@property
def alias(self):
"""
Returns packages that first received patch against this vulnerability
in their particular version history.
"""
return self.aliases.all()

def __str__(self):
return self.vulcoid
Expand Down Expand Up @@ -127,10 +141,7 @@ class Package(PackageURLMixin):
"""

vulnerabilities = models.ManyToManyField(
to="Vulnerability",
through="PackageRelatedVulnerability",
through_fields=("package", "vulnerability"),
related_name="packages",
to="Vulnerability", through="PackageRelatedVulnerability"
)

# Remove the `qualifers` and `set_package_url` overrides after
Expand Down Expand Up @@ -195,8 +206,14 @@ def __str__(self):
class PackageRelatedVulnerability(models.Model):

# TODO: Fix related_name
package = models.ForeignKey(Package, on_delete=models.CASCADE, related_name="package")
vulnerability = models.ForeignKey(Vulnerability, on_delete=models.CASCADE)
package = models.ForeignKey(
Package,
on_delete=models.CASCADE,
)
vulnerability = models.ForeignKey(
Vulnerability,
on_delete=models.CASCADE,
)
created_by = models.CharField(
max_length=100,
blank=True,
Expand All @@ -223,6 +240,10 @@ class Meta:
verbose_name_plural = "PackageRelatedVulnerabilities"
indexes = [models.Index(fields=["fix"])]

@property
def purl(self):
return self.package.package_url

def update_or_create(self):
"""
Update if supplied record has more confidence than existing record
Expand Down
4 changes: 2 additions & 2 deletions vulnerabilities/templates/package_update.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ <h1 class="title">
<div class="column is-full">
<div class="card has-background-danger-light">
<header class="card-header mb-3">
<p class="card-header-title">Vulnerable To</p>
<p class="card-header-title">Affected By</p>
</header>
<div class="tags mx-3">
{% for vulnerability in impacted_vuln %}
Expand All @@ -49,7 +49,7 @@ <h1 class="title">
<div class="column is-full">
<div class="card has-background-danger-light">
<header class="card-header mb-3">
<p class="card-header-title">Safe To</p>
<p class="card-header-title">Fixing</p>
</header>
<div class="tags mx-3">
{% for vulnerability in resolved_vuln %}
Expand Down
62 changes: 48 additions & 14 deletions vulnerabilities/templates/vulnerability.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ <h3>Summary:</h3>
</p>
{% endif %}
</div>
<div class="content is-medium ">
{% if aliases %}
<h3>Aliases:</h3>
{% for alias in aliases %}
<p>
{{alias}}
</p>
{% endfor %}
{% endif %}
</div>
<div class="content is-medium">

{% if object_list %}
Expand Down Expand Up @@ -77,27 +87,51 @@ <h3>Severity</h3>
{% endif %}

{% if vulnerability.vulnerable_to.all %}
<h3> Vulnerable Packages </h3>
<div class="tags is-medium">
{% for package in vulnerability.vulnerable_to.all %}
<span class="tag is-danger is-medium">
<a href ="{% url 'package_view' package.pk %}" class="has-text-white"> {{package.package_url}}</a>
</span>
{% endfor %}
</div>
<h3> Vulnerable Packages </h3>
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<tr>
<th> Packages </th>
</tr>
{% for package in vulnerability.vulnerable_to.all %}
<tr>
{% if package.package_url %}
<td>
<a href ="{% url 'package_view' package.pk %}"> {{package.package_url}} </a>
</td>

{% else %}
<td>-</td>

{% endif %}
</tr>

{% endfor %}
</table>
{% else %}
<h3> No available vulnerable packages </h3>
<h3> No available Vulnerable packages </h3>
{% endif %}

{% if vulnerability.resolved_to.all %}
<h3> Patched Packages </h3>
<div class="tags is-medium">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<tr>
<th> Packages </th>
</tr>
{% for package in vulnerability.resolved_to.all %}
<span class="tag is-success is-medium">
<a href ="{% url 'package_view' package.pk %}" class="has-text-white"> {{package.package_url}} </a>
</span>
<tr>
{% if package.package_url %}
<td>
<a href ="{% url 'package_view' package.pk %}"> {{package.package_url}} </a>
</td>

{% else %}
<td>-</td>

{% endif %}
</tr>

{% endfor %}
</div>
</table>
{% else %}
<h3> No available patched packages </h3>
{% endif %}
Expand Down
10 changes: 7 additions & 3 deletions vulnerabilities/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,18 @@ def request_to_queryset(request):
.annotate(
vulnerability_count=Count(
"vulnerabilities",
filter=Q(vulnerabilities__packagerelatedvulnerability__fix=False),
filter=Q(packagerelatedvulnerability__fix=False),
),
# TODO: consider renaming to fixed in the future
patched_vulnerability_count=Count(
"vulnerabilities",
filter=Q(vulnerabilities__packagerelatedvulnerability__fix=True),
filter=Q(packagerelatedvulnerability__fix=True),
),
)
.prefetch_related()
)
# FIXME: This filter is wrong and ignoring most of the fields needed for a
# proper package lookup: type/namespace/name@version?qualifiers and so on


class VulnerabilitySearchView(View):
Expand Down Expand Up @@ -154,7 +156,9 @@ class VulnerabilityDetails(ListView):

def get_context_data(self, **kwargs):
context = super(VulnerabilityDetails, self).get_context_data(**kwargs)
context["vulnerability"] = models.Vulnerability.objects.get(id=self.kwargs["pk"])
vulnerability = models.Vulnerability.objects.get(id=self.kwargs["pk"])
context["vulnerability"] = vulnerability
context["aliases"] = vulnerability.aliases.alias()
return context

def get_queryset(self):
Expand Down

0 comments on commit 8835388

Please sign in to comment.