83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
import asyncio
|
|
from pathlib import Path
|
|
|
|
import httpx
|
|
import pytest
|
|
from _pytest.monkeypatch import MonkeyPatch
|
|
from fastapi.routing import APIRoute
|
|
|
|
from gewu.bootstrap.app import create_app, create_local_app
|
|
|
|
|
|
def test_health_is_available_without_exposing_mutation_routes() -> None:
|
|
async def request_health() -> httpx.Response:
|
|
async with httpx.AsyncClient(
|
|
transport=httpx.ASGITransport(app=create_app()),
|
|
base_url="http://gewu.test",
|
|
) as client:
|
|
return await client.get("/health")
|
|
|
|
response = asyncio.run(request_health())
|
|
assert response.status_code == 200
|
|
assert response.json() == {"status": "ok", "service": "gewu"}
|
|
routes = {
|
|
f"{method} {route.path}"
|
|
for route in create_app().routes
|
|
if isinstance(route, APIRoute)
|
|
for method in route.methods or ()
|
|
}
|
|
assert routes == {"GET /health"}
|
|
|
|
|
|
def test_local_factory_composes_private_persistent_read_service(
|
|
monkeypatch: MonkeyPatch, tmp_path: Path
|
|
) -> None:
|
|
data_root = tmp_path / "private-gewu"
|
|
monkeypatch.setenv("GEWU_DATA_ROOT", str(data_root))
|
|
app = create_local_app()
|
|
route_paths = {route.path for route in app.routes if isinstance(route, APIRoute)}
|
|
assert route_paths == {
|
|
"/health",
|
|
"/v1/diagnostics",
|
|
"/v1/admin/projects",
|
|
"/v1/admin/credentials",
|
|
"/v1/admin/credentials/{credential_id}",
|
|
"/v1/admin/events",
|
|
"/v1/admin/users",
|
|
"/v1/admin/users/{username}",
|
|
"/v1/users/session",
|
|
"/v1/me",
|
|
"/v1/me/password",
|
|
"/v1/me/agent-credentials",
|
|
"/v1/me/agent-credentials/{credential_id}",
|
|
"/v1/admin/projects/{project_id}/archive",
|
|
"/v1/projects/{project_id}/nodes/{node_id}",
|
|
"/v1/projects/{project_id}/nodes/{node_id}/history",
|
|
"/v1/projects/{project_id}/sources/{revision_id}",
|
|
"/v1/projects/{project_id}/sources/{revision_id}/artifact",
|
|
"/v1/projects/{project_id}/sources/{revision_id}/extractions/{extraction_id}/blocks/{block_id}",
|
|
"/v1/neighbors",
|
|
"/v1/projects",
|
|
"/v1/search",
|
|
"/v1/sources",
|
|
"/v1/session",
|
|
"/auth/owner-session",
|
|
}
|
|
assert (data_root / "knowledge.git" / "HEAD").is_file()
|
|
assert (data_root / "identity.sqlite3").is_file()
|
|
assert (data_root / "search.sqlite3").is_file()
|
|
assert (data_root / "search.sqlite3").stat().st_mode & 0o077 == 0
|
|
assert (data_root.stat().st_mode & 0o777) == 0o700
|
|
|
|
|
|
def test_local_factory_rejects_symlinked_data_root(
|
|
monkeypatch: MonkeyPatch, tmp_path: Path
|
|
) -> None:
|
|
target = tmp_path / "real-root"
|
|
target.mkdir()
|
|
link = tmp_path / "linked-root"
|
|
link.symlink_to(target, target_is_directory=True)
|
|
monkeypatch.setenv("GEWU_DATA_ROOT", str(link))
|
|
with pytest.raises(ValueError, match="symbolic links"):
|
|
create_local_app()
|