Fix/adjust diffusion: filename validator order, 503 mapping, token redaction for PR #5754

Round 39 review findings (2 P1 + 1 P2):

1. routes/datasets.py: validate raw multipart filename before sanitize so
   smuggled control chars (NUL, newline) are rejected at the same boundary
   as the JSON path in seed.py. Previously _sanitize_filename stripped the
   control chars first, letting raw inputs slip past the validator.

2. routes/inference.py: extend RuntimeError -> 503 mapping in /images/load
   to classify "Another GPU workload is mid-handoff" as retryable, so the
   backend-surfaced phrasing matches the route-level 503 already returned
   from _raise_if_helper_advisor_busy.

3. core/inference/diffusion.py: redact hf_ tokens in the local-path branch
   of _display_repo_id so a leaf directory named hf_<token> cannot leak
   into UI labels or structured logs.
This commit is contained in:
Daniel Han-Chen 2026-05-25 21:22:13 +00:00
commit f5186e2b35
3 changed files with 18 additions and 9 deletions

View file

@ -330,7 +330,9 @@ def _display_repo_id(value: Any) -> Any:
try:
candidate = Path(value).expanduser()
if candidate.is_absolute() or candidate.exists():
return candidate.name or value
# Defense-in-depth: redact any hf_... pattern that survives
# in the leaf name before returning it to the UI / log line.
return _redact_hf_tokens(candidate.name or value)
except (OSError, ValueError):
pass
return _redact_hf_tokens(value)

View file

@ -336,19 +336,20 @@ async def upload_dataset(
file: UploadFile,
current_subject: str = Depends(get_current_subject),
) -> UploadDatasetResponse:
filename = _sanitize_filename(file.filename or "dataset_upload")
# Round 34 P1: mirror the seed.py multipart filename hardening so
# /api/datasets/upload also rejects control characters and embedded
# HF tokens. The reflected filename + stored_path are echoed back
# to the client and persisted, so the validators must match the
# JSON-side hardening on SeedInspectUploadRequest.filename.
# Validate the raw multipart filename BEFORE sanitization so smuggled
# control characters and embedded HF tokens are rejected at the same
# boundary as the JSON path; sanitizing first would silently strip
# control chars and let raw inputs pass the validator.
raw_filename = file.filename or "dataset_upload"
from models.inference import _no_control_chars, _reject_embedded_hf_token
try:
_no_control_chars(filename, "filename")
_reject_embedded_hf_token(filename, "filename")
_no_control_chars(raw_filename, "filename")
_reject_embedded_hf_token(raw_filename, "filename")
except ValueError as exc:
raise HTTPException(status_code = 400, detail = str(exc)) from exc
filename = _sanitize_filename(raw_filename)
ext = Path(filename).suffix.lower()
if ext not in LOCAL_UPLOAD_EXTS:
allowed = ", ".join(sorted(LOCAL_UPLOAD_EXTS))

View file

@ -2498,6 +2498,12 @@ async def diffusion_load(
# Round 28 P2 #15: AI Assist running (raised by
# _release_chat_backend_for_diffusion) is retryable.
or "AI Assist" in detail
# Backend mid-handoff race (raised by
# _raise_if_helper_advisor_busy_for_diffusion when
# another workload's public_load_pending is set) mirrors
# the route-level 503 at routes/inference.py:415, so the
# backend-surfaced phrasing must classify the same way.
or "Another GPU workload is mid-handoff" in detail
):
# Round 17 P1 #2: chat unload failures raised by the
# backend helper map to 503 (retryable infra issue),