fix(swagger): point the bundled UI at a document that exists - #129
Merged
andrevanzuydam merged 1 commit intoSep 9, 2026
Conversation
The bundled Swagger UI page asks for `{SWAGGER_ROUTE}/swagger.json`. That
placeholder is never substituted -- nothing in the static path templates the
file, it is served byte-for-byte off disk -- so the browser requests the
literal string, which 404s. The page loads, renders the Swagger chrome, and
then shows an error where the API should be.
The document is served at /swagger/openapi.json, so name it directly. A
literal is the right shape here precisely because this file is not templated.
This is reachable on every path that serves the bundled asset rather than a
route: /swagger//, /swagger/index.html, and -- when the swagger routes are not
registered -- /swagger itself.
The regression asserts the property rather than the paths: for every path form
that answers with a UI page, read the `url:` out of the HTML that was actually
served and fetch it. Any page naming a document that does not resolve fails,
including forms nobody has thought of yet.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The defect
The bundled Swagger UI page asks the browser for
{SWAGGER_ROUTE}/swagger.json. That placeholderis never substituted — nothing in the static path templates the file, it is served
byte-for-byte off disk — so the browser requests the literal string, which 404s. The page loads,
renders the Swagger chrome, and then shows an error where the API should be.
swagger.jsonis not a route in this port, or in any of the others. The document is served at/swagger/openapi.json.Where it is reachable
core/server.py:1704already claims both canonical forms inline ("/swagger","/swagger/"), sothose two serve the real UI. The bundled asset is what answers:
GET /swagger//GET /swagger/index.htmlBoth 200, both with a UI that can never load. With swagger disabled all forms 404
(
core/server.py:3220), so there is no production exposure — only a UI that cannot work where oneis advertised.
The fix
One string in
tina4_python/public/swagger/index.html:A literal is the right shape here precisely because this file is not templated. An absolute path is
also the only correct form: a relative URL resolves differently from
/swaggerthan from/swagger/.The regression test
It went into
tests/test_swagger_static_gate.py, the file that already owns this surface. Thatfile was written for an earlier leak on these same assets and stops at status codes — which is
exactly why it never noticed this.
The new test asserts the property, not the paths: for every path form that answers with a UI
page, read the
url:out of the HTML that was actually served and fetch it. Any page naming adocument that does not resolve fails, including forms nobody has thought of yet.
With the one string reverted and the test kept:
Verification
Full suite against pristine
v3a380345in the same tree: base 5247 passed / 5 failed / 664skipped, with this branch 5248 / 5 / 664. The five failures are identical by name either
way — the skill installer, a firebird connect timeout, and three port-takeover contract tests, all
needing services the test machine does not run. The
+1is this branch's own test.Run under
uv sync --extra test, as CI does (.github/workflows/test.yml:266) — without theextra,
tests/test_swagger_contract.pycannot importopenapi-spec-validator, which is declaredTEST-ONLY in the
testextra atpyproject.toml:99.Not python-only
The same unsubstituted file ships in
tina4-nodejsandtina4-ruby; both have their own pullrequests.
tina4-phpships an equivalent page asking for{{baseURL}}/swagger/json.json, a tokenthat likewise occurs exactly once in that tree; that one has not been reproduced and has no fix yet.