From 10e65d17a660a992beba8ec3d233d3d3206c7a6d Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Tue, 20 Oct 2026 23:34:38 +0200 Subject: [PATCH] test(scheduledauth): tolerate go-oidc's in-flight JWKS reuse in the failed-refresh test go-oidc's RemoteKeySet.keysFromRemote marks the in-flight fetch done before it takes the lock and clears r.inflight (oidc/jwks.go:196-234, v3.18.0). A Validate that starts right after the previous one returned can still see the finished in-flight fetch and reuse its cached error without a new HTTP request, so "every token causes a fetch" is not guaranteed by the library and the test failed on Linux CI. The invariant under test is that a failed refresh does not put the kid in the negative cache. Require a fetch per token within a bounded 2s retry instead, with every call still returning ErrUnauthorized, and keep the final negative-cache-empty assertion. Co-Authored-By: Claude Opus 5.5 --- internal/server/scheduledauth/kidguard_test.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/internal/server/scheduledauth/kidguard_test.go b/internal/server/scheduledauth/kidguard_test.go index 72ab4dde0..da00756ae 100644 --- a/internal/server/scheduledauth/kidguard_test.go +++ b/internal/server/scheduledauth/kidguard_test.go @@ -200,12 +200,20 @@ func TestValidate_OIDC_FailedRefreshDoesNotCacheKid(t *testing.T) { failing.Store(true) bad := signedFor(t, keyX, t0) for i := 0; i < 3; i++ { + // go-oidc's keysFromRemote marks the in-flight fetch done before it + // clears r.inflight (jwks.go:196-234), so a back-to-back Validate can + // reuse the finished fetch without a new request. Retry until one + // fetch happens; every call must still fail closed. before := hits.Load() - if err := v.Validate(context.Background(), bad); !errors.Is(err, ErrUnauthorized) { - t.Fatalf("token %d: expected ErrUnauthorized, got %v", i, err) - } - if hits.Load() == before { - t.Fatalf("token %d: no JWKS fetch although no refresh ever confirmed the kid unknown", i) + deadline := time.Now().Add(2 * time.Second) + for hits.Load() == before { + if err := v.Validate(context.Background(), bad); !errors.Is(err, ErrUnauthorized) { + t.Fatalf("token %d: expected ErrUnauthorized, got %v", i, err) + } + if time.Now().After(deadline) { + t.Fatalf("token %d: no JWKS fetch within 2s although no refresh ever confirmed the kid unknown", i) + } + time.Sleep(5 * time.Millisecond) } } if n := negativeKidCount(v); n != 0 {