- api/auth.py login + refresh call sites pass User-Agent and Accept-Language
headers to create_access_token (D-05 — fgp binding at token issuance)
- test_auth_fgp.py: promote all 4 xfail stubs to real assertions (FGP-01..04)
- conftest.py: add _TEST_USER_AGENT constant; configure async_client to send
consistent User-Agent; update auth_user/second_auth_user/admin_user fixtures
to bind fgp to _TEST_USER_AGENT so tokens validate correctly in tests
- test_auth_deps.py: import _TEST_USER_AGENT; update auth_client fixture and
all create_access_token calls to use the constant
- test_cloud.py: update _create_user_and_token to bind fgp to _TEST_USER_AGENT
- test_documents.py: update 3 inline create_access_token calls to pass user_agent
- test_security_headers.py: import _TEST_USER_AGENT; update headers_client +
token creation to use the constant
- Version bump: backend 0.1.2 → 0.1.3, frontend 0.1.2 → 0.1.3
- [Rule 1 - Bug] Fix httpx default User-Agent vs empty-string fgp mismatch in
test infrastructure: 10 tests were failing due to fgp check rejecting tokens
created with fgp="" when client sent "python-httpx/X.Y.Z"
After the ES256 upgrade, create_access_token requires non-empty
jwt_private_key / jwt_public_key. The auth_user, second_auth_user,
and admin_user fixtures in conftest.py call create_access_token
without keys being set, breaking all tests that exercise the auth
system. Add a function-scoped autouse fixture that provisions a
generated P-256 keypair for every test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add auth_limiter (IP-level limiter from api.auth) to the reset_rate_limiter
autouse fixture in conftest.py, alongside the existing account_limiter reset.
Prevents spurious 429s when tests call /api/auth/* endpoints in a tight loop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- D-11: replace get_client_ip body with trusted-proxy CIDR check (127/8, 172.16/12,
192.168/16, ::1/128); untrusted peers always return their own IP, preventing XFF
spoofing by external callers
- D-12: create services/rate_limiting.py with _account_key() keyed by user.id
(falls back to peer IP when no authenticated user in request.state); exports
account_limiter = Limiter(key_func=_account_key)
- Wire: auth.py switches from get_remote_address to get_client_ip; main.py imports
account_limiter; all 9 documents.py endpoints and 7 cloud.py endpoints decorated
@account_limiter.limit("100/minute") with request.state.current_user = current_user
as the first handler statement (A1 ordering invariant)
- Promote all 8 xfail stubs to real assertions; add autouse fixture in conftest.py
to reset MemoryStorage between tests preventing cross-test 429 contamination
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add @pytest_asyncio.fixture second_auth_user with handle prefix 'user2_'
- Creates User + Quota row following the same pattern as auth_user
- Returns {user, token, headers} dict shape for use in sharing tests
- Delete backend/data/ tracked files (D-04): flat-file metadata, settings.json,
topics.json, and uploaded files removed from git; backend/data/ added to
.gitignore (empty dir remains on macOS due to ACL — no tracked files remain)
- Prune backend/config.py: remove DATA_DIR, UPLOADS_DIR, METADATA_DIR,
TOPICS_FILE, ensure_data_dirs(); rebase SETTINGS_FILE as derived path from
settings.data_dir (Phase 1 flat-file settings kept per plan decision)
- Prune backend/tests/conftest.py: remove isolated_data_dir autouse fixture
and sync TestClient client fixture; add SQLite type compatibility shim
(visit_INET/JSONB) so in-memory db_session can create tables with
PostgreSQL-specific column types; add live_services_available fixture
- Rewrite backend/tests/test_documents.py: delete all legacy sync tests,
remove all @pytest.mark.xfail markers; async-only document tests now
use async_client + storage service directly for topic wiring
- Rewrite backend/tests/test_health.py: delete legacy sync test_health(client);
remove @pytest.mark.xfail from test_health_checks_postgres_and_minio
- Port backend/tests/test_topics.py to async_client (sync client removed)
- Port backend/tests/test_settings.py to async_client with monkeypatch for
SETTINGS_FILE isolation (settings remain flat-file in Phase 1)
- Add @pytest_asyncio.fixture db_session: in-memory SQLite via aiosqlite,
expire_on_commit=False, skips gracefully (ImportError) before Plan 03
- Add @pytest_asyncio.fixture async_client: httpx.AsyncClient with
ASGITransport, overrides deps.db.get_db, skips before Plan 03
- Retain all legacy sync fixtures (isolated_data_dir, client, sample_txt,
sample_pdf) unchanged for backward compatibility through Plan 04