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

fix(deps): libpass instead of crypt-r; gstfsd's python3-libguestfs on a RHEL compute; PyYAML for the tests

- The root password's SHA-512 crypt hash comes from libpass (the maintained
  passlib fork, pure Python) instead of crypt-r, a copy of the stdlib crypt
  module gone in Python 3.13: crypt-r ships no wheels and its build needs
  crypt.h, which Ubuntu 26.04 no longer brings with python3-dev, so the
  installer and the manual installation failed there. The hash is the same
  format ($6$, now with libpass's 656000 rounds), checked with glibc's crypt.
- The README's RHEL compute packages left out python3-libguestfs, which
  gstfsd imports with the system python: setting the password or key of a
  shut-off VM failed there.
- The tests read YAML themselves and had PyYAML only through
  drf-spectacular.
This commit is contained in:
catborise 2026-11-07 17:19:40 +03:00
parent 25a2f22b90
commit f411659f40
5 changed files with 10 additions and 11 deletions

View file

@ -240,7 +240,7 @@ Sign in at `http://<server-ip>`; you must set a new password at the first login,
A compute node is a KVM host the panel manages over libvirt.
1. Install KVM and libvirt. The bootstrap script handles Ubuntu, Debian, CentOS, Fedora, Rocky Linux and AlmaLinux 10, openEuler 24.03 LTS, openSUSE and SLES. On RHEL, which needs EPEL from its release RPM, install the `qemu-kvm` and `libvirt` packages yourself and enable `virtqemud.socket` (plus `virtproxyd-tcp.socket` for TCP):
1. Install KVM and libvirt. The bootstrap script handles Ubuntu, Debian, CentOS, Fedora, Rocky Linux and AlmaLinux 10, openEuler 24.03 LTS, openSUSE and SLES. On RHEL, which needs EPEL from its release RPM, install the `qemu-kvm`, `libvirt` and `python3-libguestfs` (for gstfsd, step 3) packages yourself and enable `virtqemud.socket` (plus `virtproxyd-tcp.socket` for TCP):
```bash
curl -fsSL https://raw.githubusercontent.com/retspen/webvirtcloud/master/dev/libvirt-bootstrap.sh | sudo sh

View file

@ -23,4 +23,5 @@ python-socketio==5.18.1
segno==1.6.6
websockify==0.13.0
whitenoise==6.12.0
crypt-r>=3.13.0; python_version >= "3.11"
# the root password's SHA-512 crypt hash (the stdlib crypt is gone in Python 3.13)
libpass==1.9.4

View file

@ -6,6 +6,8 @@ libsass==0.23.0
django-debug-toolbar==8.0.0
django-debug-toolbar-template-profiler==2.1.0
pip-audit==2.10.1
# the tests read cloud-init's YAML
PyYAML==6.0.3
ruff==0.17.0
# tracebacks of failures in manage.py test --parallel
tblib==3.2.2

View file

@ -1,3 +1,4 @@
from passlib.hash import sha512_crypt
from unittest.mock import patch
from django.contrib.auth import get_user_model
@ -45,9 +46,10 @@ class SetRootPassTestCase(TestCase):
self.assertEqual(compute, self.compute)
self.assertEqual(data["action"], "password")
self.assertEqual(data["vname"], "renamed-on-host")
# SHA-512 crypt with a random salt, not the old fixed one
# SHA-512 crypt with a random salt, not the old fixed one, which the guest's crypt(3) checks
self.assertTrue(data["passwd"].startswith("$6$"))
self.assertFalse(data["passwd"].startswith("$6$kgPoiREy$"))
self.assertTrue(sha512_crypt.verify("newSecretPassword123", data["passwd"]))
def test_set_root_pass_get_not_allowed(self):
response = self.client.get(reverse("instances:rootpasswd", args=[self.instance.id]))

View file

@ -7,17 +7,10 @@ import os
import re
import secrets
import socket
import sys
import subprocess
import time
from ipaddress import ip_address
# the stdlib crypt is deprecated from Python 3.11 and gone in 3.13: crypt_r is the same module
if sys.version_info >= (3, 11):
import crypt_r as crypt
else:
import crypt
from accounts.models import UserInstance, UserSSHKey
from admin.decorators import superuser_only
from appsettings.models import AppSettings
@ -42,6 +35,7 @@ from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy, gettext_noop
from django.views.decorators.http import require_POST
from django.views.decorators.debug import sensitive_post_parameters
from passlib.hash import sha512_crypt
from libvirt import (VIR_DOMAIN_PAUSED,
VIR_DOMAIN_RUNNING,
VIR_DOMAIN_SHUTOFF,
@ -1076,7 +1070,7 @@ def set_root_pass(request, pk):
if request.method == "POST":
passwd = request.POST.get("passwd", None)
if passwd:
passwd_hash = crypt.crypt(passwd, crypt.mksalt(crypt.METHOD_SHA512))
passwd_hash = sha512_crypt.hash(passwd)
# gstfsd opens the domain by name: send the host's current one.
data = {"action": "password", "passwd": passwd_hash, "vname": instance.proxy.instance.name()}