This commit is contained in:
Vansh Kumar Singh 2026-10-03 16:25:05 -04:00 • committed by GitHub
commit 853c743c06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 80 additions and 11 deletions

View file

@ -1,4 +1,4 @@
"""Image-level regression net for arbitrary-uid boot of the UI image.
"""Image-level regression net for the standalone UI image.
OpenShift ``restricted-v2`` ignores the image ``USER`` and assigns an
arbitrary uid in GID 0. The stock nginx base expects to start as root, so
@ -12,6 +12,11 @@ filesystem and ``/tmp`` as the only writable mount, is what catches the
whole class: a boot as the default (root) uid passes even on the broken
config.
The Next.js client requests RSC payloads under the dashboard's ``/ui`` URL
prefix, while the static export stores them at the nginx document root. The
image must strip that prefix for existing payloads without serving HTML for a
missing payload.
Gated on LITELLM_IMAGE so it is skipped in the normal unit-test run and
exercised only where an image has been built (the image-scan workflow).
Requires a working docker CLI.
@ -65,6 +70,7 @@ def ui_container() -> Iterator[tuple[str, str]]:
"--read-only", "--tmpfs", "/tmp",
IMAGE,
)
_wait_for_ui(network, container)
yield network, container
finally:
_docker("logs", container, check=False)
@ -96,17 +102,30 @@ def _probe(network: str, container: str, path: str) -> "subprocess.CompletedProc
)
def test_ui_serves_as_arbitrary_uid_read_only(ui_container: tuple[str, str]) -> None:
"""nginx boots and serves as an arbitrary uid with a read-only root fs.
def _fetch_body(network: str, container: str, path: str) -> "subprocess.CompletedProcess[str]":
"""Fetch a payload body and make curl fail on an HTTP error response."""
return _docker(
"run", "--rm", "--network", network, CURL_IMAGE,
"--silent", "--show-error", "--fail", "--max-time", "10",
f"http://{container}:{UI_PORT}{path}",
check=False,
)
On the pre-fix config nginx exits during startup with
``mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)``
and the running-check below fails; it never reaches the probes.
"""
network, container = ui_container
def _probe_content_type(network: str, container: str, path: str) -> "subprocess.CompletedProcess[str]":
"""Read the response MIME type without retaining another payload body."""
return _docker(
"run", "--rm", "--network", network, CURL_IMAGE,
"--silent", "--show-error", "--fail", "--max-time", "10",
"--output", "/dev/null", "--write-out", "%{content_type}",
f"http://{container}:{UI_PORT}{path}",
check=False,
)
def _wait_for_ui(network: str, container: str) -> None:
"""Wait for nginx to serve traffic or fail with its startup logs."""
deadline = time.time() + STARTUP_TIMEOUT_SECONDS
healthz = None
while time.time() < deadline:
if not _is_running(container):
pytest.fail(
@ -116,17 +135,63 @@ def test_ui_serves_as_arbitrary_uid_read_only(ui_container: tuple[str, str]) ->
)
healthz = _probe(network, container, "/healthz")
if healthz.returncode == 0 and healthz.stdout.strip() == "200":
break
return
time.sleep(2)
assert healthz is not None and healthz.stdout.strip() == "200", (
pytest.fail(
f"/healthz never answered 200 within {STARTUP_TIMEOUT_SECONDS}s as uid "
f"{ARBITRARY_UID}.\n{_container_logs(container)}"
)
def test_ui_serves_as_arbitrary_uid_read_only(ui_container: tuple[str, str]) -> None:
"""nginx boots and serves as an arbitrary uid with a read-only root fs.
On the pre-fix config nginx exits during startup with
``mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)``
and the fixture fails before it reaches these route probes.
"""
network, container = ui_container
for path in ("/", "/ui", "/ui/login"):
page = _probe(network, container, path)
assert page.stdout.strip() == "200", (
f"GET {path} returned {page.stdout.strip()!r} as uid {ARBITRARY_UID}.\n"
f"{_container_logs(container)}"
)
@pytest.mark.parametrize(
("canonical_path", "ui_path"),
(
("/index.txt", "/ui/index.txt"),
("/api-keys/index.txt", "/ui/api-keys/index.txt"),
("/api-keys/index.txt", "/ui/api-keys.txt"),
("/__next._tree.txt", "/ui/__next._tree.txt"),
("/api-keys/__next._tree.txt", "/ui/api-keys/__next._tree.txt"),
),
ids=("dashboard-root", "trailing-slash-route", "route", "root-tree", "nested-tree"),
)
def test_ui_prefixed_rsc_payload_matches_static_export(
ui_container: tuple[str, str], canonical_path: str, ui_path: str,
) -> None:
network, container = ui_container
canonical_payload = _fetch_body(network, container, canonical_path)
ui_payload = _fetch_body(network, container, f"{ui_path}?_rsc=regression")
ui_content_type = _probe_content_type(network, container, f"{ui_path}?_rsc=regression")
assert canonical_payload.returncode == 0, canonical_payload.stderr
assert ui_payload.returncode == 0, ui_payload.stderr
assert ui_content_type.returncode == 0, ui_content_type.stderr
assert canonical_payload.stdout
assert ui_payload.stdout == canonical_payload.stdout
assert ui_content_type.stdout.strip().startswith("text/plain")
def test_ui_prefixed_missing_rsc_payload_stays_404(ui_container: tuple[str, str]) -> None:
network, container = ui_container
missing_payload = _probe(network, container, "/ui/does-not-exist.txt?_rsc=regression")
assert missing_payload.stdout.strip() == "404", _container_logs(container)

View file

@ -85,6 +85,10 @@ http {
# /ui/<page>.txt would otherwise be rewritten to HTML and break RSC
# for nested routes. A genuinely missing payload must 404 (the
# router degrades to a hard navigation); never fall back to HTML.
location ~ ^/ui/(.+)\.txt$ {
try_files /$1.txt /$1/index.txt =404;
}
location ~ \.txt$ {
try_files $uri =404;
}