From ff22f18486b4ce180635324f8a60f457a06c62c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:46:10 +0000 Subject: [PATCH 1/3] Initial plan From 55b353f64c29dc9962a86627ab67e7225472443e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:52:41 +0000 Subject: [PATCH 2/3] Fix: Skip RAG discovery when feature_rag_enabled is false Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com> --- backend/routes/config_routes.py | 74 ++++++++++++----------- backend/tests/test_routes_config_smoke.py | 44 ++++++++++++++ 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/backend/routes/config_routes.py b/backend/routes/config_routes.py index ecabd6c..c8bf50d 100644 --- a/backend/routes/config_routes.py +++ b/backend/routes/config_routes.py @@ -74,42 +74,44 @@ async def get_config( # Get RAG data sources for the user (feature-gated MCP-backed discovery) rag_data_sources = [] rag_servers = [] - try: - if app_settings.feature_rag_mcp_enabled: - rag_mcp = app_factory.get_rag_mcp_service() - rag_data_sources = await rag_mcp.discover_data_sources( - current_user, user_compliance_level=compliance_level - ) - rag_servers = await rag_mcp.discover_servers( - current_user, user_compliance_level=compliance_level - ) - else: - rag_client = app_factory.get_rag_client() - # rag_client.discover_data_sources now returns List[DataSource] objects - data_source_objects = await rag_client.discover_data_sources(current_user) - # Convert to list of names (strings) for the 'data_sources' field (backward compatibility) - rag_data_sources = [ds.name for ds in data_source_objects] - # Populate rag_servers with the mock data in the expected format for the UI - rag_servers = [ - { - "server": "rag_mock", - "displayName": "RAG Mock Data", - "icon": "database", - "complianceLevel": "Public", # Default compliance for the mock server itself - "sources": [ - { - "id": ds.name, - "name": ds.name, - "authRequired": True, - "selected": False, - "complianceLevel": ds.compliance_level, - } - for ds in data_source_objects - ], - } - ] - except Exception as e: - logger.warning(f"Error resolving RAG data sources: {e}") + # Only attempt RAG discovery if RAG feature is enabled + if app_settings.feature_rag_enabled: + try: + if app_settings.feature_rag_mcp_enabled: + rag_mcp = app_factory.get_rag_mcp_service() + rag_data_sources = await rag_mcp.discover_data_sources( + current_user, user_compliance_level=compliance_level + ) + rag_servers = await rag_mcp.discover_servers( + current_user, user_compliance_level=compliance_level + ) + else: + rag_client = app_factory.get_rag_client() + # rag_client.discover_data_sources now returns List[DataSource] objects + data_source_objects = await rag_client.discover_data_sources(current_user) + # Convert to list of names (strings) for the 'data_sources' field (backward compatibility) + rag_data_sources = [ds.name for ds in data_source_objects] + # Populate rag_servers with the mock data in the expected format for the UI + rag_servers = [ + { + "server": "rag_mock", + "displayName": "RAG Mock Data", + "icon": "database", + "complianceLevel": "Public", # Default compliance for the mock server itself + "sources": [ + { + "id": ds.name, + "name": ds.name, + "authRequired": True, + "selected": False, + "complianceLevel": ds.compliance_level, + } + for ds in data_source_objects + ], + } + ] + except Exception as e: + logger.warning(f"Error resolving RAG data sources: {e}") # Check if tools are enabled tools_info = [] diff --git a/backend/tests/test_routes_config_smoke.py b/backend/tests/test_routes_config_smoke.py index b678ff8..ccf2533 100644 --- a/backend/tests/test_routes_config_smoke.py +++ b/backend/tests/test_routes_config_smoke.py @@ -1,3 +1,5 @@ +from unittest.mock import patch, MagicMock, AsyncMock + from starlette.testclient import TestClient from main import app @@ -14,3 +16,45 @@ def test_config_endpoint_smoke(monkeypatch): assert "tools" in data assert "prompts" in data assert "data_sources" in data + + +def test_rag_discovery_skipped_when_feature_disabled(monkeypatch): + """Verify RAG discovery is not attempted when feature_rag_enabled is False.""" + # Create mock rag_client to track if discover_data_sources is called + mock_rag_client = MagicMock() + mock_rag_client.discover_data_sources = AsyncMock(return_value=[]) + + # Create mock rag_mcp_service + mock_rag_mcp = MagicMock() + mock_rag_mcp.discover_data_sources = AsyncMock(return_value=[]) + mock_rag_mcp.discover_servers = AsyncMock(return_value=[]) + + from infrastructure.app_factory import app_factory + + # Patch the app_factory methods + with patch.object(app_factory, 'get_rag_client', return_value=mock_rag_client): + with patch.object(app_factory, 'get_rag_mcp_service', return_value=mock_rag_mcp): + # Ensure RAG feature is disabled + config_manager = app_factory.get_config_manager() + original_setting = config_manager.app_settings.feature_rag_enabled + config_manager.app_settings.feature_rag_enabled = False + + try: + client = TestClient(app) + resp = client.get("/api/config", headers={"X-User-Email": "test@test.com"}) + assert resp.status_code == 200 + + # Verify RAG discovery was NOT called when feature is disabled + mock_rag_client.discover_data_sources.assert_not_called() + mock_rag_mcp.discover_data_sources.assert_not_called() + mock_rag_mcp.discover_servers.assert_not_called() + + # Verify response still has data_sources field (just empty) + data = resp.json() + assert "data_sources" in data + assert data["data_sources"] == [] + assert "rag_servers" in data + assert data["rag_servers"] == [] + finally: + # Restore original setting + config_manager.app_settings.feature_rag_enabled = original_setting From 1da42298198116f5cdf96b58cda53ba7ebd0b555 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:54:42 +0000 Subject: [PATCH 3/3] Address code review: Move import to top of file Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com> --- backend/tests/test_routes_config_smoke.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/tests/test_routes_config_smoke.py b/backend/tests/test_routes_config_smoke.py index ccf2533..7be7314 100644 --- a/backend/tests/test_routes_config_smoke.py +++ b/backend/tests/test_routes_config_smoke.py @@ -2,6 +2,7 @@ from starlette.testclient import TestClient +from infrastructure.app_factory import app_factory from main import app @@ -29,8 +30,6 @@ def test_rag_discovery_skipped_when_feature_disabled(monkeypatch): mock_rag_mcp.discover_data_sources = AsyncMock(return_value=[]) mock_rag_mcp.discover_servers = AsyncMock(return_value=[]) - from infrastructure.app_factory import app_factory - # Patch the app_factory methods with patch.object(app_factory, 'get_rag_client', return_value=mock_rag_client): with patch.object(app_factory, 'get_rag_mcp_service', return_value=mock_rag_mcp):