security: show the fixed versions for each vuln
the data quality is bad, but let's see
This commit is contained in:
parent
3f17254ab1
commit
4ad9115d46
@ -14,7 +14,7 @@ from typing import NamedTuple, Any
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Sequence
|
||||
from pydantic import BaseModel
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from packageurl import PackageURL
|
||||
|
||||
from .appconfig import REPOSITORIES
|
||||
@ -200,6 +200,7 @@ class Vulnerability:
|
||||
url: str
|
||||
severity: Severity
|
||||
ignored: bool = False
|
||||
unaffected_versions: list[str] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def sort_key(self) -> tuple[bool, int, str, str]:
|
||||
|
||||
@ -29,10 +29,19 @@ def parse_cdx(data: bytes) -> dict[str, list[Vulnerability]]:
|
||||
for ratings in vuln["ratings"]:
|
||||
severity = Severity(ratings["severity"])
|
||||
break
|
||||
|
||||
unaffected_versions = []
|
||||
for affects in vuln["affects"]:
|
||||
versions = affects.get("versions", [])
|
||||
for version in versions:
|
||||
if version.get("status") == "unaffected" and "version" in version:
|
||||
unaffected_versions.append(version["version"])
|
||||
|
||||
return Vulnerability(
|
||||
id=vuln["id"],
|
||||
url=vuln["source"]["url"],
|
||||
severity=severity)
|
||||
severity=severity,
|
||||
unaffected_versions=unaffected_versions)
|
||||
|
||||
vuln_mapping: dict[str, list[Vulnerability]] = {}
|
||||
for vuln in cdx["vulnerabilities"]:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Base Package: {{ sources[0].name if sources else '' }}{% endblock %}
|
||||
{% block inner_content %}
|
||||
{% from 'macros.html' import vulnerability_list %}
|
||||
|
||||
{% for s in sources %}
|
||||
<div class="card mb-3">
|
||||
@ -85,11 +86,7 @@
|
||||
<dt class="col-sm-3 text-sm-end">Vulnerabilities:</dt>
|
||||
<dd class="col-sm-9">
|
||||
{% if s.all_vulnerabilities %}
|
||||
<ul class="list-unstyled">
|
||||
{% for vuln in s.all_vulnerabilities %}
|
||||
<li {% if vuln.ignored %}style="text-decoration: line-through"{% endif %}><a href="{{ vuln.url }}">{{ vuln.id }}</a> <span class="opacity-75 text-{{vulnerability_color(vuln)}}">({{ vuln.severity }})</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{{ vulnerability_list(s) }}
|
||||
{% elif not s.can_have_vulnerabilities %}
|
||||
<span class="text-muted">Not enough metadata for vulnerability reporting</span>
|
||||
{% else %}
|
||||
|
||||
32
app/templates/macros.html
Normal file
32
app/templates/macros.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% macro vulnerability_color(vuln) %}
|
||||
{%- if vuln.severity|string == "critical" -%}
|
||||
danger
|
||||
{%- elif vuln.severity|string == "high" -%}
|
||||
warning
|
||||
{%- else -%}
|
||||
secondary
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro vulnerability_tooltip(s) %}
|
||||
<span class="mytooltip-onclick">
|
||||
<span role="button" class="text-{{vulnerability_color(s.worst_active_vulnerability)}}">⚠</span>
|
||||
<template class="mytooltip-content">
|
||||
{{ vulnerability_list(s) }}
|
||||
</template>
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro vulnerability_list(s) %}
|
||||
<ul class="list-unstyled">
|
||||
{% for vuln in s.all_vulnerabilities %}
|
||||
<li {% if vuln.ignored %}style="text-decoration: line-through"{% endif %}>
|
||||
<a href="{{ vuln.url }}">{{ vuln.id }}</a>
|
||||
<span class="opacity-75 text-{{vulnerability_color(vuln)}}">({{ vuln.severity }})</span>
|
||||
{% if not vuln.ignored and vuln.unaffected_versions %}
|
||||
<br><span>(fixed in {{ vuln.unaffected_versions|join(', ') }})</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endmacro %}
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Outdated Packages{% endblock %}
|
||||
{% block inner_content %}
|
||||
{% from 'macros.html' import vulnerability_tooltip %}
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
@ -64,20 +65,11 @@
|
||||
<td class="text-version">{{ myver }}{% if gitver %} <span class="text-muted small align-text-bottom ps-1">({{ gitver }} in git)</span>{% endif %}</td>
|
||||
<td>→</td>
|
||||
<td class="text-version"><a href="{{ url }}">{{ ver }}</a></td>
|
||||
{% if s.active_vulnerabilities %}
|
||||
<td class="mytooltip-onclick">
|
||||
<span role="button" class="text-{{vulnerability_color(s.worst_active_vulnerability)}}">⚠</span>
|
||||
<template class="mytooltip-content">
|
||||
<ul class="list-unstyled">
|
||||
{% for vuln in s.all_vulnerabilities %}
|
||||
<li {% if vuln.ignored %}style="text-decoration: line-through"{% endif %}><a href="{{ vuln.url }}">{{ vuln.id }}</a> <span class="opacity-75 text-{{vulnerability_color(vuln)}}">({{ vuln.severity }})</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</template>
|
||||
<td>
|
||||
{% if s.active_vulnerabilities %}
|
||||
{{ vulnerability_tooltip(s) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@ -87,16 +79,7 @@
|
||||
{% for s in missing %}
|
||||
<a href="{{ url_for('base', base_name=s.name) }}">{{ s.realname }}</a>
|
||||
{%- if s.active_vulnerabilities %}
|
||||
<span class="mytooltip-onclick">
|
||||
<span role="button" class="text-{{vulnerability_color(s.worst_active_vulnerability)}}">⚠</span>
|
||||
<template class="mytooltip-content">
|
||||
<ul class="list-unstyled">
|
||||
{% for vuln in s.all_vulnerabilities %}
|
||||
<li {% if vuln.ignored %}style="text-decoration: line-through"{% endif %}><a href="{{ vuln.url }}">{{ vuln.id }}</a> <span class="opacity-75 text-{{vulnerability_color(vuln)}}">({{ vuln.severity }})</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</template>
|
||||
</span>
|
||||
{{ vulnerability_tooltip(s) }}
|
||||
{% endif -%}
|
||||
{{ ", " if not loop.last else '' }}
|
||||
{% endfor %}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Package: {{ packages[0][1].name if packages else '' }}{% endblock %}
|
||||
{% block inner_content %}
|
||||
{% from 'macros.html' import vulnerability_list %}
|
||||
|
||||
{% for s, p in packages %}
|
||||
<div class="card mb-3">
|
||||
@ -79,11 +80,7 @@
|
||||
{% if s.all_vulnerabilities %}
|
||||
<dt class="col-sm-3 text-sm-end">Vulnerabilities:</dt>
|
||||
<dd class="col-sm-9">
|
||||
<ul class="list-unstyled">
|
||||
{% for vuln in s.all_vulnerabilities %}
|
||||
<li {% if vuln.ignored %}style="text-decoration: line-through"{% endif %}><a href="{{ vuln.url }}">{{ vuln.id }}</a> <span class="opacity-75 text-{{vulnerability_color(vuln)}}">({{ vuln.severity }})</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{{ vulnerability_list(s) }}
|
||||
</dd>
|
||||
{% endif%}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Security {% endblock %}
|
||||
{% block inner_content %}
|
||||
{% from 'macros.html' import vulnerability_tooltip %}
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
@ -35,15 +36,8 @@
|
||||
<td><a href="{{ url_for('base', base_name=s.name) }}">{{ s.name }}</a></td>
|
||||
<td class="text-version">{{ s.version }}{% if s.version != s.git_version %} <span class="text-muted small align-text-bottom ps-1">({{ s.git_version }} in git)</span>{% endif %}</td>
|
||||
<td class="text-version">{{ s.upstream_version if s.is_outdated_in_git else '' }}</td>
|
||||
<td class="mytooltip-onclick">
|
||||
<span role="button" class="text-{{vulnerability_color(s.worst_active_vulnerability)}}">⚠</span>
|
||||
<template class="mytooltip-content">
|
||||
<ul class="list-unstyled">
|
||||
{% for vuln in s.all_vulnerabilities %}
|
||||
<li {% if vuln.ignored %}style="text-decoration: line-through"{% endif %}><a href="{{ vuln.url }}">{{ vuln.id }}</a> <span class="opacity-75 text-{{vulnerability_color(vuln)}}">({{ vuln.severity }})</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</template>
|
||||
<td>
|
||||
{{ vulnerability_tooltip(s) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
12
app/web.py
12
app/web.py
@ -21,7 +21,7 @@ from fastapi_etag import Etag
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi_etag import add_exception_handler as add_etag_exception_handler
|
||||
|
||||
from .appstate import state, get_repositories, Package, Source, DepType, SrcInfoPackage, get_base_group_name, Vulnerability, Severity, PackageKey, find_packages
|
||||
from .appstate import state, get_repositories, Package, Source, DepType, SrcInfoPackage, get_base_group_name, Vulnerability, PackageKey, find_packages
|
||||
from .utils import extract_upstream_version, version_is_newer_than
|
||||
|
||||
router = APIRouter(default_response_class=HTMLResponse)
|
||||
@ -92,16 +92,6 @@ def update_timestamp(request: Request) -> float:
|
||||
return state.last_update
|
||||
|
||||
|
||||
@context_function("vulnerability_color")
|
||||
def vulnerability_color(request: Request, vuln: Vulnerability) -> str:
|
||||
if vuln.severity == Severity.CRITICAL:
|
||||
return "danger"
|
||||
elif vuln.severity == Severity.HIGH:
|
||||
return "warning"
|
||||
else:
|
||||
return "secondary"
|
||||
|
||||
|
||||
@context_function("package_url")
|
||||
def package_url(request: Request, package: Package, name: str | None = None) -> str:
|
||||
res: str = ""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user