mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-16 05:37:28 +00:00
fix(auth): non-blocking reload check, stat-before-load, mtime inequality trigger
- users_file.go: maybeReload uses reloadMu.TryLock() instead of Lock(). A full reload (stat+read+parse+replaceFileUsers, incl. per-user resolveSecret file reads) could otherwise block every concurrent ServeHTTP request for its whole duration, negating the buildMu/mu lock split. A request that finds a reload in flight now skips this cycle; reload stays throttled and best-effort. - users_file.go: mtime check changed from ModTime().After(lastModTime) to ModTime().Equal(lastModTime), so a backward mtime move (restore from backup, cp -p) still triggers a reload instead of being skipped. Added a regression test with os.Chtimes into the past. - llmgateway.go: attachUsersFile now stats the file before loading it, matching maybeReload's ordering, so a write landing between stat and load is caught on the next check instead of being lost. Documented why the ignored statErr is safe (falls back to zero lastModTime, causing one harmless extra reload).
This commit is contained in:
@@ -271,6 +271,28 @@ func TestAuthStore_MaybeReload_UnchangedMtime_DoesNotReload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestAuthStore_MaybeReload_BackwardMtimeMove_TriggersReload is the
|
||||
// regression for the Equal-vs-After mtime check: a file restored from a
|
||||
// backup, or copied with `cp -p` from an older file, can move the mtime
|
||||
// backward. That must still trigger a reload — only an mtime equal to the
|
||||
// last observed one may skip it.
|
||||
func TestAuthStore_MaybeReload_BackwardMtimeMove_TriggersReload(t *testing.T) {
|
||||
a, fp, _, clock := newReloadableAuthStore(t, nil, []*UserConfig{{Name: "f1", Group: "eng", APIKey: "sk-f1"}})
|
||||
|
||||
past := time.Now().Add(-time.Hour)
|
||||
writeUsersDoc(t, fp, []*UserConfig{{Name: "f2", Group: "eng", APIKey: "sk-f2"}}, past)
|
||||
|
||||
clock.Advance(reloadEvery + time.Second)
|
||||
a.maybeReload()
|
||||
|
||||
if _, _, ok := identifyWithKey(a, "sk-f2"); !ok {
|
||||
t.Fatal("want a backward mtime move to still trigger a reload")
|
||||
}
|
||||
if _, _, ok := identifyWithKey(a, "sk-f1"); ok {
|
||||
t.Fatal("want f1 no longer identifiable once the backward-mtime reload replaced the file-sourced set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthStore_MaybeReload_UserCountChange_LogsViaLogf(t *testing.T) {
|
||||
a, fp, log, clock := newReloadableAuthStore(t, nil, []*UserConfig{{Name: "f1", Group: "eng", APIKey: "sk-f1"}})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user