Conversation
Remove @public_access decorator from analyze_repo and switch_commit endpoints so that all three mutating endpoints (analyze_folder, analyze_repo, switch_commit) require a valid token even when CODE_GRAPH_PUBLIC=1. Read-only endpoints remain publicly accessible. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace Flask with FastAPI + Uvicorn in pyproject.toml - Rewrite api/index.py: Pydantic request models, Depends() auth, FileResponse SPA serving, JSONResponse error responses - Auth decorators become dependency injection: public_or_auth (public endpoints), token_required (mutating endpoints) - Rewrite tests/index.py: FastAPI app factory, explicit imports - Update 7 endpoint test files: TestClient, .json() method, /api/ URL prefix - Update Makefile, start.sh, CI workflow: flask run -> uvicorn api.index:app - Endpoints remain synchronous (FastAPI auto-threads blocking calls) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- serve_spa: resolve path and verify it stays within STATIC_DIR - chat endpoint: log exception server-side, return generic error to client - Apply same fixes to test app Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Match production auth by using token_required (not public_access) for analyze_repo and switch_commit in the test app. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…gging - serve_spa: replace str().startswith() with Path.is_relative_to() to prevent prefix-collision path traversal (e.g. dist_evil matching dist) - analyze_folder: add ALLOWED_ANALYSIS_DIR containment check to prevent traversal outside allowed base directory - Upgrade logging.error to logging.exception in graph_entities and chat handlers for full traceback capture - Remove unused public_access function from tests/index.py - Mirror analyze_folder path validation in test app - Add auth tests for repo_info (public_or_auth) and list_repos endpoints - Tighten test_find_paths 422 assertions to verify field-specific validation - Parse response.json() once per response in test_list_commits Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use 'import api.index' consistently instead of mixing with 'from api.index import'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- test_list_repos_with_auth: monkeypatch get_repos for deterministic result, assert 200 status and exact payload instead of just != 401 - test_repo_info.py: remove trailing whitespace on status assignments - test_list_repos.py: remove trailing whitespace on status assignment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migrate backend from Flask to FastAPI
Convert all 12 endpoints to async def using native async drivers (falkordb.asyncio, redis.asyncio) for read endpoints, and run_in_executor for CPU-bound/sync-only operations (source analysis, git clone, LLM chat). Add AsyncGraphQuery, AsyncGitGraph wrapper classes and async standalone functions while keeping all sync code intact for the analysis pipeline. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can generate a title for your PR based on the changes.Add |
There was a problem hiding this comment.
Pull request overview
This PR promotes the staging changes that migrate the Python backend from Flask to FastAPI/Uvicorn, updating dependency management, runtime scripts, CI, and endpoint tests to match the new framework.
Changes:
- Replace Flask app with a FastAPI app (
api.index:app) and add SPA static-file serving via FastAPI. - Update run/start scripts and CI workflow to launch the server with Uvicorn.
- Update endpoint tests to use Starlette/FastAPI
TestClientand new/api/*paths; add auth/public-access tests.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
api/index.py |
Reimplements the backend API in FastAPI, adds auth dependencies and SPA static serving. |
pyproject.toml |
Swaps Flask for FastAPI + uvicorn[standard]; adds httpx to test extras. |
uv.lock |
Lockfile update reflecting FastAPI/Uvicorn dependency graph and removal of Flask deps. |
start.sh |
Starts the backend via uvicorn api.index:app instead of Flask. |
Makefile |
Updates dev/prod run commands to Uvicorn. |
.github/workflows/playwright.yml |
Starts/stops Uvicorn in Playwright CI job. |
tests/index.py |
Adds a separate FastAPI app factory used by some endpoint tests. |
tests/endpoints/test_repo_info.py |
Moves to TestClient(api.index.app) and adds auth/public-access tests. |
tests/endpoints/test_list_repos.py |
Moves to TestClient, updates paths, and adds auth tests. |
tests/endpoints/test_list_commits.py |
Moves to TestClient and updates endpoint path. |
tests/endpoints/test_graph_entities.py |
Moves to TestClient and updates endpoint path. |
tests/endpoints/test_get_neighbors.py |
Moves to POST + TestClient and updates endpoint path/payload. |
tests/endpoints/test_find_paths.py |
Moves to TestClient, updates paths, and validates Pydantic 422 behavior. |
tests/endpoints/test_auto_complete.py |
Moves to TestClient and updates endpoint path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_repo_info_public_access(monkeypatch): | ||
| """Public access is granted when CODE_GRAPH_PUBLIC=1.""" | ||
| monkeypatch.setenv("CODE_GRAPH_PUBLIC", "1") | ||
| client = TestClient(api.index.app, raise_server_exceptions=False) | ||
| response = client.post("/api/repo_info", json={"repo": "nonexistent"}) | ||
| # Auth passed (not 401); endpoint may error without a database backend | ||
| assert response.status_code != 401 |
| @app.get('/api/graph_entities') | ||
| def graph_entities(repo: str = Query(None), _=Depends(public_or_auth)): | ||
| """Fetch sub-graph entities from a given repository.""" | ||
|
|
||
| # Validate 'repo' parameter | ||
| if not repo: | ||
| logging.error("Repository name is missing in the request.") | ||
| return jsonify({"status": "Repository name is required."}), 400 | ||
|
|
||
| # Validate 'node_ids' parameter | ||
| if not node_ids: | ||
| logging.error("Node IDs is missing in the request.") | ||
| return jsonify({"status": "Node IDs is required."}), 400 | ||
| logging.error("Missing 'repo' parameter in request.") | ||
| return JSONResponse({"status": "Missing 'repo' parameter"}, status_code=400) |
| # Validate 'repo' parameter | ||
| @app.get('/api/graph_entities') | ||
| def graph_entities(repo: str = Query(None), _=Depends(token_required)): | ||
| if not repo: |
| import api.index | ||
| from pathlib import Path | ||
| from tests.index import create_app | ||
| from api import Project | ||
| from starlette.testclient import TestClient |
- Replace deprecated asyncio.get_event_loop() with get_running_loop() in all coroutines (api/index.py, api/llm.py, tests/index.py) - Remove unused `from functools import partial` import (api/index.py) - Fix inconsistent Cypher keyword casing: "With e" -> "WITH e" (api/git_utils/git_graph.py) - Rename ambiguous parameter `l` to `limit` in AsyncGraphQuery.get_sub_graph (api/graph.py) - Add strict=True to zip(nodes, edges) in AsyncGraphQuery.find_paths to catch length mismatches early (api/graph.py) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused sync imports from api/index.py (GitGraph, get_repos, graph_exists, get_repo_info, prefix_search) and tests/index.py (get_repos, graph_exists, get_repo_info, prefix_search) - Add tests/test_async_graph.py with 7 unit tests covering async_graph_exists, async_get_repos, and AsyncGraphQuery (stats, close, error cleanup) using mocked FalkorDB client Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Matches the async find_paths which already uses strict=True, so both versions raise immediately on a nodes/edges length mismatch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ate double connections - Remove strict=True from zip(nodes, edges) in find_paths (both sync and async) — nodes intentionally has one more element than edges - Revert serve_spa to sync def so FastAPI offloads filesystem I/O to thread pool instead of blocking the event loop - Add graph_exists() method to AsyncGraphQuery to reuse the connection instead of opening a separate one via async_graph_exists() - Update all endpoints in api/index.py and tests/index.py to use g.graph_exists() on the query instance - Fix missing trailing newline in api/llm.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion - Replace ineffective 'if stats is None' guard in repo_info with g.graph_exists() check in both api/index.py and tests/index.py - Add missing mock_db.aclose assertion in test_async_get_repos_empty Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migrate FastAPI endpoints from sync to async
Update the README, environment template, and reference docs so they match the current FastAPI/Uvicorn runtime, /api endpoints, supported analyzers, and auth/env behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
docs: sync docs with current FastAPI implementation
Staging-->Main