Files
gis/internal/transport/http/router.go
Bakhtiyar Issakhmetov 5b44cbda2f fix(security): close High/Critical findings from the Stage 8 scan
- Bump github.com/rabbitmq/amqp091-go 1.12.0 -> 1.13.0 (3 Critical, 7 High,
  reachable via rabbitmq.Connect) and golang.org/x/{text,net,crypto},
  klauspost/compress; toolchain go1.26.8, builder image pinned to
  golang:1.26.8-alpine3.24.
- Build Content-Disposition per RFC 6266/8187 (ASCII fallback +
  filename*=UTF-8''), stripping CR/LF, quotes and backslashes (CWE-113).
- Cap request bodies with MaxBytesReader (HTTP_MAX_UPLOAD_BYTES, default
  2 GiB); multipart uploads over the limit return 413 (CWE-400).
- /readyz reports "unavailable" instead of raw backend errors (CWE-209).
- Drop deprecated middleware.RealIP; add X-Content-Type-Options: nosniff.
- docker-compose credentials come from ${VAR:-default}.
- Check the RegisterValidation error; annotate verified gosec false
  positives with #nosec and a reason.

Re-scan: govulncheck 0 reachable, trivy fs/image 0 High/Critical,
gosec High 0. go test -race passes against PostGIS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:44:10 +05:00

56 lines
1.6 KiB
Go

package http
import (
"log/slog"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
// RouterDeps holds the handlers and dependencies the router mounts.
type RouterDeps struct {
Logger *slog.Logger
Health *HealthHandler
Categories *CategoryHandler
Datasets *DatasetHandler
// DatasetGroups serves the /dataset-groups routes.
DatasetGroups *DatasetGroupHandler
// Landscape serves the /landscape routes.
Landscape *LandscapeHandler
OpenAPISpec []byte
// MaxBodyBytes caps every request body (uploads included); <= 0 disables
// the cap.
MaxBodyBytes int64
}
// NewRouter builds the application's HTTP handler with middleware and routes.
func NewRouter(deps RouterDeps) http.Handler {
r := chi.NewRouter()
// middleware.RealIP is deliberately not used: it rewrites r.RemoteAddr
// from client-controlled headers (X-Forwarded-For, X-Real-IP,
// True-Client-IP) and is deprecated upstream as an IP-spoofing vector.
r.Use(middleware.RequestID)
r.Use(requestLogger(deps.Logger))
r.Use(middleware.Recoverer)
r.Use(securityHeaders)
r.Use(limitRequestBody(deps.MaxBodyBytes))
// Health/readiness endpoints.
r.Get("/healthz", deps.Health.Live)
r.Get("/readyz", deps.Health.Ready)
// OpenAPI 3.1.1 spec + Redoc documentation UI.
r.Get("/openapi.yaml", deps.openAPISpec)
r.Get("/docs", docsUI)
// Domain routes. Add future feature routers here.
r.Route("/categories", deps.Categories.Register)
r.Route("/datasets", deps.Datasets.Register)
r.Route("/dataset-groups", deps.DatasetGroups.Register)
r.Route("/landscape", deps.Landscape.Register)
return r
}