diff --git a/backend/tests/test_auth_es256.py b/backend/tests/test_auth_es256.py new file mode 100644 index 0000000..8e0567f --- /dev/null +++ b/backend/tests/test_auth_es256.py @@ -0,0 +1,123 @@ +""" +TDD scaffold for Phase 7.3: ES256 algorithm upgrade, startup token rotation, +and remember_me session TTL — all stubs xfail strict=True until promoted. +""" +from __future__ import annotations + +import base64 +import hashlib +import json +import time +import uuid +from datetime import datetime, timedelta, timezone + +import pytest +import pytest_asyncio + + +# ── ES256 key fixture ──────────────────────────────────────────────────────── + + +@pytest.fixture(autouse=True) +def es256_keys(monkeypatch): + """Generate a throw-away P-256 keypair and monkeypatch it into settings. + + raising=False: settings fields do not exist until Plan 02 adds them; + this fixture must not error before that. + """ + from cryptography.hazmat.primitives.asymmetric import ec + from cryptography.hazmat.primitives import serialization + + private_key = ec.generate_private_key(ec.SECP256R1()) + private_pem = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption(), + ) + public_pem = private_key.public_key().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + private_b64 = base64.b64encode(private_pem).decode() + public_b64 = base64.b64encode(public_pem).decode() + + import config + monkeypatch.setattr(config.settings, "jwt_private_key", private_b64, raising=False) + monkeypatch.setattr(config.settings, "jwt_public_key", public_b64, raising=False) + + +# ── ES256-01: access token algorithm ───────────────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="ES256-01: not yet implemented") +def test_access_token_uses_es256(): + pytest.xfail("not yet implemented") + + +# ── ES256-02: HS256 token rejected ─────────────────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="ES256-02: not yet implemented") +def test_hs256_token_rejected(): + pytest.xfail("not yet implemented") + + +# ── ES256-03: password-reset token algorithm ────────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="ES256-03: not yet implemented") +def test_reset_token_uses_es256(): + pytest.xfail("not yet implemented") + + +# ── ES256-04: startup rotation revokes tokens ───────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="ES256-04: not yet implemented") +@pytest.mark.asyncio +async def test_startup_rotation_revokes_tokens(db_session): + pytest.xfail("not yet implemented") + + +# ── ES256-05: startup rotation is idempotent ───────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="ES256-05: not yet implemented") +@pytest.mark.asyncio +async def test_startup_rotation_idempotent(db_session): + pytest.xfail("not yet implemented") + + +# ── RM-01: default TTL is 16 hours ─────────────────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="RM-01: not yet implemented") +@pytest.mark.asyncio +async def test_default_ttl_16_hours(async_client, db_session, auth_user): + pytest.xfail("not yet implemented") + + +# ── RM-02: remember_me TTL is 30 days ──────────────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="RM-02: not yet implemented") +@pytest.mark.asyncio +async def test_remember_me_ttl_30_days(async_client, db_session, auth_user): + pytest.xfail("not yet implemented") + + +# ── RM-03: cookie Max-Age values ───────────────────────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="RM-03: not yet implemented") +@pytest.mark.asyncio +async def test_remember_me_cookie_max_age(async_client, auth_user): + pytest.xfail("not yet implemented") + + +# ── CFG-01 satellite: settings has jwt key fields ──────────────────────────── + + +@pytest.mark.xfail(strict=True, reason="CFG-01: not yet implemented") +def test_settings_has_jwt_keys(): + pytest.xfail("not yet implemented") diff --git a/backend/tests/test_task1_models_config.py b/backend/tests/test_task1_models_config.py index c833ff0..2144ec8 100644 --- a/backend/tests/test_task1_models_config.py +++ b/backend/tests/test_task1_models_config.py @@ -29,6 +29,10 @@ def test_settings_has_jwt_config(): assert settings.access_token_expire_minutes == 15 assert hasattr(settings, "refresh_token_expire_days") assert settings.refresh_token_expire_days == 30 + assert hasattr(settings, "refresh_token_expire_hours") + assert settings.refresh_token_expire_hours == 16 + assert hasattr(settings, "jwt_private_key") + assert hasattr(settings, "jwt_public_key") def test_settings_has_smtp_config():