fix(05-12): close 3 UAT gaps — OAuth 400 preflight, 502 cloud fallback, upload hint

- oauth_initiate: pre-flight check returns 400 with env-var hint when
  GOOGLE_CLIENT_ID/SECRET or ONEDRIVE_CLIENT_ID/SECRET are not configured,
  preventing opaque MSAL/OAuth library 500 errors on misconfigured servers
- stream_document_content: broad except-clause catches non-CloudConnectionError
  exceptions and returns 502 with user-friendly message (was raw 500)
- docker-compose.yml: add volumes: - ./backend:/app to celery-worker so code
  changes are picked up by docker compose restart without a rebuild
- CloudStorageView: upload hint paragraph directs users to navigate into a
  cloud folder; no DropZone added (no folder context at overview level)
- 3 new backend tests pass; 2 existing tests patched with credential monkeypatch;
  full suite: 293 passed, 0 new failures, 1 pre-existing (test_extract_docx)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-05-30 17:55:08 +02:00
parent f4f340545b
commit 10175ee4b5
8 changed files with 479 additions and 1 deletions
+65 -1
View File
@@ -184,9 +184,14 @@ async def test_connect_google_drive(async_client, db_session, monkeypatch):
so the frontend can inject the Bearer Authorization header before navigating.
"""
from main import app
from config import settings
auth = await _create_user_and_token(db_session, role="user")
# Ensure pre-flight config check passes (plan 05-12)
monkeypatch.setattr(settings, "google_client_id", "test_google_client_id")
monkeypatch.setattr(settings, "google_client_secret", "test_google_client_secret")
# Mock Redis to avoid needing a real Redis connection
fake_redis = FakeRedis()
app.state.redis = fake_redis
@@ -728,7 +733,7 @@ async def test_reanalyze_cloud_document_routes_to_cloud_backend():
# ── Plan 10 tests: OAuth initiate returns JSON URL ────────────────────────────
async def test_oauth_initiate_returns_json_url(async_client, db_session):
async def test_oauth_initiate_returns_json_url(async_client, db_session, monkeypatch):
"""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
@@ -736,9 +741,14 @@ async def test_oauth_initiate_returns_json_url(async_client, db_session):
header before navigating (plan 05-10).
"""
from main import app
from config import settings
auth = await _create_user_and_token(db_session, role="user")
# Ensure pre-flight config check passes (plan 05-12)
monkeypatch.setattr(settings, "google_client_id", "test_google_client_id")
monkeypatch.setattr(settings, "google_client_secret", "test_google_client_secret")
# Set up fake Redis so state token storage works
fake_redis = FakeRedis()
app.state.redis = fake_redis
@@ -771,6 +781,60 @@ async def test_oauth_initiate_returns_json_url(async_client, db_session):
app.state.redis = None
async def test_oauth_initiate_google_drive_not_configured(async_client, db_session, monkeypatch):
"""GET /api/cloud/oauth/initiate/google_drive returns 400 with env-var hint when creds missing.
Pre-flight check (plan 05-12): empty GOOGLE_CLIENT_ID/SECRET → 400 before touching OAuth libs.
"""
from main import app
from config import settings
auth = await _create_user_and_token(db_session, role="user")
fake_redis = FakeRedis()
app.state.redis = fake_redis
monkeypatch.setattr(settings, "google_client_id", "")
monkeypatch.setattr(settings, "google_client_secret", "")
resp = await async_client.get(
"/api/cloud/oauth/initiate/google_drive",
headers=auth["headers"],
follow_redirects=False,
)
app.state.redis = None
assert resp.status_code == 400, f"Expected 400, got {resp.status_code}: {resp.text}"
assert "GOOGLE_CLIENT_ID" in resp.json()["detail"], f"Unexpected detail: {resp.json()['detail']}"
async def test_oauth_initiate_onedrive_not_configured(async_client, db_session, monkeypatch):
"""GET /api/cloud/oauth/initiate/onedrive returns 400 with env-var hint when creds missing.
Pre-flight check (plan 05-12): empty ONEDRIVE_CLIENT_ID → 400 before touching MSAL.
"""
from main import app
from config import settings
auth = await _create_user_and_token(db_session, role="user")
fake_redis = FakeRedis()
app.state.redis = fake_redis
monkeypatch.setattr(settings, "onedrive_client_id", "")
monkeypatch.setattr(settings, "onedrive_client_secret", "")
resp = await async_client.get(
"/api/cloud/oauth/initiate/onedrive",
headers=auth["headers"],
follow_redirects=False,
)
app.state.redis = None
assert resp.status_code == 400, f"Expected 400, got {resp.status_code}: {resp.text}"
assert "ONEDRIVE_CLIENT_ID" in resp.json()["detail"], f"Unexpected detail: {resp.json()['detail']}"
async def test_oauth_initiate_requires_auth(async_client, db_session):
"""GET /api/cloud/oauth/initiate/google_drive without token returns 401 or 403.