From 9b6d3f91d4577da30a0797ccab6725366cf9328c Mon Sep 17 00:00:00 2001 From: curo1305 Date: Sat, 30 May 2026 11:23:38 +0200 Subject: [PATCH] test(05-10): add failing tests for OAuth initiate JSON URL return --- backend/tests/test_cloud.py | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/backend/tests/test_cloud.py b/backend/tests/test_cloud.py index 6d79b7b..2f32416 100644 --- a/backend/tests/test_cloud.py +++ b/backend/tests/test_cloud.py @@ -711,3 +711,63 @@ async def test_reanalyze_cloud_document_routes_to_cloud_backend(): # Result must reflect successful classification, not a MinIO error assert result.get("status") in ("classified", "classification_failed"), \ f"Expected classified/classification_failed, got: {result}" + + +# ── Plan 10 tests: OAuth initiate returns JSON URL ──────────────────────────── + + +async def test_oauth_initiate_returns_json_url(async_client, db_session): + """GET /api/cloud/oauth/initiate/google_drive returns 200 JSON {url} (not 302). + + Verifies the fix for CLOUD-01 / T-05-10-01: authenticated users receive + the OAuth authorization URL as JSON so the frontend can inject the Bearer + header before navigating (plan 05-10). + """ + from main import app + + auth = await _create_user_and_token(db_session, role="user") + + # Set up fake Redis so state token storage works + fake_redis = FakeRedis() + app.state.redis = fake_redis + + # Mock google_auth_oauthlib.flow.Flow so no real Google credentials are needed + mock_flow = MagicMock() + mock_flow.authorization_url.return_value = ( + "https://accounts.google.com/test?scope=drive&state=abc", + "abc", + ) + + with patch("google_auth_oauthlib.flow.Flow.from_client_config", return_value=mock_flow): + resp = await async_client.get( + "/api/cloud/oauth/initiate/google_drive", + headers=auth["headers"], + follow_redirects=False, + ) + + assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text}" + data = resp.json() + assert "url" in data, f"Response JSON missing 'url' key: {data}" + assert data["url"].startswith("https://accounts.google.com/"), \ + f"OAuth URL does not start with Google domain: {data['url']}" + + # Verify that OAuth state was stored in Redis + stored_keys = list(fake_redis._store.keys()) + assert any(k.startswith("oauth_state:") for k in stored_keys), \ + f"No oauth_state key found in Redis store: {stored_keys}" + + app.state.redis = None + + +async def test_oauth_initiate_requires_auth(async_client, db_session): + """GET /api/cloud/oauth/initiate/google_drive without token returns 401 or 403. + + Security invariant: get_regular_user dependency blocks unauthenticated requests + (T-05-10-01 — authentication enforced on oauth_initiate endpoint). + """ + resp = await async_client.get( + "/api/cloud/oauth/initiate/google_drive", + follow_redirects=False, + ) + assert resp.status_code in (401, 403), \ + f"Expected 401 or 403 for unauthenticated request, got {resp.status_code}"