Skip to content

Commit 1c3ac9b

Browse files
committed
Use passlib in place of legacycrypt
legacycrypt requires to install libcrypt.so.1 manually Keep legacycrypt as a dependency for now, to ease the transition to those who already have a custom data.py. Move hash_password() to lib.common, to make easier to change the implementation in the future. Signed-off-by: Gaëtan Lehmann <gaetan.lehmann@vates.tech>
1 parent 617a600 commit 1c3ac9b

8 files changed

Lines changed: 44 additions & 21 deletions

File tree

conftest.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,17 @@
1313
import lib.config as global_config
1414
from lib import pxe
1515
from lib.common import (
16-
callable_marker,
1716
DiskDevName,
1817
HostAddress,
18+
callable_marker,
1919
is_uuid,
2020
prefix_object_name,
21-
setup_formatted_and_mounted_disk,
2221
shortened_nodeid,
23-
teardown_formatted_and_mounted_disk,
2422
vm_image,
2523
wait_for,
2624
)
27-
from lib.netutil import is_ipv6
2825
from lib.host import Host
26+
from lib.netutil import is_ipv6
2927
from lib.pool import Pool
3028
from lib.sr import SR
3129
from lib.vm import VM, vm_cache_key_from_def
@@ -34,8 +32,6 @@
3432
# Import package-scoped fixtures. Although we need to define them in a separate file so that we can
3533
# then import them in individual packages to fix the buggy package scope handling by pytest, we also
3634
# need to import them in the global conftest.py so that they are recognized as fixtures.
37-
from pkgfixtures import formatted_and_mounted_ext4_disk, sr_disk_wiped
38-
3935
from typing import Dict, Generator, Iterable
4036

4137
# Do we cache VMs?
@@ -321,7 +317,7 @@ def xfail_on_xcpng_8_3(host, request):
321317
@pytest.fixture(scope='session')
322318
def host_no_ipv6(host):
323319
if is_ipv6(host.hostname_or_ip):
324-
pytest.skip(f"This test requires an IPv4 XCP-ng")
320+
pytest.skip("This test requires an IPv4 XCP-ng")
325321

326322
@pytest.fixture(scope="session")
327323
def shared_sr(host):
@@ -442,9 +438,7 @@ def vm_ref(request):
442438
logging.info(">> No VM specified on CLI, and no default found in test definition. Using global default.")
443439
ref = 'mini-linux-x86_64-bios'
444440

445-
if is_uuid(ref):
446-
return ref
447-
elif ref.startswith('http'):
441+
if is_uuid(ref) or ref.startswith('http'):
448442
return ref
449443
else:
450444
return vm_image(ref)

data.py-dist

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
from __future__ import annotations
44

5-
import legacycrypt as crypt # type: ignore
65
import os
7-
from typing import Any, TYPE_CHECKING
6+
7+
from lib.common import hash_password
8+
9+
from typing import TYPE_CHECKING, Any
810

911
if TYPE_CHECKING:
1012
from lib.typing import IsoImageDef
@@ -15,11 +17,6 @@ if TYPE_CHECKING:
1517
HOST_DEFAULT_USER = "root"
1618
HOST_DEFAULT_PASSWORD = ""
1719

18-
def hash_password(password):
19-
"""Hash password for /etc/password."""
20-
salt = crypt.mksalt(crypt.METHOD_SHA512)
21-
return crypt.crypt(password, salt)
22-
2320
HOST_DEFAULT_PASSWORD_HASH = hash_password(HOST_DEFAULT_PASSWORD)
2421

2522
# Public keys for a private keys available to the test runner

lib/common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from uuid import UUID
1919

2020
import requests
21+
from passlib.hash import sha512_crypt
2122
from pydantic import TypeAdapter
2223

2324
from typing import (
@@ -367,3 +368,7 @@ def _param_clear(host, xe_prefix, uuid, param_name):
367368
""" Common implementation for param_clear. """
368369
args = {'uuid': uuid, 'param-name': param_name}
369370
host.xe(f'{xe_prefix}-param-clear', args)
371+
372+
def hash_password(password: str) -> str:
373+
"""Hash password for /etc/password."""
374+
return sha512_crypt.using(rounds=5000).hash(password)

pkgfixtures.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from __future__ import annotations
22

33
import pytest
4-
from typing import TYPE_CHECKING, Generator
54

65
import logging
76

87
from lib.common import setup_formatted_and_mounted_disk, teardown_formatted_and_mounted_disk
98

9+
from typing import TYPE_CHECKING, Generator
10+
1011
if TYPE_CHECKING:
1112
from lib.common import DiskDevName
1213
from lib.host import Host

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ requires-python = ">=3.11"
77
dependencies = [
88
"cryptography>=3.3.1",
99
"gitpython",
10+
# TODO: keep legacycrypt to let the user transition to lib.common.hash_password in their data.py
1011
"legacycrypt",
1112
"packaging>=20.7",
13+
"passlib",
1214
"pluggy>=1.1.0",
1315
"pydantic",
1416
"pytest>=8.0.0",
@@ -30,6 +32,7 @@ dev = [
3032
"types-requests",
3133
"typing-extensions",
3234
"libarchive-c==5.3",
35+
"types-passlib",
3336
]
3437

3538
[tool.pyright]

requirements/base.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ cryptography>=3.3.1
33
gitpython
44
legacycrypt
55
packaging>=20.7
6+
passlib
67
pluggy>=1.1.0
78
pydantic
89
pytest>=8.0.0

scripts/install_xcpng.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# flake8: noqa: E402
1818
sys.path.append(f"{os.path.abspath(os.path.dirname(__file__))}/..")
1919
from lib import pxe
20-
from lib.commands import SSHCommandFailed, scp, ssh
20+
from lib.commands import SSHCommandFailed, ssh
2121
from lib.common import is_uuid, wait_for
2222
from lib.host import host_data
2323
from lib.pool import Pool
@@ -62,7 +62,7 @@ def generate_answerfile(directory, installer, hostname_or_ip, target_hostname, a
6262
</installation>
6363
""")
6464
elif action == 'restore':
65-
answerfile.write(f"""<?xml version="1.0"?>
65+
answerfile.write("""<?xml version="1.0"?>
6666
<restore>
6767
</restore>
6868
""")
@@ -159,7 +159,7 @@ def main():
159159

160160
try:
161161
pool = Pool(args.host) # will fail if host is not XCP-ng or XAPI doesn't respond yet
162-
except Exception as e:
162+
except Exception:
163163
raise Exception(f"Host `{args.host}` isn't ready or isn't an XCP-ng host")
164164

165165
host = pool.master

uv.lock

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)