Keep the deployed API's OpenAPI document closed, deliberately #127
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/close-openapi-in-production"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Task 189. The Compose full-stack API container runs as Production (no
ASPNETCORE_ENVIRONMENTset), so/openapiand/swagger404 there by ADR-0029's own design — task 119 worked around it with a committed snapshot. This was never actually decided; it was the accidental side effect of an unset variable.Decision: keep it closed.
IsDocumentedis unchanged — no code change makes this true, only a record saying it's deliberate. The repo has been public since 2026-08-03, so an interactive explorer doesn't reveal the API's shape; what it hands an anonymous visitor is a ready, pre-wired client against the live deployed origin, "Try it out" included — real attack surface for a hobby-scale, conservative posture, bought for nothing this project currently needs. Opening even the raw JSON alone was considered and rejected too: a stable Production URL is a published contract on ADR-0085's own terms, and trips that record's own named trigger for reopening it.That makes
docs/openapi/v1.jsonthe supported answer rather than a workaround, which makes ADR-0108's own accepted gap — nothing checks it against the live document — the thing actually worth fixing.OpenApiSnapshotTests.CommittedSnapshot_MatchesTheLiveDocumentstarts aDevelopment-environment host, fetches/openapi/v1.jsonexactly as a real caller would, and compares it against the committed file — parsed as JSON (JsonNode.DeepEquals), not as text. A literal string comparison was tried first and rejected on real evidence: the live document's non-ASCII characters arrive over HTTP unescaped, the committed file holds them\u-escaped, and that alone reddened a snapshot with no actual drift. Mutation-tested: changed the committed file'sinfo.title, confirmed the test reddens with the live document written to a temp file and the exactcpcommand to fix it, restored, confirmed green.ADR-0111 records both halves. ADR-0108 gains
Answered by: ADR-0111for the gap it named and left open (ADR-0107's mechanism, its second real use).Merged
main(#125's ADR-0110 landed since branching); index regenerated viaAdrIndexTests, not hand-merged.Full suite,
dotnet format --verify-no-changes, and the coverage ratchet all clean on the pinned SDK.Verdict: mergeable
CI green on
9d1e3cc(run #464:build648 success,e2e650 success) — checked via/actions/tasks, notget_workflow_run.1. Mutation-tested the drift guard myself, with drift that matters. Removed
/health/liveentirely from the committeddocs/openapi/v1.json— reddened, with the temp-file path and exactcpfix in the message. Restored, re-tried by emptying a schema'srequiredarray (BeginOidcLinkResponse) — reddened again. Restored both times, confirmed green. This guard catches real shape drift, not onlyinfo.title.2.
JsonNode.DeepEqualssemantics, measured, not assumed. A throwaway check confirms it's order-insensitive for object keys ({"a":1,"b":2}=={"b":2,"a":1}) but order-sensitive for arrays ([1,2,3]!=[3,2,1]), including nested arrays inside objects. Sopathsbeing a JSON object is safe regardless of route-enumeration order, but any array in the document (tags,required,security) isn't protected by DeepEquals alone — it needs the underlying generation to be deterministic. Checked that directly: fetched the live document from two independentWebApplicationFactoryinstances, five separate process runs (ten fetches total), asserted byte-for-byte text equality every time. No ordering flake found.3. The test's
Developmenthost doesn't leak into deployment. Diff is confined to the test file, a doc comment, the ADRs and README — noProgram.cs,docker-compose.yml, orappsettings.*touched. Connection string is the same unroutable TEST-NET-1 pattern already used elsewhere (CorsPolicyTestsand others), not a new convention.4. The decision holds up. Public-since-2026-08-03 makes the "reveals nothing not already in source" claim correct, and the real distinction (pre-wired live client vs. static disclosure) is the one actually argued, not asserted. Both alternatives — open the UI, open raw JSON alone — get real reasoning in ADR-0111's own Alternatives section, tied concretely to ADR-0085's named reopening trigger, not a token mention.
5.
Answered by: ADR-0111fits ADR-0107's narrow definition. ADR-0108's own Consequences and Alternatives sections explicitly name the missing drift check as a specific, deferred gap ("Whoever picks up the CI-check alternative above should read this record first") — a genuine explicit deferral, not a later record merely touching the same area. ADR-0111 answers that exact question, even though the mechanism (in-process test vs. the CI job ADR-0108 sketched) differs — the deferred question was "is there a check", not "is it a CI job", and ADR-0111's own Alternatives section explains that substitution.AdrIndexTestspass locally (12/12), index correctly carries 0110/0111 and not 0112 (mine, still open).dotnet format --verify-no-changesclean.