From 623e9874cb2f007caf36b8146588194fd0f2e24b Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 5 Nov 2026 16:37:18 +0300 Subject: [PATCH] fix(instances): the VM page reads the user's rights from the VM's own record It looked the user's ownership up by the VM's name on its compute; names are not unique there (a VM renamed outside the panel and a migration can leave two), which gave a server error or another VM's rights on the page. --- instances/tests/test_vm_page_records.py | 44 +++++++++++++++++++++++++ instances/views.py | 6 +--- 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 instances/tests/test_vm_page_records.py diff --git a/instances/tests/test_vm_page_records.py b/instances/tests/test_vm_page_records.py new file mode 100644 index 00000000..c8cf8990 --- /dev/null +++ b/instances/tests/test_vm_page_records.py @@ -0,0 +1,44 @@ +"""The VM page reads the user's rights from the VM's own record.""" + +from unittest.mock import PropertyMock, patch + +from django.contrib.auth import get_user_model +from django.test import TestCase +from django.urls import reverse + +from accounts.models import UserInstance +from computes.models import Compute +from instances.models import Instance + + +class VmPageRecordsTestCase(TestCase): + def setUp(self): + self.owner = get_user_model().objects.create_user("rows-owner", password="x") + self.compute = Compute.objects.create(name="rows-c", hostname="192.0.2.70", login="root", password="", type=1) + self.vm = Instance.objects.create(compute=self.compute, name="web", uuid="aaaaaaaa-0000-0000-0000-000000000071") + UserInstance.objects.create(instance=self.vm, user=self.owner, is_change=False) + self.client.force_login(self.owner) + + def page(self, wvm_error=None): + with patch("instances.models.wvmInstance", side_effect=wvm_error) as wvm, patch.object( + Compute, "status", new_callable=PropertyMock, return_value=True + ): + proxy = wvm.return_value + proxy.get_memory.return_value = proxy.get_cur_memory.return_value = 1024 + proxy.get_max_memory.return_value = 4096 + proxy.get_hostdevs.return_value = ([], [], []) + proxy.get_console_type.return_value = "vnc" + proxy.get_status.return_value = 5 + for getter in ("get_networks", "get_ifaces", "get_storages", "get_disk_devices", "get_media_devices", + "get_net_devices"): + getattr(proxy, getter).return_value = [] + return self.client.get(reverse("instances:instance", args=[self.vm.id])) + + def test_the_rights_come_from_the_vms_own_record(self): + # another VM of the same name on the compute, owned with more rights: + # its record was not refreshed after a rename outside the panel + other = Instance.objects.create(compute=self.compute, name="web", uuid="aaaaaaaa-0000-0000-0000-000000000072") + UserInstance.objects.create(instance=other, user=self.owner, is_change=True) + response = self.page() + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["userinstance"].instance, self.vm) diff --git a/instances/views.py b/instances/views.py index 8df852e2..32404c5f 100755 --- a/instances/views.py +++ b/instances/views.py @@ -288,11 +288,7 @@ def _instance_page(request, pk, instance, compute): console_listener_addresses = settings.QEMU_CONSOLE_LISTENER_ADDRESSES ipv4_addresses = [address for net in instance.networks for address in net["ipv4"] or []] try: - userinstance = UserInstance.objects.get( - instance__compute_id=compute.id, - instance__name=instance.name, - user__id=request.user.id, - ) + userinstance = UserInstance.objects.get(instance=instance, user=request.user) except UserInstance.DoesNotExist: userinstance = None # The page offers only what the backend allows this user (get_instance