fix(cabana): scope the token last_used_at throttle to the guard instance

- The process-global debounce map was keyed by token ID, so a stamp from one test database suppressed a later write in another and turned TestBackendTokenPostgres red depending on order
- Each compositeGuard now owns a stampThrottle; the backend guard and the ResolveBackend guard of one activation share it, so a single-app binary still writes last_used_at at most once a minute per token
- TestTokenLastUsedThrottlePerGuard pins the per-guard isolation
This commit is contained in:
2026-10-11 15:19:55 +02:00
parent 21fdcfcba6
commit b45af8ebbf
5 changed files with 74 additions and 15 deletions

View File

@@ -46,6 +46,8 @@ type compositeGuard struct {
store tokenStore
users bouncer.UserProvider
reg *Registry
// stamps debounces last_used_at writes for this guard (see stampThrottle).
stamps *stampThrottle
}
var (
@@ -54,7 +56,7 @@ var (
)
func newCompositeGuard(jwt bouncer.Guard, store tokenStore, users bouncer.UserProvider, reg *Registry) *compositeGuard {
return &compositeGuard{jwt: jwt, store: store, users: users, reg: reg}
return &compositeGuard{jwt: jwt, store: store, users: users, reg: reg, stamps: &stampThrottle{}}
}
func (g *compositeGuard) AuthenticateCredential(r *http.Request) (*bouncer.Principal, any, error) {
@@ -115,7 +117,7 @@ func (g *compositeGuard) authenticateToken(r *http.Request, raw string) (*bounce
return nil, nil, newScopeError()
}
principal.Scope = limit
stampLastUsed(r.Context(), g.store, row.ID, now)
stampLastUsed(r.Context(), g.stamps, g.store, row.ID, now)
logTokenAuth(r, "success", principal.ID, row.ID)
return principal, row, nil
}