fix(swagger): the API doc served Swagger's demo API, not ours - #143
Merged
Conversation
swagger-ui-dist ships a swagger-initializer.js whose spec URL is Swagger's public petstore demo, with a comment saying the line "will be replaced by docker/configurator, when it runs in a docker-container". We embed the assets rather than running that container, so nothing ever replaced it. The result: /swaggerui/ has always served somebody else's API. On an internal-only deployment - ubm01, where this was found - the browser cannot even reach that host, so the page renders an error instead. Two things had to be right, and neither can be known by this process: THE SPEC URL. Absolute paths break under a path prefix. A gateway that routes /reststore/ to us REWRITES THE PREFIX AWAY before the request arrives, so by the time any Go handler sees it the path is /swaggerui/ and the prefix is gone. The browser is the only party that still knows where the page came from, so the initializer derives it from window.location and asks for the spec relative to that. THE REQUEST BASE. The spec declares neither host nor basePath, so swagger-ui builds calls as origin + the path as written - https://host/v1/projects/... - which behind a prefix misses by exactly the prefix and 404s every "Try it out". Writing a basePath into the spec would bake one deployment's layout into an artifact all of them share, so a requestInterceptor re-adds the real mount instead. Overriding one file, not vendoring the directory: the bundles and CSS still come from the agent's embed, so there is no second copy to drift. The tests assert the failure, not the plumbing. A "200 OK" test would have passed throughout - the wrong file was being served perfectly well. One greps for the demo host by name, which is why the initializer's own comment must not mention it. pkg/storage/projects fails locally without a postgres on 5432; that is environmental and predates this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSzNfcVc1FnDCfk9AF68Eh
This was referenced Aug 18, 2026
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.
swagger-ui-distships aswagger-initializer.jswhose spec URL is Swagger's public demo API, with a comment saying the line "will be replaced by docker/configurator, when it runs in a docker-container". We embed the assets rather than running that container, so nothing ever replaced it.So
/swaggerui/has always served somebody else's API. Found on ubm01, where it is worse than cosmetic: the site is internal-only, the browser cannot reach that host at all, and the page just renders an error.Two things had to be right, and this process can know neither
The spec URL. An absolute path breaks under a prefix. A gateway routing
/reststore/to us rewrites the prefix away before the request arrives — by the time any Go handler sees it, the path is/swaggerui/and the prefix is gone. The browser is the only party that still knows where the page came from, so the initializer derives the mount fromwindow.locationand asks for the spec relative to it.The request base. The spec declares neither
hostnorbasePath, so swagger-ui builds calls as origin + the path as written —https://host/v1/projects/…— which behind a prefix misses by exactly the prefix and 404s every Try it out. Writing abasePathinto the spec would bake one deployment's layout into an artifact all of them share, so arequestInterceptorre-adds the real mount instead.Both work unchanged whether restcol is mounted at
/or at/reststore/, with no configuration.Scope
One file overridden, not a vendored directory. The bundles and the CSS still come from the agent's embed, so there is no second copy to drift.
On the tests
They assert the failure, not the plumbing — a "200 OK" test would have passed throughout this whole bug, because the wrong file was being served perfectly well. One greps for the demo host by name, which is why the initializer's own comment must not mention it, and says so.
pkg/storage/projectsfails locally without a postgres on 5432; environmental, predates this.Downstream
grandturks'
reststoreimportsrestcol/pkg/server, so it picks this up on ago.modbump. Tracked in FootprintAI/grandturks#1198, which also covers the remaining item:/reststore/itself is a 404, and nobody guessesswaggerui.