1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-10 04:06:47 +00:00

feat(virtsecrets): the secrets page on Bootstrap's cards, tables and dialogs

- One searchable card: each secret's type, usage and UUID, whether it is
  kept on disk or in memory and private, and the VMs and pools that use it,
  linked. A row menu sets its value or deletes it; Delete is disabled while
  the secret is in use, and its confirmation says what is not checked.
- One Set value dialog for every secret; its label and help follow the
  type (Ceph key, CHAP password, passphrase), and it says a new passphrase
  does not encrypt anew what the old one encrypted.
- New secret dialog: the usage's and value's labels and help follow the
  type; the value is optional; Private and Ephemeral are switches with help.
This commit is contained in:
catborise 2026-10-29 09:38:08 +03:00
parent a95ec40f69
commit 2a773f6ec0
5 changed files with 249 additions and 138 deletions

View file

@ -1,5 +1,6 @@
"""The secrets page never holds a secret's value: the edit dialog only
writes a new one."""
"""The secrets page never holds a secret's value: the Set value dialog only
writes a new one. Each secret shows the VMs and pools that use it, and one in
use is not offered for deletion."""
from unittest.mock import patch
@ -7,29 +8,51 @@ from computes.models import Compute
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from instances.models import Instance
from lxml import html
UUID = "0e5b1f0a-8f3e-4c1a-9d2b-5c6d7e8f9a0b"
class SecretsPageTests(TestCase):
def page(self, usage_type):
def page(self, usage_type="ceph", users=None):
compute = Compute.objects.create(name="secrets-page", hostname="localhost", login="", password="", type=4)
Instance.objects.create(compute=compute, name="db-1", uuid="00000000-0000-4000-8000-0000000000d1")
self.client.force_login(get_user_model().objects.create_superuser("page", "page@example.com", "pw"))
with patch("virtsecrets.views.wvmSecrets") as conn:
conn.return_value.get_secrets_info.return_value = [
{"uuid": "0e5b1f0a-8f3e-4c1a-9d2b-5c6d7e8f9a0b", "usage_type": usage_type, "usage": "client.libvirt",
"ephemeral": False, "private": False}]
conn.return_value.get_users.return_value = {}
conn.return_value.wvm.secretLookupByUUIDString.return_value.value.return_value = b"cephx key"
{"uuid": UUID, "usage_type": usage_type, "usage": "client.libvirt", "ephemeral": False, "private": True}]
conn.return_value.get_users.return_value = users or {}
response = self.client.get(reverse("virtsecrets", args=[compute.id]))
self.assertEqual(response.status_code, 200)
return response
return html.fromstring(response.content)
def test_a_vtpm_secret_is_listed(self):
self.assertContains(self.page("vtpm"), "vtpm")
self.assertEqual(self.page("vtpm").xpath("//tbody/tr/td[1]/span/text()"), ["vTPM"])
def test_the_page_holds_no_secret_value(self):
response = self.page("ceph")
self.assertFalse(b"cephx key" in response.content, "the secret's value is on the page")
field = html.fromstring(response.content).get_element_by_id("secret_value_0e5b1f0a-8f3e-4c1a-9d2b-5c6d7e8f9a0b")
field = self.page().get_element_by_id("set_value")
self.assertIsNone(field.get("value"))
self.assertEqual(field.get("type"), "password")
def test_a_secret_in_use_shows_its_users_and_is_not_deleted(self):
page = self.page(users={UUID: {"vms": ["db-1", "gone-1"], "pools": ["ceph-rbd"]}})
instance = Instance.objects.get(name="db-1")
self.assertEqual(page.xpath("//tbody/tr/td[4]//a/@href")[0], reverse("instances:instance", args=[instance.id]))
self.assertIn("gone-1", page.xpath("string(//tbody/tr/td[4])"))
self.assertTrue(page.xpath("//tbody/tr/td[4]//a[contains(., 'ceph-rbd')]"))
self.assertIsNotNone(page.xpath("//button[@name='delete']")[0].get("disabled"))
def test_an_unused_secret_can_be_deleted(self):
self.assertIsNone(self.page().xpath("//button[@name='delete']")[0].get("disabled"))
def test_a_secret_without_usage_is_named_by_its_uuid(self):
compute = Compute.objects.create(name="secrets-none", hostname="localhost", login="", password="", type=4)
self.client.force_login(get_user_model().objects.create_superuser("none", "none@example.com", "pw"))
with patch("virtsecrets.views.wvmSecrets") as conn:
conn.return_value.get_secrets_info.return_value = [
{"uuid": UUID, "usage_type": "none", "usage": "", "ephemeral": True, "private": False}]
conn.return_value.get_users.return_value = {}
page = html.fromstring(self.client.get(reverse("virtsecrets", args=[compute.id])).content)
self.assertEqual(page.xpath("//button[@data-bs-target='#SetSecretValue']/@data-usage"), [UUID])
self.assertEqual(page.xpath("//tbody/tr/td[1]/span/text()"), ["none"])