fix(grok): clear golangci-lint findings on complete-integration branch

Check Close/CloseNow errors, drop unused helpers and dead constants,
lowercase ST1005 error strings, and stop discarding unwrap status as an
unused assignment so CI golangci-lint passes.
This commit is contained in:
IanShaw027
2026-08-08 12:56:40 +08:00
parent 1f58e25ab3
commit cec922d335
12 changed files with 13 additions and 122 deletions
+1 -1
View File
@@ -81,7 +81,7 @@ func (h *OpenAIGatewayHandler) GrokRealtime(c *gin.Context) {
if err != nil {
return
}
defer conn.CloseNow()
defer func() { _ = conn.CloseNow() }()
model := c.Query("model")
if strings.TrimSpace(model) == "" {
-20
View File
@@ -1359,26 +1359,6 @@ func (a *Account) GetGrokBaseURLOr(defaultBaseURL string) string {
return defaultBaseURL
}
func isOfficialGrokAPIBaseURL(raw string) bool {
return isOfficialGrokBaseURL(raw, xai.DefaultBaseURL)
}
func isOfficialGrokBaseURL(raw, expected string) bool {
parsed, err := url.Parse(strings.TrimSpace(raw))
if err != nil || parsed == nil || parsed.Opaque != "" || parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" {
return false
}
want, err := url.Parse(expected)
if err != nil || !strings.EqualFold(parsed.Scheme, want.Scheme) || !strings.EqualFold(parsed.Hostname(), want.Hostname()) {
return false
}
if port := parsed.Port(); port != "" && port != "443" {
return false
}
path := strings.TrimRight(parsed.Path, "/")
return path == "" || path == strings.TrimRight(want.Path, "/")
}
// GetGrokMediaBaseURL selects the upstream used by Grok Imagine APIs.
// The subscription CLI gateway enforces a small request-body limit that
// rejects large Base64 media payloads, so OAuth media leaves for api.x.ai
@@ -1,18 +0,0 @@
package service
import (
"context"
"fmt"
)
type accountSchedulingThresholdSnapshotCleaner interface {
ClearAccountSchedulingThresholdSnapshots(ctx context.Context, id int64) error
}
func clearAccountSchedulingThresholdSnapshots(ctx context.Context, repo AccountRepository, id int64) error {
cleaner, ok := repo.(accountSchedulingThresholdSnapshotCleaner)
if !ok {
return fmt.Errorf("account repository does not support account scheduling threshold snapshot cleanup")
}
return cleaner.ClearAccountSchedulingThresholdSnapshots(ctx, id)
}
@@ -1,21 +0,0 @@
//go:build unit
package service
import (
"context"
"testing"
"github.com/stretchr/testify/require"
)
type missingThresholdSnapshotCleanerRepo struct {
AccountRepository
}
func TestClearAccountSchedulingThresholdSnapshots_RequiresRepositorySupport(t *testing.T) {
err := clearAccountSchedulingThresholdSnapshots(context.Background(), missingThresholdSnapshotCleanerRepo{}, 1)
require.Error(t, err)
require.Contains(t, err.Error(), "does not support account scheduling threshold snapshot cleanup")
}
@@ -903,23 +903,23 @@ func (s *AccountTestService) grokTestAccessToken(ctx context.Context, account *A
switch account.Type {
case AccountTypeOAuth:
if s.grokTokenProvider == nil {
return "", fmt.Errorf("Grok token provider not configured")
return "", fmt.Errorf("grok token provider not configured")
}
// Manual tests skip production scheduling eligibility so paused/rate-limited
// accounts can still be probed by admins (same as Codex/OpenAI tests).
token, err := s.grokTokenProvider.GetAccessTokenForManualTest(ctx, account)
if err != nil {
return "", fmt.Errorf("Failed to get Grok access token: %s", err.Error())
return "", fmt.Errorf("failed to get grok access token: %s", err.Error())
}
return token, nil
case AccountTypeAPIKey:
authToken := strings.TrimSpace(account.GetCredential("api_key"))
if authToken == "" {
return "", fmt.Errorf("Grok API key is missing")
return "", fmt.Errorf("grok api key is missing")
}
return authToken, nil
default:
return "", fmt.Errorf("Unsupported Grok account type: %s", account.Type)
return "", fmt.Errorf("unsupported grok account type: %s", account.Type)
}
}
@@ -24,12 +24,7 @@ import (
// Soft-gate applies only to *explicit* free OAuth (subscription_tier/plan_type ==
// "free"). Media/cache free detection uses isKnownGrokFreeAccount instead.
// Admin paths (QueryQuota / import probe) never call this filter.
const (
defaultGrokFreeQuotaTokenLimit int64 = 500_000
defaultGrokFreeQuotaSoftGatePercent = 95
defaultGrokFreeQuotaWindowHours = 24
)
// Defaults live on config.Gateway.Grok (see config load defaults / tests).
type GrokFreeQuotaPolicy struct {
Enabled bool `json:"enabled"`
-12
View File
@@ -525,18 +525,6 @@ func isOfficialGrokVideoStatusDone(statusBody []byte) bool {
return strings.EqualFold(strings.TrimSpace(gjson.GetBytes(statusBody, "status").String()), "done")
}
// extractGrokVideoStatusContentURL returns official video.url when present.
// Kept for content/proxy helpers that still accept rewritten proxy paths after rewrite.
func extractGrokVideoStatusContentURL(body []byte) string {
if len(body) == 0 || !gjson.ValidBytes(body) {
return ""
}
if u := strings.TrimSpace(gjson.GetBytes(body, "video.url").String()); u != "" {
return u
}
return ""
}
// ExtractGrokVideoBillingFromStatusBody builds usage units from an official done status.
// Field priority (official docs):
// - duration: video.duration (seconds)
@@ -119,7 +119,7 @@ func (s *GrokQuotaService) syncGrokObservedModels(ctx context.Context, account *
if err != nil {
return err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return err
+1 -1
View File
@@ -70,7 +70,7 @@ func TestAccountGrokNeedsReauth(t *testing.T) {
}))
require.True(t, accountGrokNeedsReauth(&Account{
Status: StatusError,
ErrorMessage: grokSpendingLimitErrorMessage,
ErrorMessage: "Grok spending limit reached; reauthorize or wait for billing reset",
}))
}
@@ -2,7 +2,6 @@ package service
import (
"context"
"log/slog"
"strings"
"time"
)
@@ -10,11 +9,8 @@ import (
// Spending-limit is recoverable at the end of the observed billing period.
// When no billing snapshot is available, use a short probe rather than
// fabricating a 24h boundary from the error arrival time.
const grokSpendingLimitCooldown = 24 * time.Hour
const grokSpendingLimitProbeCooldown = 10 * time.Minute
const grokSpendingLimitErrorMessage = "Grok spending limit reached; reauthorize or wait for billing reset"
func grokSpendingLimitResetAt(account *Account, now time.Time) time.Time {
if account != nil {
if billing, err := grokBillingSnapshotFromExtra(account.Extra); err == nil && billing != nil {
@@ -28,29 +24,6 @@ func grokSpendingLimitResetAt(account *Account, now time.Time) time.Time {
return now.Add(grokSpendingLimitProbeCooldown)
}
// markGrokSpendingLimitReauth applies a long temp-unsched cool and durable
// SetError so ops sees reauth-required without wiping OAuth credentials.
func (s *OpenAIGatewayService) markGrokSpendingLimitReauth(ctx context.Context, account *Account) {
if s == nil || account == nil || account.IsPoolMode() {
return
}
s.tempUnscheduleGrok(ctx, account, grokSpendingLimitCooldown, "grok spending limit")
if s.accountRepo == nil {
return
}
stateCtx, cancel := openAIAccountStateContext(ctx)
defer cancel()
if err := s.accountRepo.SetError(stateCtx, account.ID, grokSpendingLimitErrorMessage); err != nil {
slog.Warn("grok_spending_limit_set_error_failed", "account_id", account.ID, "error", err)
}
// Soft flag in extra for UI / usage fetcher without requiring status poll.
_ = s.accountRepo.UpdateExtra(stateCtx, account.ID, map[string]any{
"grok_needs_reauth": true,
"grok_needs_reauth_reason": "spending_limit",
"grok_needs_reauth_at": time.Now().UTC().Format(time.RFC3339),
})
}
// clearGrokNeedsReauthExtra drops the soft reauth flag after successful refresh
// or reauth. Best-effort; never fails the request path.
func clearGrokNeedsReauthExtra(ctx context.Context, repo AccountRepository, accountID int64) {
@@ -50,9 +50,8 @@ type GrokUpstreamFailureDecision struct {
}
var (
reGrokTokenPair = regexp.MustCompile(`(?i)tokens?\s*(?:\(actual\s*/\s*limit\))?\s*[:=]?\s*(\d+)\s*/\s*(\d+)`)
reGrokModelFor = regexp.MustCompile(`(?i)(?:for\s+model|model|模型)\s*[:]?\s*([a-z0-9][a-z0-9._-]{2,80})`)
reGrokResetsWindow = regexp.MustCompile(`(?i)resets?\s+over\s+a\s+rolling\s+(\d+)\s*-\s*hour`)
reGrokTokenPair = regexp.MustCompile(`(?i)tokens?\s*(?:\(actual\s*/\s*limit\))?\s*[:=]?\s*(\d+)\s*/\s*(\d+)`)
reGrokModelFor = regexp.MustCompile(`(?i)(?:for\s+model|model|模型)\s*[:]?\s*([a-z0-9][a-z0-9._-]{2,80})`)
)
// classifyGrokUpstreamFailure decides cooldown/failover from status + body.
@@ -166,11 +165,10 @@ func classifyGrokUpstreamFailure(statusCode int, responseBody []byte, requestedM
}
func grokUpstreamErrorCorpus(statusCode int, responseBody []byte) (text, code, low string) {
_ = statusCode // classifier already has the transport status; corpus is body-only
raw := strings.TrimSpace(string(responseBody))
if unwrappedStatus, unwrappedBody, ok := unwrapGrokUpstreamErrorText(raw); ok {
if statusCode <= 0 {
statusCode = unwrappedStatus
}
// Strip "upstream status NNN: ..." prefixes so free-usage / quota language is visible.
if _, unwrappedBody, ok := unwrapGrokUpstreamErrorText(raw); ok {
raw = unwrappedBody
}
text = raw
@@ -14,10 +14,6 @@ import (
// tests. Current requests use the pinned default UA from this package.
const grokUpstreamUserAgent = "sub2api-grok/1.0"
// defaultBrowserLikeUpstreamUserAgent remains available for non-Grok OpenAI-like
// fingerprint templates that historically shared this constant.
const defaultBrowserLikeUpstreamUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
// Fixed CLI identity aliases — single source of truth is internal/pkg/xai.
const (
grokClientVersionHeader = xai.CLIStableVersion