diff --git a/dynamic_client_registration.go b/dynamic_client_registration.go index 7da699d..a5199c8 100644 --- a/dynamic_client_registration.go +++ b/dynamic_client_registration.go @@ -374,7 +374,7 @@ func (r *DynamicClientRegistrar) saveCredentialsToStore(ctx context.Context, res func (r *DynamicClientRegistrar) saveCredentials(resp *ClientRegistrationResponse) error { filePath := r.credentialsFilePath() - data, err := json.MarshalIndent(resp, "", " ") + data, err := json.MarshalIndent(resp, "", " ") //nolint:gosec // registration response incl. client_secret is the API output if err != nil { return fmt.Errorf("failed to marshal credentials: %w", err) } diff --git a/helpers.go b/helpers.go index f6c17b1..ea5e58c 100644 --- a/helpers.go +++ b/helpers.go @@ -163,7 +163,7 @@ func (t *TraefikOidc) exchangeTokens(ctx context.Context, grantType string, code data.Set("client_secret", t.clientSecret) } - req, err := http.NewRequestWithContext(ctx, "POST", tokenURL, strings.NewReader(data.Encode())) + req, err := http.NewRequestWithContext(ctx, "POST", tokenURL, strings.NewReader(data.Encode())) //nolint:gosec // tokenURL is the operator-trusted discovery endpoint (metadataMu) if err != nil { return nil, fmt.Errorf("failed to create token request: %w", err) } @@ -172,7 +172,7 @@ func (t *TraefikOidc) exchangeTokens(ctx context.Context, grantType string, code setOAuthBasicAuth(req, t.clientID, t.clientSecret) } - resp, err := client.Do(req) + resp, err := client.Do(req) //nolint:gosec // req above targets the trusted tokenURL if err != nil { return nil, fmt.Errorf("failed to exchange tokens: %w", err) } diff --git a/internal/dcrstorage/file.go b/internal/dcrstorage/file.go index 61e46af..6fdf554 100644 --- a/internal/dcrstorage/file.go +++ b/internal/dcrstorage/file.go @@ -78,7 +78,7 @@ func (s *FileStore) Save(ctx context.Context, providerURL string, creds *ClientR return fmt.Errorf("failed to create credentials directory: %w", err) } - data, err := json.MarshalIndent(creds, "", " ") + data, err := json.MarshalIndent(creds, "", " ") //nolint:gosec // ClientSecret must be persisted; creds are the feature's output if err != nil { return fmt.Errorf("failed to marshal credentials: %w", err) } diff --git a/internal/dcrstorage/redis.go b/internal/dcrstorage/redis.go index f72707a..6f844be 100644 --- a/internal/dcrstorage/redis.go +++ b/internal/dcrstorage/redis.go @@ -86,7 +86,7 @@ func (s *RedisStore) Save(ctx context.Context, providerURL string, creds *Client } // Serialize credentials to JSON for storage - data, err := json.Marshal(creds) + data, err := json.Marshal(creds) //nolint:gosec // secret intentionally serialized for Redis storage if err != nil { return fmt.Errorf("failed to marshal credentials: %w", err) } diff --git a/internal/pool/transport.go b/internal/pool/transport.go index 68cfea7..b60226e 100644 --- a/internal/pool/transport.go +++ b/internal/pool/transport.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "net" "net/http" + "strconv" "sync" "sync/atomic" "time" @@ -246,9 +247,15 @@ func (p *TransportPool) configKey(config TransportConfig) string { sb := Get().GetStringBuilder() defer Get().PutStringBuilder(sb) - sb.WriteByte(byte(config.MaxConnsPerHost)) - sb.WriteByte(byte(config.MaxIdleConnsPerHost)) - sb.WriteByte(byte(config.MaxIdleConns)) + // Write the int fields verbatim, not byte()s: a config value >=256 would + // otherwise truncate and make two distinct configs collide on one key, + // silently sharing a single transport with the wrong settings. + sb.WriteString(strconv.Itoa(config.MaxConnsPerHost)) + sb.WriteByte('|') + sb.WriteString(strconv.Itoa(config.MaxIdleConnsPerHost)) + sb.WriteByte('|') + sb.WriteString(strconv.Itoa(config.MaxIdleConns)) + sb.WriteByte('|') if config.ForceHTTP2 { sb.WriteByte(1) } else { diff --git a/internal/pool/utils.go b/internal/pool/utils.go index 2487df3..fef76b7 100644 --- a/internal/pool/utils.go +++ b/internal/pool/utils.go @@ -14,7 +14,7 @@ func BuildSessionName(baseName string, index int) string { sb.WriteRune('_') // Efficient int to string conversion if index < 10 { - sb.WriteRune('0' + rune(index)) + sb.WriteRune('0' + rune(index)) //nolint:gosec // index is bounded by the short alphabet size } else { sb.WriteString(intToString(index)) } diff --git a/internal/testutil/servers/oidc.go b/internal/testutil/servers/oidc.go index 7ace266..051d70f 100644 --- a/internal/testutil/servers/oidc.go +++ b/internal/testutil/servers/oidc.go @@ -279,7 +279,7 @@ func (s *OIDCServer) handleAuthorize(w http.ResponseWriter, r *http.Request) { } redirectURL := fmt.Sprintf("%s?code=test-auth-code&state=%s", redirectURI, state) - http.Redirect(w, r, redirectURL, http.StatusFound) + http.Redirect(w, r, redirectURL, http.StatusFound) //nolint:gosec // mock IdP redirects to its configured (trusted) endpoint } func (s *OIDCServer) handleUserinfo(w http.ResponseWriter, r *http.Request) { @@ -342,7 +342,7 @@ func (s *OIDCServer) handleLogout(w http.ResponseWriter, r *http.Request) { http.Error(w, "invalid post_logout_redirect_uri", http.StatusBadRequest) return } - http.Redirect(w, r, postLogoutRedirect, http.StatusFound) + http.Redirect(w, r, postLogoutRedirect, http.StatusFound) //nolint:gosec // mock IdP post-logout redirect return } diff --git a/internal/testutil/suite.go b/internal/testutil/suite.go index f20803b..69f8e7f 100644 --- a/internal/testutil/suite.go +++ b/internal/testutil/suite.go @@ -72,7 +72,7 @@ func (s *OIDCSuite) NewRequest(method, path string) *http.Request { // NewRequestWithCookie creates a request with a session cookie func (s *OIDCSuite) NewRequestWithCookie(method, path, cookieName, cookieValue string) *http.Request { req := s.NewRequest(method, path) - req.AddCookie(&http.Cookie{ + req.AddCookie(&http.Cookie{ //nolint:gosec // test cookie on an httptest request Name: cookieName, Value: cookieValue, }) diff --git a/refresh_coordinator.go b/refresh_coordinator.go index 77b4c32..ca14ba2 100644 --- a/refresh_coordinator.go +++ b/refresh_coordinator.go @@ -229,7 +229,7 @@ func (rc *RefreshCoordinator) CoordinateRefresh( if isNew { // We created a new operation, so we need to execute it - go rc.executeRefreshAsync(operation, sessionID, tokenHash, refreshFunc) + go rc.executeRefreshAsync(operation, sessionID, tokenHash, refreshFunc) //nolint:gosec // long-lived background refresh intentionally uses a background context } else { // Joined existing operation - this is a deduplicated request atomic.AddInt64(&rc.metrics.deduplicatedRequests, 1) diff --git a/session.go b/session.go index f34dcec..adf0cdd 100644 --- a/session.go +++ b/session.go @@ -1007,7 +1007,7 @@ func (sm *SessionManager) CleanupOldCookies(w http.ResponseWriter, r *http.Reque continue } - deleteCookie := &http.Cookie{ + deleteCookie := &http.Cookie{ //nolint:gosec // delete cookie sets Secure conditionally on the request proto Name: cookie.Name, Value: "", Path: "/",