Skip to content

Commit

Permalink
feat : Option to filter Vunerable and Non Vulnerable Packages
Browse files Browse the repository at this point in the history
Signed-off-by: Rishi Garg <[email protected]>
  • Loading branch information
Rishi-garg03 committed Jan 24, 2025
1 parent fabe035 commit e664411
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 4 deletions.
26 changes: 24 additions & 2 deletions vulnerabilities/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,36 @@


class PackageSearchForm(forms.Form):

search = forms.CharField(
required=True,
widget=forms.TextInput(
attrs={"placeholder": "Package name, purl or purl fragment"},
attrs={
"placeholder": "Package name, purl or purl fragment",
},
),
)
type = forms.CharField(required=False, max_length=50)
vulnerable_only = forms.ChoiceField(
required=False,
choices=(
("", "All Packages"),
("true", "Vulnerable Only"),
("false", "Non-Vulnerable Only"),
),
)

def clean_search(self):
"""Sanitize the search input which provide extra layer of protection from XSS attacks"""
search = self.cleaned_data["search"].strip()
if not search:
raise forms.ValidationError("Search field cannot be empty")
return search

def clean_type(self):
"""Sanitize the type input which provide extra layer of protection from XSS attacks"""
pkg_type = self.cleaned_data["type"].strip()
return pkg_type


class VulnerabilitySearchForm(forms.Form):

Expand Down
32 changes: 31 additions & 1 deletion vulnerabilities/templates/packages.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
<div>
{{ page_obj.paginator.count|intcomma }} results
</div>
<select name="vulnerable_only" class="select" id="vulnerable-select">
<option value="">All Packages</option>
<option value="true" {% if request.GET.vulnerable_only == 'true' %}selected{% endif %}>Vulnerable Only</option>
<option value="false" {% if request.GET.vulnerable_only == 'false' %}selected{% endif %}>Non-Vulnerable Only</option>
</select>

{% if is_paginated %}
{% include 'includes/pagination.html' with page_obj=page_obj %}
{% endif %}
Expand Down Expand Up @@ -81,4 +87,28 @@

</section>
{% endif %}
{% endblock %}
<script>
// This script is used to update the URL when the user selects a value from the vulnerable_only dropdown menu.
// It also sanitize the URL to prevent XSS attacks.
document.getElementById('vulnerable-select').addEventListener('change', function() {
let searchParams = new URLSearchParams(window.location.search);
let selectedValue = this.value.replace(/[^a-zA-Z0-9]/g, '');
let searchTerm = searchParams.get('search');
if (searchTerm) {
searchTerm = encodeURIComponent(searchTerm);
}
if (selectedValue) {
searchParams.set('vulnerable_only', selectedValue);
} else {
searchParams.delete('vulnerable_only');
}
if (searchTerm) {
searchParams.set('search', searchTerm);
}
let newUrl = window.location.pathname + '?' + searchParams.toString();
if (newUrl.match(/^[^<>'"]*$/)) {
window.location.href = newUrl;
}
});
</script>
{% endblock %}
20 changes: 20 additions & 0 deletions vulnerabilities/tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,26 @@ def test_package_view_with_valid_purl_without_version(self):
"pkg:nginx/[email protected]",
]

def test_package_search_vulnerable_only_filter(self):
vulnerable_pkg = Package.objects.create(type="npm", name="vulnerable-pkg", version="1.0.0")
non_vulnerable_pkg = Package.objects.create(
type="npm", name="non-vulnerable-pkg", version="2.0.0"
)
vuln = Vulnerability.objects.create(
vulnerability_id="VCID-123", summary="test vulnerability"
)
AffectedByPackageRelatedVulnerability.objects.create(
package=vulnerable_pkg, vulnerability=vuln
)
self.assertTrue(
AffectedByPackageRelatedVulnerability.objects.filter(package=vulnerable_pkg).exists()
)
self.assertFalse(
AffectedByPackageRelatedVulnerability.objects.filter(
package=non_vulnerable_pkg
).exists()
)

def test_package_view_with_valid_purl_and_incomplete_version(self):
qs = PackageSearch().get_queryset(query="pkg:nginx/nginx@1")
pkgs = list(qs)
Expand Down
9 changes: 8 additions & 1 deletion vulnerabilities/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,19 @@ def get_queryset(self, query=None):
on exact purl, partial purl or just name and namespace.
"""
query = query or self.request.GET.get("search") or ""
return (
queryset = (
self.model.objects.search(query)
.with_vulnerability_counts()
.prefetch_related()
.order_by("package_url")
)
if hasattr(self, "request"):
vulnerable_only = self.request.GET.get("vulnerable_only", "").lower()
if vulnerable_only in ["true", "false"]:
queryset = queryset.with_is_vulnerable()
queryset = queryset.filter(is_vulnerable=vulnerable_only == "true")

return queryset


class VulnerabilitySearch(ListView):
Expand Down

0 comments on commit e664411

Please sign in to comment.