shinkan-jinkendo/backend/tests/test_auth_password_reset_minlength.py
Lars fc33bfbdeb
All checks were successful
Deploy Development / deploy (push) Successful in 37s
Test Suite / pytest-backend (push) Successful in 34s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 8s
Test Suite / playwright-tests (push) Successful in 26s
feat(compliance): update retention policy and enhance password reset validation
- Adjusted retention policy to align with compliance requirements:
  - Changed HIDDEN_TO_PURGE_DAYS from 90 to 30 days.
- Enhanced password reset functionality to enforce a minimum password length of 8 characters.
- Updated tests to validate new password requirements and retention logic.
- Corrected umlaut in copyright error messages for clarity.
2026-05-10 08:26:15 +02:00

101 lines
3.4 KiB
Python

"""
P-05b: POST /api/auth/reset-password muss Passwoerter unter 8 Zeichen ablehnen.
Prueft Pydantic-Validierung (HTTP 422) BEVOR die DB befragt wird.
"""
from __future__ import annotations
import os
from unittest.mock import MagicMock, patch
import pytest
from fastapi.testclient import TestClient
os.environ.setdefault("SKIP_DB_MIGRATE", "1")
from main import app
@pytest.fixture
def client() -> TestClient:
return TestClient(app)
def _mock_db_valid_token() -> MagicMock:
mock_cur = MagicMock()
mock_cur.fetchone.return_value = {"profile_id": 1}
mock_conn = MagicMock()
mock_cm = MagicMock()
mock_cm.__enter__.return_value = mock_conn
mock_cm.__exit__.return_value = False
return mock_cm, mock_cur
# ── Mindestlaenge-Grenzwerte ──────────────────────────────────────────────────
@pytest.mark.parametrize("short_pw", ["", "a", "1234567"])
def test_reset_password_too_short_rejected(client: TestClient, short_pw: str) -> None:
"""Passwort < 8 Zeichen muss mit 422 abgelehnt werden (Pydantic-Validierung)."""
r = client.post(
"/api/auth/reset-password",
json={"token": "sometoken", "new_password": short_pw},
)
assert r.status_code == 422, (
f"Erwartet 422 fuer Passwort {short_pw!r} ({len(short_pw)} Zeichen), "
f"erhalten {r.status_code}"
)
def test_reset_password_exactly_8_chars_accepted(client: TestClient) -> None:
"""Passwort mit genau 8 Zeichen muss die Validierung passieren."""
mock_cm, mock_cur = _mock_db_valid_token()
with patch("routers.auth.get_db", return_value=mock_cm), patch(
"routers.auth.get_cursor", return_value=mock_cur
):
r = client.post(
"/api/auth/reset-password",
json={"token": "sometoken", "new_password": "12345678"},
)
assert r.status_code == 200
assert r.json().get("ok") is True
def test_reset_password_long_password_accepted(client: TestClient) -> None:
"""Langes Passwort (>= 8 Zeichen) muss akzeptiert werden."""
mock_cm, mock_cur = _mock_db_valid_token()
with patch("routers.auth.get_db", return_value=mock_cm), patch(
"routers.auth.get_cursor", return_value=mock_cur
):
r = client.post(
"/api/auth/reset-password",
json={"token": "sometoken", "new_password": "sicheresPasswort123!"},
)
assert r.status_code == 200
def test_reset_password_missing_field_rejected(client: TestClient) -> None:
"""Fehlendes new_password-Feld muss mit 422 abgelehnt werden."""
r = client.post(
"/api/auth/reset-password",
json={"token": "sometoken"},
)
assert r.status_code == 422
def test_reset_password_invalid_token_returns_400(client: TestClient) -> None:
"""Gueltiges Passwort aber ungueltiger Token muss 400 liefern."""
mock_cur = MagicMock()
mock_cur.fetchone.return_value = None
mock_conn = MagicMock()
mock_cm = MagicMock()
mock_cm.__enter__.return_value = mock_conn
mock_cm.__exit__.return_value = False
with patch("routers.auth.get_db", return_value=mock_cm), patch(
"routers.auth.get_cursor", return_value=mock_cur
):
r = client.post(
"/api/auth/reset-password",
json={"token": "ungueltig", "new_password": "validesPw123"},
)
assert r.status_code == 400