fix(backend): gate Swagger + the OpenAPI doc behind IsDevelopment (RB-15)
BIO-015: app.UseSwagger()/app.UseSwaggerUI() ran unconditionally, so
the full OpenAPI document (every route + request/response shape) and
SwaggerUI's interactive "Try it out" were reachable in every
environment, including a real deployment.
Both now run only inside `if (app.Environment.IsDevelopment())`.
AddSwaggerGen/AddEndpointsApiExplorer stay unconditional — DI
registration only, no HTTP surface by itself.
RB-09 already made a non-Development environment throw at startup,
which broke `npm run gen:api` until that script pinned
ASPNETCORE_ENVIRONMENT=Development for its one CLI invocation. This
change sits in the same pipeline, so it was verified rather than
assumed: `dotnet swagger tofile` resolves ISwaggerProvider straight
out of DI and never sends an HTTP request through this middleware, so
gating it can't affect that tool by construction. Ran the real
`npm run gen:api` to confirm — exit 0, regenerated files byte-identical
to what's committed.
New tests exercise the gate on a third ("Staging") environment name,
not Production — Production already can't boot at all post-RB-09, so
a Production-environment test would only re-prove that unrelated
startup throw, not this gate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -142,8 +142,21 @@ app.Use(async (ctx, next) =>
|
||||
await next(ctx);
|
||||
});
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
// RB-15/BIO-015: the OpenAPI document + its UI are a genuine attack-surface reduction to
|
||||
// gate — they enumerate every route, request/response shape and (via SwaggerUI's "Try it
|
||||
// out") let a caller fire requests straight from the browser. Development-only, like the
|
||||
// dev-role/scenario-toggle hatches this POC already keeps out of production builds
|
||||
// (docker-compose.prod.yml runs Production; only docker-compose.yml's dev image runs
|
||||
// Development). `dotnet swagger tofile` (npm run gen:api) is unaffected: Swashbuckle's CLI
|
||||
// resolves ISwaggerProvider straight out of the DI container to build swagger.json — it
|
||||
// never sends an HTTP request through this pipeline, so it never touches this middleware at
|
||||
// all, gated or not. Verified empirically (see rb-15.md) rather than assumed, per RB-09's
|
||||
// note that this exact file has already broken that tool once.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
app.UseCors(SpaCors);
|
||||
|
||||
// Liveness/readiness for orchestrators (k8s probes, load balancers). No data, no PII.
|
||||
|
||||
Reference in New Issue
Block a user