Files
VoiceStudio/tests/test_backend_marker_header_1385.py
T
Palash Debnath e953af3730 fix(client): a foreign 404 page is a routing problem, not a backend error (#1386)
A rehosted UI whose API requests land on its own static host (or a reverse proxy with no API route) got that host's 404 page back, and we echoed it verbatim — the reporter saw 'NOT_FOUND bom1::...' and had no way to know their requests were reaching the wrong server.

The backend now stamps x-omnivoice-backend on every response, exposed through CORS, so the client can tell 'the backend answered 404' from 'something else answered 404' without guessing at body shape. A 404 in any other voice is reported as a routing problem, naming the URL that answered and where to fix it. The message goes through the same i18n helper as the other backend-diagnosis copy, in all 21 locales.
2026-08-06 15:13:08 +05:30

97 lines
3.6 KiB
Python

"""Every response says "an OmniVoice backend answered this" (#1385).
A rehosted UI whose API requests land on a static host or a reverse proxy with
no API route gets that host's own 404 page. The frontend used to echo it
("NOT_FOUND bom1::…"), sending users to chase a page that never existed. It now
says the request reached the wrong host — but only if it can TELL, and body
shape alone cannot tell: a proxy can answer with JSON too.
Hence the marker header. Its presence is authoritative; its absence is what
lets the client conclude the responder is not this backend. Two properties
matter and both are pinned here: it is on *every* response (including the auth
gates' rejections, which are generated by middleware rather than routes), and
it is readable cross-origin (otherwise the one deployment that needs it — a
browser UI on another origin — cannot see it).
"""
import os
import sys
import pytest
from fastapi.testclient import TestClient
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "backend"))
MARKER = "x-omnivoice-backend"
@pytest.fixture()
def client(monkeypatch, tmp_path):
monkeypatch.setenv("OMNIVOICE_DATA_DIR", str(tmp_path))
import main
return TestClient(main.app), main
def test_a_normal_response_carries_the_marker(client):
c, _ = client
res = c.get("/health")
assert res.headers.get(MARKER), "no marker on a plain 200"
def test_an_unrouted_path_carries_the_marker(client):
# The exact case that matters: a 404. If OUR 404 were unmarked, the client
# could not tell it from a foreign server's 404 and would tell the user
# their routing is broken when it is not.
c, _ = client
res = c.get("/definitely-not-a-route-xyz")
assert res.status_code == 404
assert res.headers.get(MARKER)
def test_the_marker_reports_the_running_version(client):
c, main = client
from core.version import APP_VERSION
assert c.get("/health").headers[MARKER] == APP_VERSION
def test_the_marker_survives_the_auth_gates(monkeypatch, tmp_path):
# The PIN/API-key middlewares answer 401 themselves, outside any route.
# Those rejections are responses too, and a client that gets one has
# certainly reached a backend — it must not read as "wrong host".
monkeypatch.setenv("OMNIVOICE_DATA_DIR", str(tmp_path))
monkeypatch.setenv("OMNIVOICE_API_KEY", "secret-key-for-this-test")
import importlib
import main
importlib.reload(main)
try:
c = TestClient(main.app)
res = c.get("/system/info", headers={"x-forwarded-for": "203.0.113.9"})
# Assert the rejection first (CodeRabbit): a 200 here would mean the
# gate never ran, and the test would prove nothing about middleware-
# generated responses — the only kind that bypass every route.
assert res.status_code == 401, (
f"expected the API-key gate to reject this request, got {res.status_code}"
)
assert res.headers.get(MARKER), "auth-gate rejection lost the marker"
finally:
monkeypatch.delenv("OMNIVOICE_API_KEY", raising=False)
importlib.reload(main)
def test_the_marker_is_exposed_to_cross_origin_readers():
# A browser can only read a response header that CORS exposes. The whole
# point is the deployment where the UI is on another origin, so an
# unexposed marker is an invisible one.
import main
for mw in main.app.user_middleware:
if mw.cls.__name__ == "CORSMiddleware":
exposed = [h.lower() for h in mw.kwargs.get("expose_headers", [])]
assert MARKER in exposed
return
pytest.fail("CORSMiddleware is not registered")