mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-15 05:29:28 +00:00
feat(auth): let a user join several groups and hold a personal grant
A user entry can now list several groups in "groups", next to the existing "group" field. A user can also hold a personal grant with its own "providers" and optional "models" lists. Users with one group and no personal grant behave exactly as before. A request is allowed only when one grant allows the provider, the model and, for passthrough, the path. Grants never merge, so one grant cannot supply the provider while another supplies the model or the path. The personal grant uses the path list of the first group. A personal "models" list without "providers" is a configuration error. Each member group applies its own limits. Caching stays on unless a member group turns it off, and the shortest group TTL wins. The /v1/models cache uses a stable, length-prefixed key, so reloads do not grow it. Tests cover the grant union, cross-grant denials, passthrough path and model coupling, reloads and the cache key. The yaegi-check harness asserts the same cases under the interpreter. Claude-Session: https://claude.ai/code/session_019uJHQKcNLMACkXssb3L7Q3
This commit is contained in:
@@ -732,23 +732,28 @@ func (g *Gateway) serveAdminOverview(w http.ResponseWriter) {
|
||||
// dashboard can tell "explicitly restricted to these N" apart from
|
||||
// "unrestricted" without the payload growing with catalog size.
|
||||
type adminUsageEntryView struct {
|
||||
Limits *LimitsConfig `json:"limits,omitempty"`
|
||||
Kind string `json:"kind"`
|
||||
ID string `json:"id"`
|
||||
GroupName string `json:"groupName,omitempty"`
|
||||
Providers []string `json:"providers,omitempty"`
|
||||
Models []string `json:"models,omitempty"`
|
||||
MCPServers []string `json:"mcpServers,omitempty"`
|
||||
Agents []string `json:"agents,omitempty"`
|
||||
RequestsPerMinute int64 `json:"requestsPerMinute"`
|
||||
RequestsPerDay int64 `json:"requestsPerDay"`
|
||||
TokensInPerDay int64 `json:"tokensInPerDay"`
|
||||
TokensOutPerDay int64 `json:"tokensOutPerDay"`
|
||||
TokensInPerMonth int64 `json:"tokensInPerMonth"`
|
||||
TokensOutPerMonth int64 `json:"tokensOutPerMonth"`
|
||||
CostPerDayMicroUSD int64 `json:"costPerDayMicroUsd"`
|
||||
CostPerMonthMicroUSD int64 `json:"costPerMonthMicroUsd"`
|
||||
StoreDown bool `json:"storeDown,omitempty"`
|
||||
Limits *LimitsConfig `json:"limits,omitempty"`
|
||||
Kind string `json:"kind"`
|
||||
ID string `json:"id"`
|
||||
GroupName string `json:"groupName,omitempty"`
|
||||
// Groups is the user's full member group list (multi-group support)
|
||||
// — set only for a user entry, same "user-only" convention GroupName
|
||||
// above already follows. GroupName keeps the first group for
|
||||
// back-compat; Groups is the complete membership.
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Providers []string `json:"providers,omitempty"`
|
||||
Models []string `json:"models,omitempty"`
|
||||
MCPServers []string `json:"mcpServers,omitempty"`
|
||||
Agents []string `json:"agents,omitempty"`
|
||||
RequestsPerMinute int64 `json:"requestsPerMinute"`
|
||||
RequestsPerDay int64 `json:"requestsPerDay"`
|
||||
TokensInPerDay int64 `json:"tokensInPerDay"`
|
||||
TokensOutPerDay int64 `json:"tokensOutPerDay"`
|
||||
TokensInPerMonth int64 `json:"tokensInPerMonth"`
|
||||
TokensOutPerMonth int64 `json:"tokensOutPerMonth"`
|
||||
CostPerDayMicroUSD int64 `json:"costPerDayMicroUsd"`
|
||||
CostPerMonthMicroUSD int64 `json:"costPerMonthMicroUsd"`
|
||||
StoreDown bool `json:"storeDown,omitempty"`
|
||||
}
|
||||
|
||||
// adminUsageResponse is the full body of GET /admin/api/usage: every
|
||||
@@ -863,6 +868,7 @@ func (g *Gateway) buildAdminUsage() adminUsageResponse {
|
||||
for i, su := range userUsage {
|
||||
users[i] = usageEntryView(su, userSummaries[i].limits)
|
||||
users[i].GroupName = userSummaries[i].groupName
|
||||
users[i].Groups = userSummaries[i].groups
|
||||
}
|
||||
groups := make([]adminUsageEntryView, len(groupUsage))
|
||||
for i, su := range groupUsage {
|
||||
|
||||
Reference in New Issue
Block a user