"""Deployment flags: NAVI_WEBCLIENT_ENABLED gating and navi-server settings.
The webclient gating in navi/main.py runs at import time, so these tests
launch a subprocess with the flag in the environment and inspect the
registered routes — monkeypatching settings in-process would not re-gate.
"""
from __future__ import annotations
import json
import os
import subprocess
import sys
from navi.config import Settings
ROUTES_SCRIPT = """
import json
import navi.main as m
print(json.dumps(sorted({r.path for r in m.app.routes})))
"""
def _app_routes(extra_env: dict[str, str]) -> list[str]:
env = {k: v for k, v in os.environ.items() if k != "NAVI_WEBCLIENT_ENABLED"}
env.update(extra_env)
out = subprocess.run(
[sys.executable, "-c", ROUTES_SCRIPT],
capture_output=True, text=True, env=env, cwd=os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
timeout=120,
)
assert out.returncode == 0, out.stderr[-2000:]
# Import-time logging (profile loading etc.) shares stdout — the JSON
# payload is the last line printed by the script itself.
return json.loads(out.stdout.strip().splitlines()[-1])
def test_settings_defaults():
s = Settings(database_url="postgresql://x")
assert s.navi_webclient_enabled is True
assert s.navi_host == "127.0.0.1"
assert s.navi_port == 8000
def test_webclient_enabled_default_registers_ui_routes():
routes = _app_routes({"NAVI_WEBCLIENT_ENABLED": "true"})
# Web panel, static mounts and the debug tools are all present.
assert "/" in routes
assert "/admin" in routes
assert "/health" in routes
assert "/ws/sessions/{session_id}" in routes
def test_webclient_disabled_drops_ui_routes_only():
routes = _app_routes({"NAVI_WEBCLIENT_ENABLED": "false"})
# Everything web-facing is gone …
assert "/" not in routes
assert "/admin" not in routes
assert "/debug" not in routes
assert not any(r.startswith(("/assets", "/images", "/content")) for r in routes)
# … but the API the terminal client uses is fully intact.
assert "/health" in routes
assert "/sessions" in routes
assert "/ws/sessions/{session_id}" in routes
assert "/api/sessions/{session_id}/files/{filename}" in routes
# The /admin/* JSON API (profile/memory/sessions management) stays —
# only the HTML panel is web UI. require_admin still gates it.
assert "/admin/profiles" in routes