fix(api): accept blockedModels in the key permissions schema - #13666
Merged
diegosouzapw merged 2 commits intoSep 17, 2026
Merged
diegosouzapw merged 2 commits into
diegosouzapw merged 2 commits into
Conversation
`PATCH /api/keys/[id]` already destructures `blockedModels`, forwards it into the update payload, and `updateApiKeyPermissions()` writes it to the `blocked_models` column. Only the first link was missing: `updateKeyPermissionsSchema` never declared the field, so Zod stripped it from the parsed body and the destructured value was always `undefined`. The request answered 200 and wrote nothing. The API Manager permissions modal sends `blockedModels` on every save (ApiManagerPageClient.tsx), so the Claude-Code family-blocking control silently did nothing and an existing deny-list could not be cleared. `blockedModels` is the deny-list half of the model policy — read by `isModelAllowedForKey()` before the allow-list and winning over it — so that half was only reachable by editing the database by hand. Declare the field mirroring `allowedModels` (trimmed, non-empty, max 1000) and count it in the "No valid fields to update" guard so a body carrying only `blockedModels` is a valid update. Left out of `createKeySchema` deliberately: the create route does not read `blockedModels`, so declaring it there would be dead weight.
Owner
|
Thanks for this — nice catch and a clean, minimal fix. Confirmed on the current release tip |
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Contributor
Author
|
Added the changelog fragment in commit |
4 of 5 tasks
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…uzapw#13666) * fix(api): accept blockedModels in the key permissions schema `PATCH /api/keys/[id]` already destructures `blockedModels`, forwards it into the update payload, and `updateApiKeyPermissions()` writes it to the `blocked_models` column. Only the first link was missing: `updateKeyPermissionsSchema` never declared the field, so Zod stripped it from the parsed body and the destructured value was always `undefined`. The request answered 200 and wrote nothing. The API Manager permissions modal sends `blockedModels` on every save (ApiManagerPageClient.tsx), so the Claude-Code family-blocking control silently did nothing and an existing deny-list could not be cleared. `blockedModels` is the deny-list half of the model policy — read by `isModelAllowedForKey()` before the allow-list and winning over it — so that half was only reachable by editing the database by hand. Declare the field mirroring `allowedModels` (trimmed, non-empty, max 1000) and count it in the "No valid fields to update" guard so a body carrying only `blockedModels` is a valid update. Left out of `createKeySchema` deliberately: the create route does not read `blockedModels`, so declaring it there would be dead weight. * docs(changelog): add fragment for blockedModels key schema fix Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
blockedModelsis plumbed end-to-end but unreachable through the API.PATCH /api/keys/[id]destructuresblockedModelsfromvalidation.data, forwards it into the payload, andupdateApiKeyPermissions()writes it to theblocked_modelscolumn:src/app/api/keys/[id]/route.ts:72— destructuredsrc/app/api/keys/[id]/route.ts:101—if (blockedModels !== undefined) payload.blockedModels = blockedModels;src/lib/db/apiKeys.ts:846-849—updates.push("blocked_models = @blockedModels")Every link exists except the first:
updateKeyPermissionsSchemanever declared the field, so Zod strips it from the parsed body and the destructured value is alwaysundefined. The request answers200and writes nothing.Impact
The API Manager permissions modal sends
blockedModelson every save:src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx:875—blockedModels: validBlockedModelsin the PATCH bodySo the Claude-Code family-blocking control (
getBlockedClaudeCodeFamilies/CLAUDE_CODE_FAMILY_BLOCK_PATTERNS, same file around :196) silently does nothing — the operator toggles families, saves, gets a success, and the column is never written. An existing deny-list also cannot be cleared through the UI.blockedModelsis the deny-list half of the model policy:isModelAllowedForKey()checks it before the allow-list and it wins over it (src/lib/db/apiKeys.ts:1516), which is what lets an operator keep a broad scope likecc/*while excluding specific families. With the field unsettable, that half of the policy could only be written by editing the database by hand.Fix
Two lines in
src/shared/validation/schemas/keys.ts:blockedModelsinupdateKeyPermissionsSchema, mirroringallowedModelsexactly (trimmed, non-empty entries, max 1000)."No valid fields to update"superRefineguard, so a body carrying onlyblockedModelsis a valid update instead of being rejected as empty.Deliberately not added to
createKeySchema: the create route (src/app/api/keys/route.ts) does not readblockedModels, so declaring it there would be dead weight.Tests
New:
tests/unit/api-keys-blocked-models-schema.test.ts— 6 rules.blockedModelsverbatimblockedModelsalone is a valid updatemodelAccessMode: "all"allowedModels(trimmed / non-empty / max 1000 / must be an array)[]so a deny-list can be clearedBefore the fix: 5 failed, 1 passed (R6 passes — it guards the already-correct route wiring).
After the fix: 6 passed.
Neighbouring key-permission suites re-run, no regressions — 36/36:
npm run typecheck:coreclean. Prettier clean. The 11no-unused-varsESLint errors onschemas/keys.tslines 3-15 are pre-existing (import block byte-identical to the base ref; the file is already inconfig/quality/eslint-suppressions.json).Live validation
Reproduced on a production gateway before the fix:
PATCH /api/keys/{id}with{ modelAccessMode: "all", allowedModels: [], blockedModels: [...] }returned200and echoedmodelAccessMode/allowedModelsback, while a direct read of theblocked_modelscolumn showed it stillNULL.