From 1ac27d2377a77b4c673f4b841d6afc49f10863e4 Mon Sep 17 00:00:00 2001 From: Dave Lawrence Date: Mon, 30 Mar 2026 18:51:20 +1030 Subject: [PATCH 1/2] Security fixes for variantopedia app #3817 --- variantopedia/grids.py | 1 + variantopedia/views.py | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/variantopedia/grids.py b/variantopedia/grids.py index c2bc70d98..dfe84bde7 100644 --- a/variantopedia/grids.py +++ b/variantopedia/grids.py @@ -352,5 +352,6 @@ def get_initial_queryset(self) -> QuerySet[VariantTag]: # Not going to use anything build specific so don't care about build genome_build = variant.any_genome_build qs = VariantTag.get_for_build(genome_build, variant_qs=variant.equivalent_variants) + qs = VariantTag.filter_for_user(self.user, queryset=qs) qs = qs.filter(tag=tag) return qs diff --git a/variantopedia/views.py b/variantopedia/views.py index b47e85840..8b3a0349d 100644 --- a/variantopedia/views.py +++ b/variantopedia/views.py @@ -11,6 +11,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.models import User +from django.core.exceptions import PermissionDenied from django.db import connection from django.forms import model_to_dict from django.shortcuts import get_object_or_404, render, redirect @@ -362,8 +363,10 @@ def database_statistics(request): def variant_tag_detail(request, variant_id, tag): """ Loaded via tags grid on variant page """ - variant = Variant.objects.get(pk=variant_id) + variant = get_object_or_404(Variant, pk=variant_id) tag = get_object_or_404(Tag, pk=tag) + if not VariantTag.filter_for_user(request.user).filter(variant=variant, tag=tag).exists(): + raise PermissionDenied context = { "variant": variant, "tag": tag, @@ -610,7 +613,7 @@ def export_classifications_allele(request, allele_id: int): """ CSV export of what is currently filtered into the classification grid """ - allele = Allele.objects.get(pk=allele_id) + allele = get_object_or_404(Allele, pk=allele_id) return ClassificationExportFormatterCSV( ClassificationFilter( user=request.user, @@ -657,7 +660,7 @@ def variant_details_annotation_version(request, variant_id, annotation_version_i extra_context: dict = None): """ Main Variant Details page """ variant = get_object_or_404(Variant, pk=variant_id) - annotation_version = AnnotationVersion.objects.get(pk=annotation_version_id) + annotation_version = get_object_or_404(AnnotationVersion, pk=annotation_version_id) genome_build = annotation_version.genome_build latest_annotation_version = AnnotationVersion.latest(genome_build) variant_annotation = None @@ -784,7 +787,7 @@ def nearby_variants_tab(request, variant_id, annotation_version_id): def nearby_variants(request, variant_id, annotation_version_id): variant = get_object_or_404(Variant, pk=variant_id) - annotation_version = AnnotationVersion.objects.get(pk=annotation_version_id) + annotation_version = get_object_or_404(AnnotationVersion, pk=annotation_version_id) variant_annotation_version = annotation_version.variant_annotation_version variant_annotation = variant.variantannotation_set.filter(version=variant_annotation_version).first() From 6cbf4e29c6c7a5c1efaf16cfa80f544965a11449 Mon Sep 17 00:00:00 2001 From: Dave Lawrence Date: Mon, 30 Mar 2026 18:51:23 +1030 Subject: [PATCH 2/2] Use format_html in health check as_html methods #3817 --- library/health_check.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/library/health_check.py b/library/health_check.py index 28989b23c..62a0e87b8 100644 --- a/library/health_check.py +++ b/library/health_check.py @@ -6,6 +6,7 @@ import django.dispatch from django.db.models import Model, Q +from django.utils.html import format_html from django.utils.timezone import localtime from library.log_utils import NotificationBuilder @@ -84,14 +85,15 @@ def as_markdown(self): return result def as_html(self): - amount_str = self.amount if self.amount: - amount_str = f"{amount_str}" - result = f"{amount_str} {self.name}" + amount_html = format_html("{}", self.amount) + else: + amount_html = format_html("{}", self.amount) + result = format_html("{} {}", amount_html, self.name) if self.sub_type: - result = f"{result} {self.sub_type}" + result = format_html("{} {}", result, self.sub_type) if self.extra: - result = f"{result} {self.extra}" + result = format_html("{} {}", result, self.extra) return result @classmethod @@ -200,12 +202,13 @@ def as_markdown(self): return result def as_html(self): - amount_str = self.amount if self.amount: - amount_str = f"{amount_str:,}" - result = f"{amount_str} {self.name}" + amount_html = format_html("{:,}", self.amount) + else: + amount_html = format_html("{}", self.amount) + result = format_html("{} {}", amount_html, self.name) if self.extra: - result = f"{result} - {self.extra}" + result = format_html("{} - {}", result, self.extra) return result @classmethod @@ -226,7 +229,7 @@ def as_markdown(self): return f"{emoji} {self.name} ({self.used} used, {self.available} available)" def as_html(self): - return f"{self.name} ({self.used} used, {self.available} available)" + return format_html("{} ({} used, {} available)", self.name, self.used, self.available) @classmethod def sort_order(cls): @@ -269,8 +272,8 @@ def as_markdown(self): def as_html(self): if not self.last_performed_tz: - return f"Never Run {self.name}" - return f"{self.age_in_days} days old {self.name}" + return format_html("Never Run {}", self.name) + return format_html("{} days old {}", self.age_in_days, self.name) _MULTIPLIER_TO_FACE = { 0: ":simple_smile:",