From 81c6c6c7329235e8a807797c364524bb7f2ee778 Mon Sep 17 00:00:00 2001 From: Ali Date: Tue, 14 Apr 2026 02:21:45 +0500 Subject: [PATCH 1/2] config: guard against nil oauth2 credential in RoundTrip toSecret returns (nil, nil) when no source is configured. Most callers guarded the returned SecretReader with an `!= nil` check before invoking Fetch, but oauth2RoundTripper.RoundTrip reached directly into rt.oauthCredential.Immutable() and would nil-deref panic when someone supplied an oauth2 block with no client-secret source (likely the proximate cause of prometheus/prometheus#16622). Return a clear error instead of panicking, and document toSecret's nil-return contract so future callers explicitly acknowledge it. Fixes #790 Signed-off-by: Ali --- config/http_config.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/config/http_config.go b/config/http_config.go index 55cc5b07..84dd5a35 100644 --- a/config/http_config.go +++ b/config/http_config.go @@ -828,7 +828,10 @@ func (*refSecret) Immutable() bool { } // toSecret returns a SecretReader from one of the given sources, assuming exactly -// one or none of the sources are provided. +// one or none of the sources are provided. When no source is provided it +// returns (nil, nil); callers MUST guard the returned reader with a nil check +// before invoking any method on it — see the nil-deref issue tracked at +// https://github.com/prometheus/common/issues/790. func toSecret(secretManager SecretManager, text Secret, file, ref string) (SecretReader, error) { if text != "" { return NewInlineSecret(string(text)), nil @@ -1053,6 +1056,15 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro needsInit bool ) + // oauthCredential can be nil when the caller constructed an oauth2 + // config without any client-secret source (Secret/File/Ref all empty). + // That is an invalid config — oauth2 requires a client secret — but + // rather than panicking on the Immutable()/Fetch() calls below, surface + // it as a request-time error so the caller can see it. + if rt.oauthCredential == nil { + return nil, errors.New("oauth2 client secret is required") + } + rt.mtx.RLock() secret = rt.lastSecret needsInit = rt.lastRT.Source == nil From 974978ee5d55dbd6eb606b6e2b3be702a78d0ecf Mon Sep 17 00:00:00 2001 From: Ali Date: Wed, 15 Apr 2026 18:03:50 +0500 Subject: [PATCH 2/2] config: simplify comments per review feedback - toSecret: restore original one-line comment (no need to document nil-return semantics in the function comment) - oauth2RoundTripper.RoundTrip nil guard: replace verbose explanation with a single-line note matching reviewer's suggestion Signed-off-by: Ali --- config/http_config.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/config/http_config.go b/config/http_config.go index 84dd5a35..5cd6dc79 100644 --- a/config/http_config.go +++ b/config/http_config.go @@ -828,10 +828,7 @@ func (*refSecret) Immutable() bool { } // toSecret returns a SecretReader from one of the given sources, assuming exactly -// one or none of the sources are provided. When no source is provided it -// returns (nil, nil); callers MUST guard the returned reader with a nil check -// before invoking any method on it — see the nil-deref issue tracked at -// https://github.com/prometheus/common/issues/790. +// one or none of the sources are provided. func toSecret(secretManager SecretManager, text Secret, file, ref string) (SecretReader, error) { if text != "" { return NewInlineSecret(string(text)), nil @@ -1056,11 +1053,8 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro needsInit bool ) - // oauthCredential can be nil when the caller constructed an oauth2 - // config without any client-secret source (Secret/File/Ref all empty). - // That is an invalid config — oauth2 requires a client secret — but - // rather than panicking on the Immutable()/Fetch() calls below, surface - // it as a request-time error so the caller can see it. + // This should not happen when config goes through the normal Prometheus + // validation path, but guard against a nil credential to avoid a panic. if rt.oauthCredential == nil { return nil, errors.New("oauth2 client secret is required") }