Repository navigation
feat(docs-routes): forward protected Swagger UI keys by header instead of embedding them - #823
Conversation
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Also align JSON/YAML handler parameter names with the SDK req binding, as required by real-host worker indexing. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #812. Real CDN Chromium regressions prove fail-closed redirects without changing default or legacy-query rendering.
R3 authorization record (PR #823, head 2c727e7)What this is: the maintainer (yeongseon) delegated the merge decision to an Oracle (AI) review in the working session ("decide the merge with Oracle and proceed", then "review, merge, and continue"). No line-by-line human review of this diff has taken place. Under the repository policy (#818) Oracle is advisory; this is a delegated decision, not independent human approval. The squash commit can be reverted if the maintainer disagrees after reading it. Oracle verdicts (real Chromium + the real Swagger UI 5.32.4 CDN bundle, SRI enforced)
Fix verified: Residual risks (documented in docs/security.md): the initial navigation URL reaches the Functions host and may appear in logs or browser history before cleanup; Not verified: Azure function-key enforcement (Core Tools does not enforce keys), the host's own request logging in a deployment, release-gate execution. Compatibility and release: |
Summary
First half of #812 (runtime and documentation): add explicit protected-docs key forwarding modes without embedding the page key in HTML in header mode. The security-gate half follows separately. Supersedes #816, which was closed when its stacked base branch was deleted after #815 merged.
Changes
register_openapi_routes(..., docs_key_forwarding=None)accepts"header","query", or"none". Protected default registrations retain legacy query forwarding and emit an intentional, testedDeprecationWarning; anonymous registrations never forward or warn. The default will become"header"in a future minor before 1.0.codeparameters withhistory.replaceState, preserves other parameters/fragments, and attachesx-functions-keyonly to the exact same-origin specification download, never Try-it-out. Absolute HTTPS specs never receive the page key; protocol-relative URLs are rejected.request.redirect = 'error': every redirect fails closed with Swagger UI's normal specification-load error, with no request to the destination.render_swagger_ui(..., forward_page_key_header=False)remains opt-in. Default and legacy-query HTML/headers are byte-identical toorigin/mainwith a fixed nonce. Snapshots are unchanged. No runtime dependencies, gate weakening, or type-ignore suppressions added.?code=URL inperformance.getEntriesByType("navigation")[0].nameafter address-bar cleanup, for the page lifetime.Type of Change
Checklist
Review history
Oracle NO-GO on
8f69463: redirects carry the key beyond the exact spec URL, proven with real Chromium and the real Swagger UI 5.32.4 CDN bundle with SRI enforced. Reproduced before the fix in this revision:Same-origin 307 and 308 also reproduced forwarding before the fix.
What changed: the interceptor sets
request.redirect = 'error'in exactly the guarded block that attaches the header. Inspection of the actual 5.32.4 bundle confirmed swagger-client'shttp_httpconsumeso = await o.requestInterceptor(o) || oand calls(o.userFetch || fetch)(o.url, o). Chromium regression instrumentation observes the actual native-fetch options without altering behavior and confirmsredirect: 'error'is honored. No alternative downloader is needed.After the fix: real-bundle same-origin 302/307/308, cross-origin 302 under permissive CSP/CORS, and a configured same-origin-to-cross-origin chain all fail closed before any destination request. The normal real-bundle flow still loads the spec, cleans the address bar, executes
/api/pingwithout the key, and requests favicon without the key.A separate AI reviewer inspected the delta and reported no blocking findings. This is advisory evidence, not human approval or authorization. Review threads were not resolved.
Verification
hatch run pytest -q: passed; 95.14% branch-inclusive coverage, unchanged 95% floor. Optional validation-dependent tests and the live-host test skip in this default invocation. Expected deprecation/runtime warnings remain visible.hatch run pytest -m browser --no-cov -q -s tests/test_docs_key_browser.py: 8 passed, including 6 real-CDN/SRI cases, no network skips. CDN cases carry bothbrowserand registeredbrowser_cdnmarkers and skip on recognized CDN network unavailability; SRI/execution failures are failures.hatch run mypy --strict src tests: passed (96 files).hatch run mkdocs build --strict: passed. The theme prints its upstream MkDocs 2 migration notice; no strict-build failure.hatch build: sdist and wheel built.origin/mainbyte-for-byte; snapshots untouched.tests/host_smoke/test_fixture_routes.pytests passed withHOST_SMOKE_BASE_URL. Storage-health timeout appeared during teardown after Azurite was stopped. This does not prove Azure function-key enforcement./tmp/opencodeworktree because they are outside the request cwd. Strict mypy and Ruff pass; no clean LSP result is claimed.Residual risks: the initial navigation URL reaches the Functions host and may be retained in proxy/access logs, earlier history, navigation timing, and other page-lifetime memory. Header forwarding does not erase these copies. The key must authorize both functions; prefer production edge authentication. Azure key enforcement was not reverified locally.
Related Issues
Final CI evidence
Final head:
2c727e77e099751afa140364e48660d2e35f859c.Exact-head check-runs show all required contexts completed successfully:
bandit,semgrep,Analyze,PR title, andci-required.The full test/compatibility/build/docs/performance matrix and both real-host
smoke jobs passed (CI run
40038682936). An earlier duplicatePR titlerun40038683035was cancelled, although the oldgh pr checksCLI labels itfail; the later run40038683304completed successfully. No reruns,force-push, merge, or thread resolution were performed.
mainremained67e7f548dd1c6010ffdc89ff99bbd902ee9b28e0after completion.Refs #812