mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
- A secret is in use when a VM names it in a disk, a host device or its vTPM, or a pool in its source, by UUID or by its usage within the usage type, as they run and as saved. The vTPM, host devices and pools' saved definitions were not checked before. - A Ceph key is taken in base64, as `ceph auth get-key` prints it; any other value is a password or passphrase stored as typed, spaces included. - A new secret takes its value at once; a value refused leaves no secret. - TLS and vTPM secrets can be created; the usage has no length limit. - Every POST redirects; the list is read once and only with its users; a secret, VM or pool gone meanwhile is left out. - domain_trees() is shared by the in-use checks of secrets, network filters, networks and pools; the storage page's Ceph secret picker reads the same listing.
60 lines
2.9 KiB
Python
60 lines
2.9 KiB
Python
"""Secret changes write rows on the Logs page; a secret's value never does."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from computes.models import Compute
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
from vrtManager.util import OperationError
|
|
|
|
from logs.models import Logs
|
|
|
|
UUID = "8f2c0000-0000-4000-8000-000000000009"
|
|
VALUE = "s3cr3t-value"
|
|
|
|
|
|
def rows():
|
|
return list(Logs.objects.order_by("id").values_list("message", "success"))
|
|
|
|
|
|
class SecretRowTests(TestCase):
|
|
def setUp(self):
|
|
self.compute = Compute.objects.create(name="c1", hostname="localhost", login="", password="", type=4)
|
|
self.client.force_login(get_user_model().objects.create_superuser("audit-admin", "a@example.com", "pw"))
|
|
Logs.objects.all().delete() # the login's row
|
|
self.url = reverse("virtsecrets", args=[self.compute.id])
|
|
patcher = patch("virtsecrets.views.wvmSecrets")
|
|
self.conn = patcher.start().return_value
|
|
self.addCleanup(patcher.stop)
|
|
self.conn.get_secrets_info.return_value = []
|
|
|
|
def test_secret_actions(self):
|
|
self.client.post(self.url, {"create": "", "private": "on", "usage_type": "ceph", "usage": "client.admin",
|
|
"value": VALUE})
|
|
self.client.post(self.url, {"set_value": "", "uuid": UUID, "value": VALUE})
|
|
self.client.post(self.url, {"delete": "", "uuid": UUID})
|
|
self.assertEqual(rows(), [
|
|
("Secret ceph client.admin: add", True),
|
|
(f"Secret {UUID}: set value", True),
|
|
(f"Secret {UUID}: delete", True),
|
|
])
|
|
self.assertEqual(set(Logs.objects.values_list("host", flat=True)), {"c1"})
|
|
|
|
def test_a_secret_value_is_never_logged(self):
|
|
# an unexpected error naming the value is raised, its row names only the error's class
|
|
self.conn.set_secret_value.side_effect = ValueError(f"bad value {VALUE}")
|
|
with self.assertRaises(ValueError):
|
|
self.client.post(self.url, {"set_value": "", "uuid": UUID, "value": VALUE})
|
|
self.assertEqual(rows(), [(f"Secret {UUID}: set value: ValueError", False)])
|
|
self.conn.set_secret_value.side_effect = OperationError("A Ceph key is base64 text")
|
|
with patch.object(Logs.objects, "create", side_effect=RuntimeError("db down")), \
|
|
self.assertLogs("logs.audit", "WARNING") as logged:
|
|
self.client.post(self.url, {"set_value": "", "uuid": UUID, "value": VALUE})
|
|
self.assertNotIn(VALUE, "\n".join(logged.output))
|
|
self.assertIn(f"Secret {UUID}: set value", "\n".join(logged.output))
|
|
|
|
def test_a_refused_secret_delete(self):
|
|
self.conn.delete_secret.side_effect = OperationError(f"Secret {UUID} is used by VMs db-2")
|
|
self.client.post(self.url, {"delete": "", "uuid": UUID})
|
|
self.assertEqual(rows(), [(f"Secret {UUID}: delete: Secret {UUID} is used by VMs db-2", False)])
|