8.4 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 07.4 | 01 | execute | 0 |
|
true |
|
|
Purpose: Establishes the Nyquist test harness before any production code changes. Follows the xfail(strict=False) Wave 0 convention established in Phases 7.2 and 7.3.
Output: backend/tests/test_auth_fgp.py with 4 stubs; full test suite still passes with zero failures.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/07.4-security-token-fingerprinting-token-binding-inserted/07.4-CONTEXT.md @.planning/phases/07.4-security-token-fingerprinting-token-binding-inserted/07.4-RESEARCH.md @.planning/phases/07.4-security-token-fingerprinting-token-binding-inserted/07.4-PATTERNS.mdFrom backend/tests/test_auth_deps.py (full harness to copy):
Imports: import uuid import pytest import pytest_asyncio from httpx import ASGITransport, AsyncClient from fastapi import FastAPI, Depends from sqlalchemy.ext.asyncio import AsyncSession from tests.test_auth_api import FakeRedis
make_test_app(): Creates minimal FastAPI app with /test/me route wired to get_current_user. Sets app.state.redis = FakeRedis() so NBF check and fgp check can access request.app.state.redis.
auth_client fixture: @pytest_asyncio.fixture async def auth_client(db_session: AsyncSession): app = make_test_app() app.dependency_overrides[get_db] = lambda: db_session async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c: yield c app.dependency_overrides.clear()
_create_user helper (no decorator — plain async function): Inserts minimal User row; returns User ORM object. Fields: id=uuid.uuid4(), handle, email, password_hash, role, is_active=True
Test function pattern: @pytest.mark.asyncio async def test_name(auth_client, db_session): from services.auth import create_access_token user = await _create_user(db_session) token = create_access_token(str(user.id), "user") resp = await auth_client.get("/test/me", headers={"Authorization": f"Bearer {token}"}) assert resp.status_code == 200
conftest _patch_es256_test_keys is autouse=True at session scope — no explicit reference needed in this file.
From backend/tests/test_auth_es256.py (xfail stub pattern for Phase 7.3): @pytest.mark.xfail(strict=False, reason="not implemented yet") @pytest.mark.asyncio async def test_stub_name(...): pytest.xfail("not implemented yet")
Task 1: Create test_auth_fgp.py with 4 xfail stubs (FGP-01..FGP-04) backend/tests/test_auth_fgp.py - backend/tests/test_auth_deps.py — copy the full harness (make_test_app, auth_client fixture, _create_user helper, imports block). This is the structural template; copy verbatim then modify test functions only. - backend/tests/test_auth_es256.py — xfail stub decoration pattern used in Phase 7.3. Stubs use @pytest.mark.xfail(strict=False, reason="not implemented yet") and body is only pytest.xfail("not implemented yet"). - .planning/phases/07.4-security-token-fingerprinting-token-binding-inserted/07.4-RESEARCH.md §"Test Case Structure" — exact test names and behaviour descriptions for all 4 tests. - FGP-01 test_fgp_match_returns_200: issues token with user_agent="Mozilla/5.0" accept_lang="en", sends request with matching headers — expects 200 - FGP-02 test_fgp_mismatch_returns_401: issues token with user_agent="Mozilla/5.0" accept_lang="en", sends request with user_agent="different-agent" — expects 401 and detail="Token fingerprint mismatch" - FGP-03 test_no_fgp_claim_allowed: crafts token manually without "fgp" key in payload — expects 200 (migration grace) - FGP-04 test_missing_headers_empty_string_binding: issues token with no user_agent/accept_lang args (defaults to ""), sends request with no User-Agent/Accept-Language headers — expects 200 Create backend/tests/test_auth_fgp.py. Structure:1. Module docstring explaining Phase 7.4 fgp test coverage (FGP-01..04).
2. Imports: copy the exact imports block from test_auth_deps.py. Add these additional imports needed for FGP-03 (manual token craft): `import base64`, `import time`, `import jwt as _jwt`, and `from config import settings`.
3. Copy make_test_app() verbatim from test_auth_deps.py (includes app.state.redis = FakeRedis()). Do NOT add a /test/admin route — not needed here.
4. Copy auth_client fixture verbatim from test_auth_deps.py.
5. Copy _create_user helper verbatim from test_auth_deps.py.
6. Write 4 test functions in this order:
- test_fgp_match_returns_200 (FGP-01)
- test_fgp_mismatch_returns_401 (FGP-02)
- test_no_fgp_claim_allowed (FGP-03)
- test_missing_headers_empty_string_binding (FGP-04)
Each test function:
- Decorated with @pytest.mark.xfail(strict=False, reason="not implemented yet") ABOVE @pytest.mark.asyncio
- Decorated with @pytest.mark.asyncio
- Accepts (auth_client, db_session) as parameters
- Body is a single line: pytest.xfail("not implemented yet")
Do NOT write any assertion logic, token construction, or request code inside the stubs. The stub body is ONLY the pytest.xfail() call. Implementation comes in Wave 1 (Plan 07.4-02).
7. No production files (services/auth.py, deps/auth.py, api/auth.py) may be modified in this task.
<threat_model>
Trust Boundaries
| Boundary | Description |
|---|---|
| test harness → test DB | xfail stubs create no DB state; no trust boundary crossed in Wave 0 |
STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|---|---|---|---|---|
| T-07.4-SC | Tampering | npm/pip/cargo installs | accept | No new packages installed in this plan; stdlib only |
| </threat_model> |
<success_criteria>
backend/tests/test_auth_fgp.pyexists with 4 test stubs (FGP-01..04)- All 4 stubs use
@pytest.mark.xfail(strict=False, reason="not implemented yet") - Full test suite passes with zero failures; 4 new XFAIL added
- No production code modified </success_criteria>