"""Regression coverage for the Gateway-owned LangGraph API runtime.""" from __future__ import annotations import re from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] def _read(path: str) -> str: return (REPO_ROOT / path).read_text(encoding="utf-8") def test_root_makefile_no_longer_exposes_transition_gateway_targets(): makefile = _read("Makefile") assert "dev-pro" not in makefile assert "start-pro" not in makefile assert "dev-daemon-pro" not in makefile assert "start-daemon-pro" not in makefile assert "docker-start-pro" not in makefile assert "up-pro" not in makefile assert not re.search(r"serve\.sh .*--gateway", makefile) assert "docker.sh start --gateway" not in makefile assert "deploy.sh --gateway" not in makefile def test_service_launchers_always_use_gateway_runtime(): operational_files = { "scripts/serve.sh": _read("scripts/serve.sh"), "scripts/docker.sh": _read("scripts/docker.sh"), "scripts/deploy.sh": _read("scripts/deploy.sh"), "docker/docker-compose-dev.yaml": _read("docker/docker-compose-dev.yaml"), "docker/docker-compose.yaml": _read("docker/docker-compose.yaml"), } for path, content in operational_files.items(): assert "start --gateway" not in content, path assert "deploy.sh --gateway" not in content, path assert "langgraph dev" not in content, path assert "LANGGRAPH_UPSTREAM" not in content, path assert "LANGGRAPH_REWRITE" not in content, path def test_local_dev_gateway_reload_excludes_runtime_state_with_absolute_dirs(): serve_sh = _read("scripts/serve.sh") assert 'export DEER_FLOW_PROJECT_ROOT="$REPO_ROOT"' in serve_sh assert 'BACKEND_RUNTIME_HOME="$REPO_ROOT/backend/.deer-flow"' in serve_sh assert 'export DEER_FLOW_HOME="$BACKEND_RUNTIME_HOME"' in serve_sh # Every absolute reload-exclude must be pre-created, including backend/sandbox # (#3459 / #3454) — see test_uvicorn_reload_exclude.py for the mechanism. assert 'mkdir -p "$DEER_FLOW_HOME" "$BACKEND_RUNTIME_HOME" "$REPO_ROOT/backend/sandbox"' in serve_sh assert "--reload-exclude='$DEER_FLOW_HOME'" in serve_sh assert "--reload-exclude='$BACKEND_RUNTIME_HOME'" in serve_sh assert "--reload-exclude='sandbox/'" not in serve_sh assert "--reload-exclude='.deer-flow/'" not in serve_sh def test_backend_container_only_exposes_gateway_port(): dockerfile = _read("backend/Dockerfile") assert not re.search(r"^EXPOSE\s+.*\b2024\b", dockerfile, re.M) assert "langgraph: 2024" not in dockerfile assert re.search(r"^EXPOSE\s+8001\b", dockerfile, re.M) def test_root_makefile_clean_does_not_reference_langgraph_server_cache(): makefile = _read("Makefile") assert ".langgraph_api" not in makefile def test_nginx_routes_official_langgraph_prefix_to_gateway_api(): for path in ("docker/nginx/nginx.local.conf", "docker/nginx/nginx.conf"): content = _read(path) assert "/api/langgraph-compat" not in content assert "proxy_pass http://langgraph" not in content assert "rewrite ^/api/langgraph/(.*) /api/$1 break;" in content assert "proxy_pass http://gateway" in content or "proxy_pass http://$gateway_upstream" in content def test_nginx_defers_cors_to_gateway_allowlist(): for path in ("docker/nginx/nginx.local.conf", "docker/nginx/nginx.conf"): content = _read(path) assert "Access-Control-Allow-Origin" not in content assert "Access-Control-Allow-Methods" not in content assert "Access-Control-Allow-Headers" not in content assert "Access-Control-Allow-Credentials" not in content assert "proxy_hide_header 'Access-Control-Allow-" not in content assert "if ($request_method = 'OPTIONS')" not in content def test_gateway_cors_configuration_uses_gateway_allowlist(): gateway_config = _read("backend/app/gateway/config.py") gateway_app = _read("backend/app/gateway/app.py") csrf_middleware = _read("backend/app/gateway/csrf_middleware.py") assert not re.search(r"(?