//go:build dev package main import ( "log" "net/http" "github.com/google/uuid" "github.com/missionworkforce/missionmatch/internal/modules/auth" "github.com/missionworkforce/missionmatch/internal/platform/config" "github.com/missionworkforce/missionmatch/internal/platform/security" "github.com/missionworkforce/missionmatch/internal/platform/tenant" ) // chooseResolver, in a dev tagged build only, returns the X-Org-ID header resolver when it is // explicitly enabled, otherwise the real session resolver. This whole file is excluded from a default // release build, so the header path cannot ship. Production is further guarded: config.Validate fatals // if AllowDevHeaderAuth is true under Env production, and main asserts the active resolver is the // session one in production. func chooseResolver(cfg config.Config, authH *auth.Handler) (func(http.Handler) http.Handler, string) { if !cfg.AllowDevHeaderAuth { return authH.SessionMiddleware(), "session" } log.Printf("DEV: X-Org-ID header tenant resolver is ACTIVE; this must never run in production") return devHeaderMiddleware, "dev-header" } // devHeaderMiddleware resolves the tenant from the X-Org-ID header and stamps a synthetic owner // principal so the RBAC gated routes remain usable for local testing. Dev only. func devHeaderMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { raw := r.Header.Get("X-Org-ID") if raw == "" { http.Error(w, "forbidden", http.StatusForbidden) return } if _, err := uuid.Parse(raw); err != nil { http.Error(w, "forbidden", http.StatusForbidden) return } ctx := tenant.WithUser(tenant.WithOrg(r.Context(), raw), tenant.Principal{UserID: raw, Role: string(security.RoleOwner)}) next.ServeHTTP(w, r.WithContext(ctx)) }) }