fix: serve certification page on direct load, read certify key from env, fix sequential note

This commit is contained in:
9qeklajc
2026-10-03 13:28:36 +02:00
parent 4d65cd6f4c
commit fb7de40a87
5 changed files with 91 additions and 14 deletions
+15 -12
View File
@@ -340,6 +340,21 @@ async def providers() -> RedirectResponse:
UI_DIST_PATH = Path(__file__).parent.parent.parent / "ui_out"
# Every `ui/app/**/page.tsx` route needs an entry, or a direct load 404s.
UI_PAGES = (
"dashboard",
"login",
"model",
"providers",
"providers/certification",
"settings",
"transactions",
"balances",
"logs",
"usage",
"unauthorized",
)
if UI_DIST_PATH.exists() and UI_DIST_PATH.is_dir():
logger.info(f"Serving static UI from {UI_DIST_PATH}")
@@ -362,18 +377,6 @@ if UI_DIST_PATH.exists() and UI_DIST_PATH.is_dir():
# with a slash (e.g. `/login/`). The proxy router catches `/{path:path}`
# before FastAPI's `redirect_slashes` logic can normalize the URL, so we
# must register both the with-slash and without-slash variants here.
UI_PAGES = (
"dashboard",
"login",
"model",
"providers",
"settings",
"transactions",
"balances",
"logs",
"usage",
"unauthorized",
)
def _register_ui_page(name: str) -> None:
page_dir = UI_DIST_PATH / name
+9 -1
View File
@@ -17,6 +17,7 @@ import argparse
import asyncio
import json
import math
import os
import sys
import time
from collections.abc import Callable
@@ -1245,7 +1246,14 @@ def main(argv: list[str] | None = None) -> int:
required=True,
help="Upstream base URL (repeatable), e.g. https://api.example.com/v1",
)
parser.add_argument("--key", default="", help="Bearer API key for the upstream")
parser.add_argument(
"--key",
default=os.environ.get("ROUTSTR_CERTIFY_KEY", ""),
help=(
"Bearer API key for the upstream (defaults to $ROUTSTR_CERTIFY_KEY; "
"prefer the env var so the key stays out of shell history and ps)"
),
)
parser.add_argument(
"--model",
default=None,
+46
View File
@@ -0,0 +1,46 @@
"""The certification CLI reads the upstream key from the environment."""
from __future__ import annotations
from typing import Any
import pytest
from routstr.upstream import certification
@pytest.fixture
def captured_keys(monkeypatch: pytest.MonkeyPatch) -> list[str]:
keys: list[str] = []
async def fake_certify(url: str, *, api_key: str, **_: Any) -> dict[str, Any]:
keys.append(api_key)
return {"url": url, "rows": []}
monkeypatch.setattr(certification, "certify_upstream_url", fake_certify)
monkeypatch.setattr(certification, "render_checklist", lambda _result: "")
return keys
def test_key_defaults_to_env_var(
monkeypatch: pytest.MonkeyPatch, captured_keys: list[str]
) -> None:
monkeypatch.setenv("ROUTSTR_CERTIFY_KEY", "sk-from-env")
assert certification.main(["--url", "http://localhost:1/v1"]) == 0
assert captured_keys == ["sk-from-env"]
def test_key_flag_overrides_env_var(
monkeypatch: pytest.MonkeyPatch, captured_keys: list[str]
) -> None:
monkeypatch.setenv("ROUTSTR_CERTIFY_KEY", "sk-from-env")
certification.main(["--url", "http://localhost:1/v1", "--key", "sk-flag"])
assert captured_keys == ["sk-flag"]
def test_key_is_empty_without_flag_or_env(
monkeypatch: pytest.MonkeyPatch, captured_keys: list[str]
) -> None:
monkeypatch.delenv("ROUTSTR_CERTIFY_KEY", raising=False)
certification.main(["--url", "http://localhost:1/v1"])
assert captured_keys == [""]
+19
View File
@@ -0,0 +1,19 @@
"""Every static UI page must be served on a direct load, not the proxy 404."""
from __future__ import annotations
from pathlib import Path
from routstr.core import main as core_main
UI_APP_DIR = Path(__file__).resolve().parents[2] / "ui" / "app"
def test_every_ui_app_page_is_in_ui_pages() -> None:
routes = {
page.parent.relative_to(UI_APP_DIR).as_posix()
for page in UI_APP_DIR.rglob("page.tsx")
if page.parent != UI_APP_DIR
}
assert routes, "no ui/app pages found"
assert routes - set(core_main.UI_PAGES) == set()
@@ -272,7 +272,8 @@ export function ProviderCertificationSetupPanel({
)}
{mode === 'all' && (
<p className='text-muted-foreground text-xs'>
All {paths.length} paths will run in parallel.
All {paths.length} paths will run one after another, each
with its own probe calls.
</p>
)}
</>