Skip to content

fix(egress): preserve forwarded query strings - #2989

Open
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/egress-preserve-query-string
Open

fix(egress): preserve forwarded query strings#2989
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/egress-preserve-query-string

Conversation

@tang-vu

@tang-vu tang-vu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Why this matters

remote-provider-egress is the production boundary between OpenAI-compatible clients and a configured remote runtime. The catch-all route validated the path and body but discarded the incoming query string, so provider features expressed as encoded or repeated query parameters silently changed in transit.

Root cause and invariant

The FastAPI handler passed only /{full_path} into prepare_upstream_request, and _join_openai_path built a URL from that path alone. The invariant is: after the path allowlist is applied, the original raw query string must reach the same upstream request without decoding, reordering, or collapsing repeated keys.

This change passes Starlette's raw ASCII query string into the pure request-preparation helper and composes it with urllib.parse, while path authorization remains exact and unchanged.

Overlap check

Searched open and closed PRs for remote provider egress query string, egress query passthrough, and the changed production files. Open PRs touching app/main.py are #2733 (caller auth), #2708 (bounded request bodies), #2702 (client LRU), and #2700 (non-blocking probes). None preserves query semantics; ods/bin/remote_provider/egress.py has no overlapping open PR.

Regression coverage

The request-preparation contract now exercises an encoded value plus a repeated key and asserts the exact upstream URL. This is the nearest deterministic boundary before the HTTP client sends the production request, and the FastAPI handler is wired to supply the raw ASGI query bytes.

Validation

  • python ods/tests/contracts/test-remote-provider-egress-service.py — 16 passed
  • python -m py_compile ods/bin/remote_provider/egress.py ods/extensions/services/remote-provider-egress/app/main.py
  • git diff --check

Tradeoffs and rollback

No query parameters are interpreted or trusted by ODS; they remain provider-owned data after the existing path, route, DNS, body, and credential controls pass. Rollback is a clean revert of this commit, restoring the prior query-dropping behavior.

@tang-vu

tang-vu commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Batch compatibility receipt (2026-08-23)

Validated merge order: #2989 ? #2990 ? #2993 ? #2991 ? #2992 ? #2994 ? #2995 ? #2996 ? #2997 ? #2998. The changes are independently useful; this order only reconciles shared model-router and magic-link files.

Synthetic integration head: origin/batch/quality-ten-20260822-round2-integration at 91eb730d. The only textual conflict was the two model-router tests inserting at the same class boundary; the integration resolution retains both contracts. Magic-link changes merged cleanly.

Combined validation on that exact head:

  • remote-provider egress contract: 16 passed
  • Token Spy suites: 22 passed, 1 skipped (live PostgreSQL availability)
  • model-router suite: 55 passed
  • APE suite: 29 passed
  • dashboard OAuth + magic-link suites: 118 passed, 2 platform skips
  • Brave Search loopback E2E: all checks passed
  • git diff --check: passed

All required GitHub checks are green across the batch. #2992 initially hit a transient openSUSE repository/mirror failure while installing rsync; a clearly labeled empty retry commit reran the unchanged tree, and openSUSE plus the full matrix passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant