From 02ab78fe94271bd12a156ac40bbf19edaff386d7 Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 5 Nov 2026 08:46:27 +0300 Subject: [PATCH] fix(instances): a clone size of a digit that is no number gets the form's refusal clone_data checked the clone's vCPUs and memory with str.isdigit(), which takes characters such as a superscript two that int() refuses: the user saw Python's "invalid literal for int()" instead of the refusal. It now checks with str.isdecimal(), whose characters int() reads. --- instances/jobs.py | 2 +- instances/tests/test_clone_job.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/instances/jobs.py b/instances/jobs.py index 54bf23a1..de7be21b 100644 --- a/instances/jobs.py +++ b/instances/jobs.py @@ -137,7 +137,7 @@ def clone_data(user, instance, fields): ("memory", instance.config_memory, _("Enter a whole number of memory (MiB) for the clone"))): value = fields.get(f"clone-{key}") or str(source) - if not value.isdigit() or int(value) < 1: + if not value.isdecimal() or int(value) < 1: raise util.OperationError(refusal) # None: as the VM, nothing to change after the copy data[key] = int(value) if int(value) != source else None diff --git a/instances/tests/test_clone_job.py b/instances/tests/test_clone_job.py index 2a800231..b96aa225 100644 --- a/instances/tests/test_clone_job.py +++ b/instances/tests/test_clone_job.py @@ -6,6 +6,7 @@ from uuid import uuid4 import libvirt from django.contrib.auth import get_user_model +from django.contrib.messages import get_messages from django.core.exceptions import PermissionDenied from django.test import TransactionTestCase from django.urls import reverse @@ -116,6 +117,13 @@ class CloneJobTestCase(TransactionTestCase): self.assertIsNone(op) self.proxy.clone_instance.assert_not_called() + def test_a_digit_that_is_not_a_number_is_refused_with_the_reason(self): + # superscript two: str.isdigit() takes it, int() does not + response = self.client.post(reverse("instances:clone", args=[self.source.pk]), + {"name": "copy", "disk-vda": "copy.qcow2", "clone-net-mac-0": "52:54:00:00:00:01", + "submission_key": "key-clone003", "clone-vcpu": "\u00b2"}) + self.assertEqual([str(m) for m in get_messages(response.wsgi_request)], ["Enter a whole number of vCPUs for the clone"]) + def test_a_clone_that_cannot_start_is_made_with_a_warning(self): self.proxy.start.side_effect = libvirt.libvirtError("no memory") op, result = self.clone_with(**{"clone-start": "true"})