"""Lock the transport-agnostic core boundary. The core (tool registry, Gitea client, policy, audit, config, request context, tools) must import cleanly without dragging in the web stack. If a stray ``import fastapi`` creeps back into a core module, the local stdio package would gain a needless heavy dependency and the ``[server]`` extra split would leak. The check runs in a subprocess because, within the pytest process, FastAPI is already imported by the server tests — so ``'fastapi' in sys.modules`` would be true regardless. A clean interpreter is the only reliable probe. """ from __future__ import annotations import os import subprocess import sys from pathlib import Path _SRC = Path(__file__).resolve().parents[1] / "src" # Core modules that must stay free of the web stack. _CORE_MODULES = [ "aegis_gitea_mcp.registry", "aegis_gitea_mcp.gitea_client", "aegis_gitea_mcp.policy", "aegis_gitea_mcp.audit", "aegis_gitea_mcp.config", "aegis_gitea_mcp.request_context", "aegis_gitea_mcp.response_limits", "aegis_gitea_mcp.security", "aegis_gitea_mcp.cache", "aegis_gitea_mcp.logging_utils", "aegis_gitea_mcp.mcp_protocol", "aegis_gitea_mcp.errors", "aegis_gitea_mcp.tools.raw_tools", "aegis_gitea_mcp.tools.read_tools", "aegis_gitea_mcp.tools.write_tools", "aegis_gitea_mcp.tools.repository", "aegis_gitea_mcp.tools.arguments", ] def test_core_does_not_import_fastapi() -> None: """Importing the core in a clean interpreter must not import FastAPI.""" imports = "\n".join(f"import {module}" for module in _CORE_MODULES) program = ( f"import sys\n{imports}\n" "leaked = [m for m in ('fastapi', 'uvicorn', 'starlette') if m in sys.modules]\n" "assert not leaked, f'core leaked web stack: {leaked}'\n" "print('ok')\n" ) env = dict(os.environ) env["PYTHONPATH"] = str(_SRC) result = subprocess.run( [sys.executable, "-c", program], env=env, capture_output=True, text=True, ) detail = f"core import boundary violated.\nstdout: {result.stdout}\nstderr: {result.stderr}" assert result.returncode == 0, detail assert "ok" in result.stdout