(t *testing.T)
| 849 | } |
| 850 | |
| 851 | func TestValidateToken(t *testing.T) { |
| 852 | t.Parallel() |
| 853 | |
| 854 | // These tests use httptest.NewServer to control response headers |
| 855 | // (X-RateLimit-Remaining, Retry-After) that the FakeIDP's |
| 856 | // WithDynamicUserInfo hook does not expose. |
| 857 | |
| 858 | newValidateConfig := func(t *testing.T, validateURL string) *externalauth.Config { |
| 859 | t.Helper() |
| 860 | f := promoauth.NewFactory(prometheus.NewRegistry()) |
| 861 | return &externalauth.Config{ |
| 862 | InstrumentedOAuth2Config: f.New("test-validate", &oauth2.Config{}), |
| 863 | ID: "test-validate", |
| 864 | Type: codersdk.EnhancedExternalAuthProviderGitHub.String(), |
| 865 | ValidateURL: validateURL, |
| 866 | } |
| 867 | } |
| 868 | |
| 869 | newToken := func() *oauth2.Token { |
| 870 | return &oauth2.Token{ |
| 871 | AccessToken: "test-access-token", |
| 872 | Expiry: time.Now().Add(time.Hour), |
| 873 | } |
| 874 | } |
| 875 | |
| 876 | // newValidateCtx returns a context carrying a dedicated http.Client per |
| 877 | // subtest. Without this, parallel subtests share http.DefaultTransport, |
| 878 | // and httptest.Server.Close() calls http.DefaultTransport.CloseIdleConnections |
| 879 | // which can break in-flight requests of sibling subtests. |
| 880 | newValidateCtx := func(t *testing.T) context.Context { |
| 881 | t.Helper() |
| 882 | tp := &http.Transport{} |
| 883 | t.Cleanup(tp.CloseIdleConnections) |
| 884 | return oidc.ClientContext(context.Background(), &http.Client{Transport: tp}) |
| 885 | } |
| 886 | |
| 887 | // RateLimitRemaining: 403 with X-RateLimit-Remaining: 0 should be |
| 888 | // treated as rate-limited, not as an invalid token. |
| 889 | t.Run("RateLimitRemaining", func(t *testing.T) { |
| 890 | t.Parallel() |
| 891 | |
| 892 | srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
| 893 | w.Header().Set("X-RateLimit-Remaining", "0") |
| 894 | w.Header().Set("X-RateLimit-Limit", "5000") |
| 895 | w.WriteHeader(http.StatusForbidden) |
| 896 | })) |
| 897 | t.Cleanup(srv.Close) |
| 898 | |
| 899 | config := newValidateConfig(t, srv.URL) |
| 900 | valid, user, err := config.ValidateToken(newValidateCtx(t), newToken()) |
| 901 | |
| 902 | require.NoError(t, err) |
| 903 | assert.True(t, valid, "rate-limited 403 should be treated as optimistically valid") |
| 904 | assert.Nil(t, user) |
| 905 | }) |
| 906 | |
| 907 | // RetryAfter: 403 with Retry-After header (secondary rate limit) |
| 908 | // should be treated as rate-limited. |
nothing calls this directly
no test coverage detected