- tests/: 55 тестов web-панели, авторизации, сети и обновлений, все страницы рендерятся на замоканных virsh/systemctl; - GitHub Actions: pyflakes + pytest на Python 3.11–3.13, shellcheck, сборка ISO amd64/arm64 по тегу v* или вручную; - Makefile: make check / make test / make iso; - docs/IMAGE.md и README: установка с ISO, продакшен-настройки, разработка; - updates/versions.json: описание версии 0.10.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LEUXMcdZo7b87mjkUsPgg
50 строки
1.8 KiB
Python
50 строки
1.8 KiB
Python
import pytest
|
|
|
|
import auth
|
|
|
|
# SHA-512 crypt hash of "s3cret" with salt "virtualitysalt".
|
|
SHA512_HASH = "$6$virtualitysalt$"
|
|
|
|
|
|
@pytest.fixture()
|
|
def password_hash():
|
|
computed = auth.crypt_hash("s3cret", SHA512_HASH)
|
|
assert computed and computed.startswith(SHA512_HASH)
|
|
return computed
|
|
|
|
|
|
def write_shadow(tmp_path, monkeypatch, entries):
|
|
shadow = tmp_path / "shadow"
|
|
shadow.write_text("".join(f"{user}:{pw}:19000:0:99999:7:::\n" for user, pw in entries))
|
|
monkeypatch.setattr(auth, "SHADOW_FILE", shadow)
|
|
monkeypatch.setattr(auth, "_stdlib_spwd", None)
|
|
|
|
|
|
def test_libcrypt_fallback_matches(password_hash, monkeypatch):
|
|
monkeypatch.setattr(auth, "_stdlib_crypt", None)
|
|
assert auth.crypt_hash("s3cret", password_hash) == password_hash
|
|
assert auth.crypt_hash("wrong", password_hash) != password_hash
|
|
|
|
|
|
def test_verify_password_with_shadow_file(password_hash, tmp_path, monkeypatch):
|
|
write_shadow(tmp_path, monkeypatch, [("root", "*"), ("admin", password_hash), ("locked", "!" + password_hash)])
|
|
monkeypatch.setattr(auth, "_stdlib_crypt", None)
|
|
assert auth.verify_password("admin", "s3cret")
|
|
assert not auth.verify_password("admin", "wrong")
|
|
assert not auth.verify_password("admin", "")
|
|
assert not auth.verify_password("root", "anything")
|
|
assert not auth.verify_password("locked", "s3cret")
|
|
assert not auth.verify_password("missing", "s3cret")
|
|
|
|
|
|
def test_throttle_locks_and_resets():
|
|
throttle = auth.LoginThrottle(max_failures=3, window_seconds=60, lockout_seconds=60)
|
|
for _ in range(2):
|
|
throttle.record_failure("1.2.3.4")
|
|
assert throttle.retry_after("1.2.3.4") == 0
|
|
throttle.record_failure("1.2.3.4")
|
|
assert throttle.retry_after("1.2.3.4") > 0
|
|
assert throttle.retry_after("5.6.7.8") == 0
|
|
throttle.record_success("1.2.3.4")
|
|
assert throttle.retry_after("1.2.3.4") == 0
|