docs(08-01): complete Wave 0 xfail stubs plan — 3 xpassed, CR-01/02/03 contracts locked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-06-08 16:23:13 +02:00
co-authored by Claude Sonnet 4.6
parent f750d30224
commit c636ac956f
@@ -0,0 +1,129 @@
---
phase: 08-stack-upgrade-backend-decomposition
plan: "01"
subsystem: backend-tests
tags: [tests, session-revocation, xfail, wave-0, cr-01, cr-02, cr-03]
dependency_graph:
requires: []
provides:
- "behavioral contract for CR-01: change_password revokes other sessions"
- "behavioral contract for CR-02: enable_totp revokes other sessions"
- "behavioral contract for CR-03: disable_totp revokes other sessions"
affects:
- "backend/tests/test_auth.py — new file"
tech_stack:
added: []
patterns:
- "xfail(strict=False) Wave 0 scaffold — tests pass now (xpassed), marker removed in 08-03"
- "FakeRedis in-memory store for all auth/TOTP tests (established pattern)"
- "cookies= kwarg for explicit refresh token injection bypassing path restriction"
- "patch.dict(sys.modules) to prevent Celery broker connection on token replay"
key_files:
created:
- path: "backend/tests/test_auth.py"
description: "Three xfail tests for CR-01/CR-02/CR-03 session revocation contracts"
modified: []
decisions:
- "Used fixed User-Agent on revoke_client fixture to match fgp claim in access tokens"
- "Used DB-direct TOTP enable for CR-03 test to avoid extraneous setup session token"
- "Patched services.auth.verify_totp for CR-03 TOTP logins to bypass 90s replay prevention"
- "Patched tasks.email_tasks via patch.dict(sys.modules) to avoid real Celery connection"
metrics:
duration: "10m 8s"
completed: "2026-06-08"
tasks_completed: 1
tasks_total: 1
files_created: 1
files_modified: 0
---
# Phase 8 Plan 01: Wave 0 xfail Stubs for CR-01/CR-02/CR-03 Summary
**One-liner:** Three xfail(strict=False) tests locking session-revocation contracts for change_password, enable_totp, and disable_totp — all xpassed since backend is already complete.
## What Was Built
Created `backend/tests/test_auth.py` with three Wave 0 test stubs:
| Test | Requirement | Status |
|------|------------|--------|
| `test_change_password_revokes_other_sessions` | CR-01 | xpassed |
| `test_enable_totp_revokes_other_sessions` | CR-02 | xpassed |
| `test_disable_totp_revokes_other_sessions` | CR-03 | xpassed |
All three tests pass when run with `--runxfail` (backend already implements the behavior per RESEARCH.md §Wave 1). They show `XPASS` in normal mode since `strict=False`.
## Test Infrastructure
**Fixtures used:**
- `revoke_client` (new, defined in test_auth.py): AsyncClient with FakeRedis, fixed `User-Agent: docuvault-test/1.0`, DB override
- `db_session` (from conftest.py): in-memory SQLite session
**Helper functions:**
- `_register_user(client, handle, email)` — register + assert 201
- `_login_session(client, email)` — login + return (access_token, refresh_cookie)
- `_try_refresh(client, refresh_token)` — POST /api/auth/refresh + return status code
**xfail decorator reason string:** `"Wave 0 stub — promoted to passing in 08-03"`
## Pytest Collection Count
- Pre-change baseline: 0 tests in `test_auth.py` (file did not exist)
- Post-change: 3 tests collected
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] FakeRedis not set on app.state.redis**
- **Found during:** Task 1 implementation
- **Issue:** The plan's existing `authed_client` fixture pattern required FakeRedis injection on `app.state.redis`. Without it, endpoints that call `request.app.state.redis.set(...)` (change_password, enable_totp, disable_totp) would fail.
- **Fix:** Created dedicated `revoke_client` fixture with FakeRedis injection, matching the pattern from `test_auth_api.py`.
- **Files modified:** `backend/tests/test_auth.py`
**2. [Rule 1 - Bug] Token fingerprint mismatch on API calls**
- **Found during:** Task 1 — first test run
- **Issue:** The access token's `fgp` claim is bound to the User-Agent at login time. The plan suggested using distinct User-Agents for session A and B to ensure separate DB rows, but this caused fingerprint mismatch when using token_a in subsequent API calls with a different User-Agent.
- **Fix:** Used a single fixed User-Agent (`"docuvault-test/1.0"`) for the `revoke_client` fixture. Two sequential logins always create two separate RefreshToken rows regardless of User-Agent.
- **Files modified:** `backend/tests/test_auth.py`
**3. [Rule 1 - Bug] TOTP replay prevention blocks second session login in CR-03**
- **Found during:** Task 1 — second test run
- **Issue:** The FakeRedis stores TOTP used-code keys with a 90s TTL. When `_login_with_totp()` was called twice in the same 30-second TOTP window, `pyotp.TOTP(secret).now()` returned the same code which was already marked used in FakeRedis.
- **Fix:** Patched `services.auth.verify_totp` to return `True` for the TOTP login calls in CR-03. The test focuses on session revocation, not TOTP validation.
- **Files modified:** `backend/tests/test_auth.py`
**4. [Rule 1 - Bug] Celery broker connection attempt on revoked token**
- **Found during:** Task 1 — third test run
- **Issue:** When `_try_refresh` is called with session B's revoked token, `rotate_refresh_token` triggers the family-revocation path which calls `send_security_alert_email.delay(...)`. This attempted a real Redis/Celery broker connection (not available in unit tests).
- **Fix:** Patched `tasks.email_tasks` via `patch.dict("sys.modules", {...})` inside `_try_refresh`, matching the pattern from `test_task2_auth_service.py`.
- **Files modified:** `backend/tests/test_auth.py`
## Verification
```
3 xpassed, 10 warnings in 2.02s
```
Full backend suite before this plan (pre-existing): `1 failed (test_extract_docx — ModuleNotFoundError: docx not installed locally), 402 passed`
Full backend suite after this plan: same baseline + 3 xpassed new tests added.
The pre-existing `test_extractor.py::test_extract_docx` failure is a `ModuleNotFoundError: No module named 'docx'` — the `python-docx` package is only installed inside Docker, not in the local Python environment. This is out-of-scope and was pre-existing before Plan 08-01.
## Threat Flags
None — this plan only adds tests, no new network endpoints, auth paths, file access patterns, or schema changes.
## Known Stubs
None — the test bodies contain full assertion logic, not `pass` placeholders.
## Self-Check: PASSED
- [x] `backend/tests/test_auth.py` created and contains 3 test functions
- [x] All three function names match the exact names specified in the plan
- [x] `grep -c "pytest.mark.xfail" backend/tests/test_auth.py` = 4 (3 decorators + 1 in docstring, baseline was 0)
- [x] Commit `f750d30` exists: `git log --oneline | grep f750d30`
- [x] Tests show XPASS status (strict=False xfail)
- [x] No new failures in the full suite