From 99f55825aac4e9d0de064ae61e44e0bf832284b3 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Sat, 6 Jun 2026 17:13:50 +0200 Subject: [PATCH] =?UTF-8?q?test(07.3-01):=20Wave=200=20Nyquist=20scaffold?= =?UTF-8?q?=20=E2=80=94=209=20xfail=20stubs=20for=20ES256=20+=20remember?= =?UTF-8?q?=5Fme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create test_auth_es256.py with 9 xfail(strict=True) stubs: ES256-01..05, RM-01..03, CFG-01 - Add es256_keys(autouse) fixture using cryptography P-256 keygen + monkeypatch with raising=False - Extend test_settings_has_jwt_config to assert refresh_token_expire_hours==16 + jwt key fields --- backend/tests/test_auth_es256.py | 123 ++++++++++++++++++++++ backend/tests/test_task1_models_config.py | 4 + 2 files changed, 127 insertions(+) create mode 100644 backend/tests/test_auth_es256.py 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():