# allow: no-sut-import — guardian; greps history_routes.py source to keep sensitive data out of logs """Tests for sensitive data logging changes in history_routes. Verifies that PR #1896 changes are in place: - logger.debug used instead of logger.info for research detail lookups - Request headers are not logged - Request URL is not logged - Full research query results are not logged """ from pathlib import Path # Resolve the source file path relative to this test file _ROUTES_FILE = ( Path(__file__).resolve().parents[2] / "src" / "local_deep_research" / "web" / "routes" / "history_routes.py" ) def _read_source() -> str: """Read the history_routes.py source file directly from disk.""" return _ROUTES_FILE.read_text(encoding="utf-8") class TestSensitiveDataLogging: """Verify that sensitive data is not exposed through logging.""" def test_uses_debug_not_info_for_details_route(self): """logger.info should not be used for the details route access log.""" source = _read_source() assert 'logger.info(f"Details route' not in source, ( "Details route log should use logger.debug, not logger.info" ) assert "logger.debug" in source, ( "history_routes should contain at least one logger.debug call" ) def test_no_request_headers_logging(self): """Request headers must not be logged as they may contain auth tokens.""" source = _read_source() assert "request.headers" not in source, ( "request.headers should not appear in history_routes.py" ) def test_no_request_url_logging(self): """Request URL must not be logged as it may contain sensitive params.""" source = _read_source() assert "request.url" not in source, ( "request.url should not appear in history_routes.py" ) def test_no_full_research_query_result_logging(self): """Full research query result objects should not be logged.""" source = _read_source() assert 'logger.info(f"Research query result' not in source, ( "Full research query result should not be logged via logger.info" ) def test_no_user_research_list_logging(self): """Full list of user research entries should not be logged.""" source = _read_source() assert 'logger.info(f"All research for user' not in source, ( "Full user research list should not be logged via logger.info" ) def test_research_count_uses_debug(self): """Research count log should use debug level.""" source = _read_source() assert "All research count" in source, ( "Should log research count (not full list)" ) assert 'logger.debug(f"All research count' in source, ( "Research count should be logged at debug level" ) def test_research_found_uses_debug_with_id_only(self): """Research found log should use debug and only include the ID.""" source = _read_source() assert 'logger.debug(f"Research found:' in source, ( "Research found log should use logger.debug" ) assert "research.id if research else None" in source, ( "Should log only research.id, not the full object" )