From 56cd182e24d796b520c6740f0076d8b08379e3f4 Mon Sep 17 00:00:00 2001 From: Dexter2099 Date: Fri, 26 Jun 2026 09:14:33 +1000 Subject: [PATCH] fix: return 404 for missing versioning parents --- api/features/versioning/permissions.py | 9 ++-- .../test_unit_versioning_permissions.py | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 api/tests/unit/features/versioning/test_unit_versioning_permissions.py diff --git a/api/features/versioning/permissions.py b/api/features/versioning/permissions.py index e7072cf1e617..0accc4d4d0c0 100644 --- a/api/features/versioning/permissions.py +++ b/api/features/versioning/permissions.py @@ -5,6 +5,7 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from django.shortcuts import get_object_or_404 from rest_framework.permissions import BasePermission from rest_framework.request import Request from rest_framework.viewsets import GenericViewSet @@ -21,14 +22,16 @@ def has_permission(self, request: Request, view: GenericViewSet) -> bool: # typ return True environment_pk = view.kwargs["environment_pk"] - environment = Environment.objects.get(id=environment_pk) + environment = get_object_or_404(Environment, id=environment_pk) tag_ids = None required_permission = UPDATE_FEATURE_STATE if required_permission in TAG_SUPPORTED_ENVIRONMENT_PERMISSIONS: feature_id = view.kwargs["feature_pk"] - feature = Feature.objects.get(id=feature_id, project=environment.project) + feature = get_object_or_404( + Feature, id=feature_id, project=environment.project + ) tag_ids = list(feature.tags.values_list("id", flat=True)) return request.user.has_environment_permission( # type: ignore[union-attr,no-any-return] @@ -70,7 +73,7 @@ def has_object_permission(self, request, view, obj): # type: ignore[no-untyped- class EnvironmentFeatureVersionFeatureStatePermissions(BasePermission): def has_permission(self, request: Request, view: GenericViewSet) -> bool: # type: ignore[override,type-arg] environment_pk = view.kwargs["environment_pk"] - environment = Environment.objects.get(id=environment_pk) + environment = get_object_or_404(Environment, id=environment_pk) if view.action == "list": return request.user.has_environment_permission( # type: ignore[union-attr,no-any-return] diff --git a/api/tests/unit/features/versioning/test_unit_versioning_permissions.py b/api/tests/unit/features/versioning/test_unit_versioning_permissions.py new file mode 100644 index 000000000000..46673ec67aca --- /dev/null +++ b/api/tests/unit/features/versioning/test_unit_versioning_permissions.py @@ -0,0 +1,54 @@ +import pytest +from django.http import Http404 +from pytest_mock import MockerFixture +from rest_framework.request import Request +from rest_framework.viewsets import GenericViewSet + +from environments.models import Environment +from features.models import Feature +from features.versioning.permissions import ( + EnvironmentFeatureVersionFeatureStatePermissions, + EnvironmentFeatureVersionPermissions, +) +from users.models import FFAdminUser + +pytestmark = pytest.mark.django_db + + +def test_environment_feature_version_feature_state_permissions__missing_environment__raises_404( + admin_user: FFAdminUser, + mocker: MockerFixture, +) -> None: + # Given + request = mocker.MagicMock(spec=Request, user=admin_user) + view = mocker.MagicMock( + spec=GenericViewSet, + action="list", + kwargs={"environment_pk": 1000000}, + ) + + # When / Then + with pytest.raises(Http404): + EnvironmentFeatureVersionFeatureStatePermissions().has_permission(request, view) + + +def test_environment_feature_version_permissions__missing_feature__raises_404( + admin_user: FFAdminUser, + environment: Environment, + feature: Feature, + mocker: MockerFixture, +) -> None: + # Given + request = mocker.MagicMock(spec=Request, user=admin_user) + view = mocker.MagicMock( + spec=GenericViewSet, + action="create", + kwargs={ + "environment_pk": environment.id, + "feature_pk": feature.id + 1000000, + }, + ) + + # When / Then + with pytest.raises(Http404): + EnvironmentFeatureVersionPermissions().has_permission(request, view)