Skip to content

Pr/key enabled switch upstream#422

Open
FLCnhzmry wants to merge 2 commits into
tbphp:mainfrom
FLCnhzmry:pr/key-enabled-switch-upstream
Open

Pr/key enabled switch upstream#422
FLCnhzmry wants to merge 2 commits into
tbphp:mainfrom
FLCnhzmry:pr/key-enabled-switch-upstream

Conversation

@FLCnhzmry

@FLCnhzmry FLCnhzmry commented Jun 6, 2026

Copy link
Copy Markdown

添加一个针对每个密钥的启用开关,用于控制活动密钥能否进入路由池,同时不改变现有的无效/黑名单状态逻辑。

Summary by CodeRabbit

  • New Features
    • Added an enable/disable toggle switch for each API key, allowing users to control whether keys are active in routing without deletion.
    • Disabled keys are automatically excluded from all routing operations.
    • New UI controls and labels added in English, Japanese, and Chinese.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR implements a complete API key enable/disable feature. Keys can be toggled between enabled and disabled states without deletion, controlling whether they participate in request routing. The implementation spans backend pool synchronization, HTTP API, and frontend UI with multi-language support.

Changes

API Key Enable/Disable Toggle

Layer / File(s) Summary
Data Model Enhancement
internal/models/types.go, web/src/types/models.ts
APIKey gains an Enabled boolean field (default true) persisted by GORM and exposed in JSON/TypeScript interfaces.
Backend Pool Availability Filtering
internal/keypool/provider.go
KeyProvider implements enabled-aware availability: SelectKey parses enabled state from store, handleSuccess and pool loading use isKeyAvailableForPool (checks both active status and enabled), new SetKeyEnabled method updates the database and removes/re-adds keys from the active pool based on eligibility.
Service Layer and HTTP Handler
internal/services/key_service.go, internal/handler/key_handler.go, internal/router/router.go
KeyService initializes enabled=true on key creation and delegates toggling to KeyProvider; new UpdateKeyEnabled handler parses route ID, binds request body, calls service, and returns updated key with error mapping; routes PUT /api/keys/:id/enabled.
Frontend API Client
web/src/api/keys.ts
keysApi.updateKeyEnabled issues PUT request to toggle enabled state with message suppression and returns response containing id, enabled, and status.
Frontend UI with Toggle Switch
web/src/components/keys/KeyTable.vue
Imports NSwitch, tracks toggling state per key, implements updateKeyEnabled with optimistic UI update and rollback logic; template applies is-disabled class and includes switch in status row; responsive layout refactoring and disabled-state opacity styling.
Internationalization
web/src/locales/en-US.ts, web/src/locales/ja-JP.ts, web/src/locales/zh-CN.ts
Six new i18n keys added across three languages: key enabled/disabled labels, routing switch label, enable/disable action text, and routing-disabled short form.

Sequence Diagram

sequenceDiagram
  participant User
  participant KeyTable
  participant keysApi
  participant UpdateKeyEnabled
  participant KeyService
  participant KeyProvider
  participant Redis
  participant Database
  User->>KeyTable: click toggle switch
  KeyTable->>KeyTable: optimistic: set key.enabled
  KeyTable->>keysApi: updateKeyEnabled(id, false)
  keysApi->>UpdateKeyEnabled: PUT /api/keys/:id/enabled {enabled: false}
  UpdateKeyEnabled->>KeyService: SetKeyEnabled(id, false)
  KeyService->>KeyProvider: SetKeyEnabled(id, false)
  KeyProvider->>Database: update key enabled field
  KeyProvider->>Redis: update hash enabled field
  KeyProvider->>Redis: remove from active_keys
  Redis-->>KeyProvider: deletion confirmed
  KeyProvider-->>KeyService: return updated key
  KeyService-->>UpdateKeyEnabled: return updated key
  UpdateKeyEnabled-->>keysApi: {id, enabled: false, status}
  keysApi-->>KeyTable: response
  KeyTable->>KeyTable: show success, trigger sync refresh
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

enhancement

Suggested reviewers

  • tbphp

Poem

🐰 A switch to toggle keys with grace,
No deletion, just a disabled space,
Through three tongues the labels sing,
Pool stays synced with everything! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is missing required sections from the template, including related issue number, checkboxes for change type, and self-review checklist. Fill in the complete template with issue number (Closes #...), select the change type checkbox, provide detailed description, and complete the self-review checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and uses non-descriptive terminology that doesn't clearly convey the main change to someone scanning history. Use a more descriptive title like 'Add per-key enabled switch for route pool control' to clearly summarize the feature being added.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot requested a review from tbphp June 6, 2026 19:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
web/src/components/keys/KeyTable.vue (1)

342-344: ⚡ Quick win

Consider showing an error message to the user when the toggle fails.

Currently, when the API call fails, the key's enabled state is rolled back (which provides visual feedback), but no error message is shown to the user—only a console log. Consider adding window.$message.error(...) in the catch block to inform the user why the toggle failed, similar to how other operations in this file handle errors.

💡 Suggested improvement
  } catch (error) {
    key.enabled = previousEnabled;
    console.error("Update key enabled failed", error);
+   window.$message.error(t("keys.updateEnabledFailed"));
  } finally {

Note: You'll need to add the corresponding i18n key updateEnabledFailed to the locale files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/keys/KeyTable.vue` around lines 342 - 344, In the catch
block that rolls back the toggle (the block containing "key.enabled =
previousEnabled" and "console.error('Update key enabled failed', error)") add a
user-facing error message via window.$message.error(...) (or the app's message
helper) using the i18n key "updateEnabledFailed" so users see why the toggle
failed; keep the existing rollback logic and console.error, and also add the
"updateEnabledFailed" entry to the locale files.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/handler/key_handler.go`:
- Around line 507-509: The UpdateKeyEnabledRequest struct currently uses Enabled
bool which treats a missing field as false; change it to Enabled *bool and
update the UpdateKeyEnabled handler to return a 400 Bad Request when req.Enabled
is nil (reject requests that omit enabled). Also locate the database error
handling in the same handler where it checks for "record not found" via string
matching and replace that with a proper errors.Is(err, gorm.ErrRecordNotFound)
check (or use app_errors.ParseDBError if preferred) to correctly detect wrapped
not-found errors.
- Around line 568-574: Replace the string-based not-found check in
UpdateKeyEnabled's error handling with a proper errors.Is check: after calling
s.KeyService.SetKeyEnabled, detect a missing record by using errors.Is(err,
gorm.ErrRecordNotFound) (and add the missing "errors" import and ensure "gorm"
is imported) and map that case to response.Error(c,
app_errors.ErrResourceNotFound); otherwise continue to call response.Error(c,
app_errors.ParseDBError(err)).

In `@internal/keypool/provider.go`:
- Around line 642-653: The active-list sync currently performs
p.store.HSet(keyHashKey, p.apiKeyToMap(&key)) before removing the key from the
active list, which can leave a disabled key in group:*:active_keys if LRem
fails; change the logic so that on the disable path you call
p.store.LRem(activeKeysListKey, 0, key.ID) first and return on error, then
update the hash with p.store.HSet; conversely, on the enable path update the
hash via p.store.HSet(...) first and only then call
p.store.LPush(activeKeysListKey, key.ID) (using isKeyAvailableForPool to decide
the push) while preserving the existing error messages and returns for
p.store.LRem, p.store.HSet and p.store.LPush.

---

Nitpick comments:
In `@web/src/components/keys/KeyTable.vue`:
- Around line 342-344: In the catch block that rolls back the toggle (the block
containing "key.enabled = previousEnabled" and "console.error('Update key
enabled failed', error)") add a user-facing error message via
window.$message.error(...) (or the app's message helper) using the i18n key
"updateEnabledFailed" so users see why the toggle failed; keep the existing
rollback logic and console.error, and also add the "updateEnabledFailed" entry
to the locale files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 267f700a-08a7-4366-89fa-2c56ab9ad5e2

📥 Commits

Reviewing files that changed from the base of the PR and between 5579930 and 15578a2.

📒 Files selected for processing (11)
  • internal/handler/key_handler.go
  • internal/keypool/provider.go
  • internal/models/types.go
  • internal/router/router.go
  • internal/services/key_service.go
  • web/src/api/keys.ts
  • web/src/components/keys/KeyTable.vue
  • web/src/locales/en-US.ts
  • web/src/locales/ja-JP.ts
  • web/src/locales/zh-CN.ts
  • web/src/types/models.ts

Comment on lines +507 to +509
type UpdateKeyEnabledRequest struct {
Enabled bool `json:"enabled"`
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="internal/handler/key_handler.go"

echo "== Context around UpdateKeyEnabledRequest =="
sed -n '470,650p' "$file" | nl -ba | sed -n '1,220p'

echo
echo "== Exact lines 500-590 (matches requested ranges) =="
sed -n '495,590p' "$file" | nl -ba

echo
echo "== Search for UpdateKeyEnabled and binding/error mapping =="
rg -n "UpdateKeyEnabled|ShouldBindJSON|record not found|strings\.Contains\(err\.Error|errors\.Is" "$file"

Repository: tbphp/gpt-load

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="internal/handler/key_handler.go"
if [ ! -f "$file" ]; then
  echo "Missing file: $file" >&2
  exit 1
fi

python3 - <<'PY'
import itertools

path = "internal/handler/key_handler.go"
start, end = 470, 650
with open(path, "r", encoding="utf-8") as f:
    for i, line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:5d}: {line.rstrip()}")
PY

echo
echo "== Search: UpdateKeyEnabled binding and error mapping =="
rg -n "UpdateKeyEnabledRequest|type UpdateKeyEnabledRequest|UpdateKeyEnabled\(|ShouldBindJSON|record not found|strings\.Contains\(|errors\.Is" "$file"

Repository: tbphp/gpt-load

Length of output: 5380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "SetKeyEnabled\\(" -S .
rg -n "type .*KeyService|KeyService" -S internal .
rg -n "record not found" -S .
rg -n "ParseDBError\\(" -S internal .

Repository: tbphp/gpt-load

Length of output: 16179


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show KeyService.SetKeyEnabled implementation
sed -n '230,320p' internal/services/key_service.go | cat

echo
echo "----"

# Show KeyProvider.SetKeyEnabled implementation
sed -n '580,720p' internal/keypool/provider.go | cat

echo
echo "----"

# Show ParseDBError implementation
sed -n '1,140p' internal/errors/errors.go | cat

Repository: tbphp/gpt-load

Length of output: 10432


Reject requests that omit enabled (UpdateKeyEnabled).
Enabled bool treats {} as enabled=false, causing an unintended disable; use *bool and return 400 when enabled is missing. Also replace the brittle strings.Contains(err.Error(), "record not found") check with errors.Is(err, gorm.ErrRecordNotFound) (or rely on app_errors.ParseDBError), since the provider wraps underlying GORM errors with %w.

Suggested fix
 type UpdateKeyEnabledRequest struct {
-	Enabled bool `json:"enabled"`
+	Enabled *bool `json:"enabled"`
 }
@@
 	var req UpdateKeyEnabledRequest
 	if err := c.ShouldBindJSON(&req); err != nil {
 		response.Error(c, app_errors.NewAPIError(app_errors.ErrInvalidJSON, err.Error()))
 		return
 	}
+	if req.Enabled == nil {
+		response.Error(c, app_errors.NewAPIError(app_errors.ErrBadRequest, "enabled is required"))
+		return
+	}
 
-	key, err := s.KeyService.SetKeyEnabled(uint(keyID), req.Enabled)
+	key, err := s.KeyService.SetKeyEnabled(uint(keyID), *req.Enabled)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/handler/key_handler.go` around lines 507 - 509, The
UpdateKeyEnabledRequest struct currently uses Enabled bool which treats a
missing field as false; change it to Enabled *bool and update the
UpdateKeyEnabled handler to return a 400 Bad Request when req.Enabled is nil
(reject requests that omit enabled). Also locate the database error handling in
the same handler where it checks for "record not found" via string matching and
replace that with a proper errors.Is(err, gorm.ErrRecordNotFound) check (or use
app_errors.ParseDBError if preferred) to correctly detect wrapped not-found
errors.

Comment on lines +568 to +574
key, err := s.KeyService.SetKeyEnabled(uint(keyID), req.Enabled)
if err != nil {
if strings.Contains(err.Error(), "record not found") {
response.Error(c, app_errors.ErrResourceNotFound)
} else {
response.Error(c, app_errors.ParseDBError(err))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print SetKeyEnabled implementation in internal/keypool/provider.go
file="internal/keypool/provider.go"
if [ -f "$file" ]; then
  echo "== $file =="
  # Print around function definition
  line=$(rg -n "func \\(p \\*KeyProvider\\) SetKeyEnabled\\b" "$file" | head -n1 | cut -d: -f1)
  if [ -n "${line:-}" ]; then
    start=$((line-30))
    end=$((line+120))
    sed -n "${start},${end}p" "$file" | nl -ba | sed -n '1,200p'
  else
    echo "SetKeyEnabled not found in $file"
  fi
else
  echo "File not found: $file"
fi

# Also inspect internal/services/key_service.go just in case it's implemented there
file2="internal/services/key_service.go"
if [ -f "$file2" ]; then
  echo "== $file2 =="
  line=$(rg -n "func \\(s \\*KeyService\\) SetKeyEnabled\\b" "$file2" | head -n1 | cut -d: -f1)
  if [ -n "${line:-}" ]; then
    start=$((line-20))
    end=$((line+80))
    sed -n "${start},${end}p" "$file2" | nl -ba | sed -n '1,200p'
  else
    echo "SetKeyEnabled not found in $file2"
  fi
else
  echo "File not found: $file2"
fi

Repository: tbphp/gpt-load

Length of output: 155


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# helper to print with line numbers (no nl dependency)
print_with_numbers() {
  local f="$1"; local start="$2"; local end="$3"
  local i=1
  awk -v s="$start" -v e="$end" 'NR>=s && NR<=e { printf "%5d\t%s\n", NR, $0 }' "$f"
}

file="internal/keypool/provider.go"
echo "== $file =="
if [ -f "$file" ]; then
  line=$(rg -n "func \\(p \\*KeyProvider\\) SetKeyEnabled\\b" "$file" | head -n1 | cut -d: -f1 || true)
  if [ -n "${line:-}" ]; then
    start=$((line-30))
    end=$((line+160))
    print_with_numbers "$file" "$start" "$end"
  else
    echo "SetKeyEnabled not found"
  fi
else
  echo "File not found: $file"
fi

file2="internal/services/key_service.go"
echo "== $file2 =="
if [ -f "$file2" ]; then
  line=$(rg -n "func \\(s \\*KeyService\\) SetKeyEnabled\\b" "$file2" | head -n1 | cut -d: -f1 || true)
  if [ -n "${line:-}" ]; then
    start=$((line-20))
    end=$((line+120))
    print_with_numbers "$file2" "$start" "$end"
  else
    echo "SetKeyEnabled not found"
  fi
else
  echo "File not found: $file2"
fi

Repository: tbphp/gpt-load

Length of output: 9725


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="internal/handler/key_handler.go"
echo "== $file (imports) =="
# Print import block (best-effort)
start=$(rg -n "^import \\(" "$file" | head -n1 | cut -d: -f1 || true)
if [ -n "${start:-}" ]; then
  # find closing paren
  end=$(awk -v s="$start" 'NR>=s{ if($0 ~ /^\\)/){ print NR; exit } }' "$file")
  sed -n "${start},${end}p" "$file" | nl -ba | head -n 200
else
  echo "No multi-line import block found"
fi

echo
echo "== $file (around SetKeyEnabled handler error mapping) =="
# Print around provided line numbers
sed -n '540,610p' "$file" | nl -ba | sed -n '1,200p'

Repository: tbphp/gpt-load

Length of output: 214


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="internal/handler/key_handler.go"

echo "== $file (import block) =="
# find import block start
start=$(rg -n "^import \\(" "$file" | head -n1 | cut -d: -f1 || true)
if [ -z "${start:-}" ]; then
  # single-line import fallback
  rg -n "^import " "$file" | head -n 50
else
  end=$(awk -v s="$start" 'NR>=s{ if($0 ~ /^\\)/){ print NR; exit } }' "$file")
  awk -v s="$start" -v e="$end" 'NR>=s && NR<=e { printf "%5d\t%s\n", NR, $0 }' "$file"
fi

echo
echo "== $file (around SetKeyEnabled mapping) =="
awk 'NR>=540 && NR<=610 { printf "%5d\t%s\n", NR, $0 }' "$file"

Repository: tbphp/gpt-load

Length of output: 1544


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="internal/handler/key_handler.go"
awk 'NR<=140 { printf "%5d\t%s\n", NR, $0 }' "$file" | sed -n '1,140p'

Repository: tbphp/gpt-load

Length of output: 5124


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="internal/handler/key_handler.go"
echo "== search for errors import/usages =="
rg -n "\"errors\"" "$file" || true
rg -n "\berrors\." "$file" || true

Repository: tbphp/gpt-load

Length of output: 96


Use errors.Is for the not-found mapping.

UpdateKeyEnabled maps not-found by checking strings.Contains(err.Error(), "record not found"), but KeyProvider.SetKeyEnabled wraps the underlying GORM error with %w, so a stable check is errors.Is(err, gorm.ErrRecordNotFound) (and add the missing errors import).

Suggested fix
 import (
+	"errors"
 	"fmt"
 	app_errors "gpt-load/internal/errors"
@@
 	key, err := s.KeyService.SetKeyEnabled(uint(keyID), req.Enabled)
 	if err != nil {
-		if strings.Contains(err.Error(), "record not found") {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
 			response.Error(c, app_errors.ErrResourceNotFound)
 		} else {
 			response.Error(c, app_errors.ParseDBError(err))
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
key, err := s.KeyService.SetKeyEnabled(uint(keyID), req.Enabled)
if err != nil {
if strings.Contains(err.Error(), "record not found") {
response.Error(c, app_errors.ErrResourceNotFound)
} else {
response.Error(c, app_errors.ParseDBError(err))
}
key, err := s.KeyService.SetKeyEnabled(uint(keyID), req.Enabled)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
response.Error(c, app_errors.ErrResourceNotFound)
} else {
response.Error(c, app_errors.ParseDBError(err))
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/handler/key_handler.go` around lines 568 - 574, Replace the
string-based not-found check in UpdateKeyEnabled's error handling with a proper
errors.Is check: after calling s.KeyService.SetKeyEnabled, detect a missing
record by using errors.Is(err, gorm.ErrRecordNotFound) (and add the missing
"errors" import and ensure "gorm" is imported) and map that case to
response.Error(c, app_errors.ErrResourceNotFound); otherwise continue to call
response.Error(c, app_errors.ParseDBError(err)).

Comment on lines +642 to +653
if err := p.store.HSet(keyHashKey, p.apiKeyToMap(&key)); err != nil {
return fmt.Errorf("failed to update key enabled flag in store: %w", err)
}

if err := p.store.LRem(activeKeysListKey, 0, key.ID); err != nil {
return fmt.Errorf("failed to LRem key from active list: %w", err)
}

if isKeyAvailableForPool(&key) {
if err := p.store.LPush(activeKeysListKey, key.ID); err != nil {
return fmt.Errorf("failed to LPush key to active list: %w", err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail closed when syncing the active pool on disable.

This updates the hash before removing the key from group:*:active_keys. If HSet succeeds and LRem fails, this call returns an error but the list still contains the key, so SelectKey can keep routing a supposedly disabled key. Remove from the active list first on the disable path, and only LPush after the hash says enabled on the enable path.

Suggested direction
-		if err := p.store.HSet(keyHashKey, p.apiKeyToMap(&key)); err != nil {
-			return fmt.Errorf("failed to update key enabled flag in store: %w", err)
-		}
-
-		if err := p.store.LRem(activeKeysListKey, 0, key.ID); err != nil {
-			return fmt.Errorf("failed to LRem key from active list: %w", err)
-		}
-
-		if isKeyAvailableForPool(&key) {
+		if !enabled {
+			if err := p.store.LRem(activeKeysListKey, 0, key.ID); err != nil {
+				return fmt.Errorf("failed to LRem key from active list: %w", err)
+			}
+		}
+
+		if err := p.store.HSet(keyHashKey, p.apiKeyToMap(&key)); err != nil {
+			return fmt.Errorf("failed to update key enabled flag in store: %w", err)
+		}
+
+		if enabled && isKeyAvailableForPool(&key) {
 			if err := p.store.LPush(activeKeysListKey, key.ID); err != nil {
 				return fmt.Errorf("failed to LPush key to active list: %w", err)
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/keypool/provider.go` around lines 642 - 653, The active-list sync
currently performs p.store.HSet(keyHashKey, p.apiKeyToMap(&key)) before removing
the key from the active list, which can leave a disabled key in
group:*:active_keys if LRem fails; change the logic so that on the disable path
you call p.store.LRem(activeKeysListKey, 0, key.ID) first and return on error,
then update the hash with p.store.HSet; conversely, on the enable path update
the hash via p.store.HSet(...) first and only then call
p.store.LPush(activeKeysListKey, key.ID) (using isKeyAvailableForPool to decide
the push) while preserving the existing error messages and returns for
p.store.LRem, p.store.HSet and p.store.LPush.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant