Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UI #700

Merged
merged 1 commit into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vulnerabilities/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class VulnerabilityAdmin(admin.ModelAdmin):

@admin.register(VulnerabilityReference)
class VulnerabilityReferenceAdmin(admin.ModelAdmin):
search_fields = ["vulnerability__vulnerability_id", "reference_id", "url"]
search_fields = ["vulnerabilityrelatedreference__vulnerability__id", "reference_id", "url"]


@admin.register(Package)
Expand Down
52 changes: 41 additions & 11 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 @@ -44,10 +45,11 @@ class Meta:

class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
scores = VulnerabilitySeveritySerializer(many=True, source="vulnerabilityseverity_set")
reference_url = serializers.CharField(source="url")

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


class MinimalPackageSerializer(serializers.HyperlinkedModelSerializer):
Expand All @@ -71,36 +73,64 @@ class MinimalVulnerabilitySerializer(serializers.HyperlinkedModelSerializer):

class Meta:
model = Vulnerability
fields = ["url", "vulnerability_id", "references", "summary"]
fields = ["url", "vulnerability_id", "summary", "references"]


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
)
fixed_packages = MinimalPackageSerializer(many=True, source="resolved_to", read_only=True)
TG1999 marked this conversation as resolved.
Show resolved Hide resolved
affected_packages = MinimalPackageSerializer(many=True, source="vulnerable_to", read_only=True)

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

class Meta:
model = Vulnerability
fields = "__all__"
fields = [
"url",
"vulnerability_id",
"summary",
"aliases",
"fixed_packages",
"affected_packages",
"references",
]


class PackageSerializer(serializers.HyperlinkedModelSerializer):

unresolved_vulnerabilities = MinimalVulnerabilitySerializer(
purl = serializers.CharField(source="package_url")
affected_by_vulnerabilities = MinimalVulnerabilitySerializer(
many=True, source="vulnerable_to", read_only=True
)
resolved_vulnerabilities = MinimalVulnerabilitySerializer(
fixing_vulnerabilities = MinimalVulnerabilitySerializer(
many=True, source="resolved_to", read_only=True
)
purl = serializers.CharField(source="package_url")

class Meta:
model = Package
exclude = ["vulnerabilities"]
fields = [
"url",
"purl",
"type",
"namespace",
"name",
"version",
"qualifiers",
"subpath",
"affected_by_vulnerabilities",
"fixing_vulnerabilities",
]


class PackageFilterSet(filters.FilterSet):
Expand Down
12 changes: 3 additions & 9 deletions vulnerabilities/importers/alpine_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class AlpineImporter(Importer):
license_url = "https://secdb.alpinelinux.org/license.txt"

def advisory_data(self) -> Iterable[AdvisoryData]:
advisories = []
page_response_content = fetch_response(BASE_URL).content
advisory_directory_links = fetch_advisory_directory_links(page_response_content)
advisory_links = []
Expand All @@ -68,8 +67,7 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
if not record["packages"]:
LOGGER.error(f'"packages" not found in {link!r}')
continue
advisories.extend(process_record(record))
return advisories
yield from process_record(record)


def fetch_response(url):
Expand Down Expand Up @@ -127,7 +125,7 @@ def check_for_attributes(record) -> bool:
return True


def process_record(record: dict) -> List[AdvisoryData]:
def process_record(record: dict) -> Iterable[AdvisoryData]:
"""
Return a list of AdvisoryData objects by processing data
present in that `record`
Expand All @@ -136,22 +134,18 @@ def process_record(record: dict) -> List[AdvisoryData]:
LOGGER.error(f'"packages" not found in this record {record!r}')
return []

advisories: List[AdvisoryData] = []

for package in record["packages"]:
if not package["pkg"]:
LOGGER.error(f'"pkg" not found in this package {package!r}')
continue
if not check_for_attributes(record):
continue
loaded_advisories = load_advisories(
yield from load_advisories(
package["pkg"],
record["distroversion"],
record["reponame"],
record["archs"],
)
advisories.extend(loaded_advisories)
return advisories


def load_advisories(
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-26 08:42

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


class Migration(migrations.Migration):

dependencies = [
('vulnerabilities', '0010_vulnerabilityrelatedreference_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'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2022-05-03 09:41

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('vulnerabilities', '0011_vulnerability_packages_alter_package_vulnerabilities_and_more'),
]

operations = [
migrations.AlterField(
model_name='vulnerability',
name='vulnerability_id',
field=models.CharField(blank=True, help_text='Unique identifier for a vulnerability in the external representation. It is prefixed with VULCOID-', max_length=20, unique=True),
),
]
22 changes: 22 additions & 0 deletions vulnerabilities/migrations/0013_auto_20220503_0941.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.0.4 on 2022-05-03 09:41

from django.db import migrations

from django.utils.http import int_to_base36

class Migration(migrations.Migration):

dependencies = [
('vulnerabilities', '0012_alter_vulnerability_vulnerability_id'),
]

def save_vulnerability_id(apps, schema_editor):
Vulnerabilities = apps.get_model("vulnerabilities", "Vulnerability")
for vulnerability in Vulnerabilities.objects.all():
if not vulnerability.vulnerability_id:
vulnerability.vulnerability_id = f"VULCOID-{int_to_base36(vulnerability.id).upper()}"
vulnerability.save()

operations = [
migrations.RunPython(save_vulnerability_id)
]
52 changes: 35 additions & 17 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 All @@ -47,12 +48,12 @@ class Vulnerability(models.Model):
stored as ``Alias``.
"""

vulnerability_id = models.UUIDField(
default=uuid.uuid4,
editable=False,
vulnerability_id = models.CharField(
unique=True,
help_text="Unique identifier for a vulnerability in this database, assigned automatically. "
"In the external representation it is prefixed with VULCOID-",
blank=True,
max_length=20,
help_text="Unique identifier for a vulnerability in the external representation. "
"It is prefixed with VULCOID-",
)

summary = models.TextField(
Expand All @@ -63,28 +64,42 @@ class Vulnerability(models.Model):
references = models.ManyToManyField(
to="VulnerabilityReference", through="VulnerabilityRelatedReference"
)
packages = models.ManyToManyField(
to="Package",
through="PackageRelatedVulnerability",
)

@property
def vulcoid(self):
return f"VULCOID-{self.vulnerability_id}"
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not self.vulnerability_id:
self.vulnerability_id = f"VULCOID-{int_to_base36(self.id).upper()}"
super().save(update_fields=["vulnerability_id"])

@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
return self.vulnerability_id

class Meta:
verbose_name_plural = "Vulnerabilities"
Expand Down Expand Up @@ -150,10 +165,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 @@ -218,8 +230,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 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
4 changes: 2 additions & 2 deletions vulnerabilities/templates/packages.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ <h1 class="title">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<tr>
<th>Package URL</th>
<th>Vulnerabilities</th>
<th>Patched Vulnerabilities</th>
<th>Affected By Vulnerabilities</th>
<th>Fixing Vulnerabilities</th>
</tr>
{% for package in packages %}
<tr>
Expand Down
6 changes: 3 additions & 3 deletions vulnerabilities/templates/vulnerabilities.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ <h1 class="title">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<tr>
<th>Vulnerability ID</th>
<th>Vulnerable packages</th>
<th>Patched packages</th>
<th>Affected packages</th>
<th>Fixed packages</th>
</tr>
{% for vulnerability in vulnerabilities %}
<tr>
<td><a href="{% url 'vulnerability_view' vulnerability.pk %}">{{vulnerability.vulnerability_id}}</a></td>
<td><a href="{% url 'vulnerability_view' vulnerability.pk %}">{{vulnerability.vulcoid}}</a></td>
<td>{{vulnerability.vulnerable_package_count}}</td>
<td>{{vulnerability.patched_package_count}}</td>
</tr>
Expand Down
Loading