forked from cardosofelipe/fast-next-template
fix(mcp-kb): add input validation, path security, and health checks
Security fixes from deep review: - Add input validation patterns for project_id, agent_id, collection - Add path traversal protection for source_path (reject .., null bytes) - Add error codes (INTERNAL_ERROR) to generic exception handlers - Handle FieldInfo objects in validation for test robustness Performance fixes: - Enable concurrent hybrid search with asyncio.gather Health endpoint improvements: - Check all dependencies (database, Redis, LLM Gateway) - Return degraded/unhealthy status based on dependency health - Updated tests for new health check response structure All 139 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,10 +13,10 @@ class TestHealthCheck:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_health_check_healthy(self):
|
||||
"""Test health check when healthy."""
|
||||
"""Test health check when all dependencies are connected."""
|
||||
import server
|
||||
|
||||
# Create a proper async context manager mock
|
||||
# Create a proper async context manager mock for database
|
||||
mock_conn = AsyncMock()
|
||||
mock_conn.fetchval = AsyncMock(return_value=1)
|
||||
|
||||
@@ -29,24 +29,75 @@ class TestHealthCheck:
|
||||
mock_cm.__aexit__.return_value = None
|
||||
mock_db.acquire.return_value = mock_cm
|
||||
|
||||
# Mock Redis
|
||||
mock_redis = AsyncMock()
|
||||
mock_redis.ping = AsyncMock(return_value=True)
|
||||
|
||||
# Mock HTTP client for LLM Gateway
|
||||
mock_http_response = AsyncMock()
|
||||
mock_http_response.status_code = 200
|
||||
mock_http_client = AsyncMock()
|
||||
mock_http_client.get = AsyncMock(return_value=mock_http_response)
|
||||
|
||||
# Mock embeddings with Redis and HTTP client
|
||||
mock_embeddings = MagicMock()
|
||||
mock_embeddings._redis = mock_redis
|
||||
mock_embeddings._http_client = mock_http_client
|
||||
|
||||
server._database = mock_db
|
||||
server._embeddings = mock_embeddings
|
||||
|
||||
result = await server.health_check()
|
||||
|
||||
assert result["status"] == "healthy"
|
||||
assert result["service"] == "knowledge-base"
|
||||
assert result["database"] == "connected"
|
||||
assert result["dependencies"]["database"] == "connected"
|
||||
assert result["dependencies"]["redis"] == "connected"
|
||||
assert result["dependencies"]["llm_gateway"] == "connected"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_health_check_no_database(self):
|
||||
"""Test health check without database."""
|
||||
"""Test health check without database - should be unhealthy."""
|
||||
import server
|
||||
|
||||
server._database = None
|
||||
server._embeddings = None
|
||||
|
||||
result = await server.health_check()
|
||||
|
||||
assert result["database"] == "not initialized"
|
||||
assert result["status"] == "unhealthy"
|
||||
assert result["dependencies"]["database"] == "not initialized"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_health_check_degraded(self):
|
||||
"""Test health check with database but no Redis - should be degraded."""
|
||||
import server
|
||||
|
||||
# Create a proper async context manager mock for database
|
||||
mock_conn = AsyncMock()
|
||||
mock_conn.fetchval = AsyncMock(return_value=1)
|
||||
|
||||
mock_db = MagicMock()
|
||||
mock_db._pool = MagicMock()
|
||||
|
||||
mock_cm = AsyncMock()
|
||||
mock_cm.__aenter__.return_value = mock_conn
|
||||
mock_cm.__aexit__.return_value = None
|
||||
mock_db.acquire.return_value = mock_cm
|
||||
|
||||
# Mock embeddings without Redis
|
||||
mock_embeddings = MagicMock()
|
||||
mock_embeddings._redis = None
|
||||
mock_embeddings._http_client = None
|
||||
|
||||
server._database = mock_db
|
||||
server._embeddings = mock_embeddings
|
||||
|
||||
result = await server.health_check()
|
||||
|
||||
assert result["status"] == "degraded"
|
||||
assert result["dependencies"]["database"] == "connected"
|
||||
assert result["dependencies"]["redis"] == "not initialized"
|
||||
|
||||
|
||||
class TestSearchKnowledgeTool:
|
||||
|
||||
Reference in New Issue
Block a user