mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-20 05:56:56 +00:00
feat: read-only admin dashboard and JSON API
Adds GET /admin (single-page dashboard), GET /admin/api/overview, and GET /admin/api/usage per spec §4: providers/redis/cache/groups summary and per-user/group current-window usage+limits. Gated by Config.Admin (default off, not registered when disabled) and UserConfig.Admin. Gate order: disabled -> 404 fall-through; unauthenticated -> 401; authenticated non-admin -> 403; admin -> serve, counted against the admin's own request limits like any other route. Adds small, read-only, mutex-guarded hooks: modelRegistry.snapshot(), limiter.currentUsage()/redisStatus(), authStore.snapshot(). No secret field (API key, digest, redis password) is ever read into any admin response type; verified by a canary-literal redaction test. HTML/CSS/JS ship as a single Go raw-string const (Yaegi forbids go:embed); confirmed interpretable via make yaegi-check.
This commit is contained in:
@@ -22,6 +22,11 @@ type Config struct {
|
||||
Agents map[string]*AgentConfig `json:"agents,omitempty"`
|
||||
Users *UsersConfig `json:"users,omitempty"`
|
||||
Redis *RedisConfig `json:"redis,omitempty"`
|
||||
// Admin gates the read-only admin dashboard (spec §4, v0.2): nil or
|
||||
// Admin.Enabled false means the /admin* routes are not registered at
|
||||
// all — ServeHTTP falls through to its existing 404/passthroughUnknown
|
||||
// handling for those paths, preserving v0.1 behavior exactly.
|
||||
Admin *AdminConfig `json:"admin,omitempty"`
|
||||
// Retry is a struct value, not a pointer, because its own Enabled
|
||||
// field is the on/off signal (unlike Redis/Users, where the block's
|
||||
// mere presence is the signal) — so its tag omits "omitempty":
|
||||
@@ -84,6 +89,13 @@ type UserConfig struct {
|
||||
Name string `json:"name"`
|
||||
Group string `json:"group"`
|
||||
APIKey string `json:"apiKey"`
|
||||
// Admin grants this user access to the read-only admin dashboard
|
||||
// (spec §4, v0.2), whether the user is inline or file-sourced —
|
||||
// file-users granting admin is operator-controlled via the Secret
|
||||
// backing Users.File, which is an accepted trust boundary. An admin
|
||||
// user is otherwise an ordinary user: their own keys, group, and
|
||||
// limits still apply, including to the admin routes themselves.
|
||||
Admin bool `json:"admin,omitempty"`
|
||||
}
|
||||
|
||||
// RedisConfig configures the distributed limit-state backend.
|
||||
@@ -136,6 +148,15 @@ type CacheConfig struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
// AdminConfig configures the read-only admin dashboard (spec §4, v0.2).
|
||||
// The zero value (Enabled: false) disables it, preserving v0.1 behavior
|
||||
// exactly: no /admin* route is registered, so those paths fall through
|
||||
// to ServeHTTP's existing 404/passthroughUnknown handling like any other
|
||||
// unrecognized path.
|
||||
type AdminConfig struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
// ModelPricing overrides the built-in per-model price table.
|
||||
type ModelPricing struct {
|
||||
InputPerM float64 `json:"inputPerM"`
|
||||
@@ -383,6 +404,16 @@ func (g *Gateway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Admin routes (spec §4, v0.2) are matched only when adminEnabled: a
|
||||
// nil or disabled Config.Admin means none of these paths are
|
||||
// registered at all, so a request to /admin* falls through to the
|
||||
// same 404/passthroughUnknown handling as any other unrecognized
|
||||
// path — no special-casing needed for the disabled case.
|
||||
if adminEnabled(g.cfg) && r.Method == http.MethodGet && isAdminPath(r.URL.Path) {
|
||||
g.handleAdmin(sw, r)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == http.MethodGet && (r.URL.Path == "/v1/mcp/servers" || r.URL.Path == "/v1/agents") {
|
||||
u, grp, ok := g.auth.identify(r)
|
||||
g.logAuthEvent(ok, authEventUserName(u), r)
|
||||
|
||||
Reference in New Issue
Block a user