Skip to content

fix(ui): omit unchanged allowed_routes on key update#27070

Open
fengfeng-zi wants to merge 1 commit into
BerriAI:litellm_internal_stagingfrom
fengfeng-zi:fix/non-admin-key-edit-allowed-routes-27005
Open

fix(ui): omit unchanged allowed_routes on key update#27070
fengfeng-zi wants to merge 1 commit into
BerriAI:litellm_internal_stagingfrom
fengfeng-zi:fix/non-admin-key-edit-allowed-routes-27005

Conversation

@fengfeng-zi

Copy link
Copy Markdown

Summary

  • omit \�llowed_routes\ from key update payloads when the edit form did not actually change the route override
  • preserve real clears and real route edits so proxy admins can still modify overrides intentionally
  • add UI regression tests for unchanged, empty, and clear-to-empty allowed_routes flows

Testing

  • npm.cmd test -- --run src/components/templates/key_info_view.test.tsx

Closes #27005

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a UX bug where the key-edit form always included allowed_routes in the update payload, causing non-admin editors to hit a backend permission error on saves where they hadn't actually changed the route override. The fix adds normalizeStringList / areStringListsEqual helpers and strips allowed_routes from the payload when it is identical to the stored value, while still forwarding deliberate clears or edits. Three new unit tests cover the unchanged, already-empty, and clear-to-empty flows.

Confidence Score: 4/5

Safe to merge; findings are P2 suggestions that don't affect correctness of the core fix.

Only P2 findings: an order-sensitive list comparison that could misfire if the form reorders routes, and a minor test-coverage gap for undefined allowed_routes. The core logic is sound and well-tested for the three key scenarios.

No files require special attention beyond the inline suggestions.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/templates/key_info_view.tsx Adds areStringListsEqual and normalizeStringList helpers; strips unchanged allowed_routes from key-update payloads to avoid tripping the backend permission check on no-op saves.
ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx Adds three new tests for unchanged, already-empty, and clear-to-empty allowed_routes flows; all use mocked keyUpdateCall and do not make real network calls.

Reviews (1): Last reviewed commit: "fix(ui): omit unchanged allowed_routes o..." | Re-trigger Greptile

Comment on lines +69 to +77
const areStringListsEqual = (left: unknown, right: unknown): boolean => {
const normalizedLeft = normalizeStringList(left);
const normalizedRight = normalizeStringList(right);

return (
normalizedLeft.length === normalizedRight.length &&
normalizedLeft.every((entry, index) => entry === normalizedRight[index])
);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 areStringListsEqual uses positional comparison (every((entry, index) => entry === right[index])), so two lists with the same routes in different order are treated as distinct. If the multi-select component in KeyEditView ever returns routes in a different order than how they were stored (e.g., it sorts alphabetically or the user reselects in a different sequence), a non-admin editor would still trip the backend permission check on what they perceive as an unchanged save. A set/sorted comparison is more robust for unordered identifiers like routes.

Suggested change
const areStringListsEqual = (left: unknown, right: unknown): boolean => {
const normalizedLeft = normalizeStringList(left);
const normalizedRight = normalizeStringList(right);
return (
normalizedLeft.length === normalizedRight.length &&
normalizedLeft.every((entry, index) => entry === normalizedRight[index])
);
};
const areStringListsEqual = (left: unknown, right: unknown): boolean => {
const normalizedLeft = normalizeStringList(left).sort();
const normalizedRight = normalizeStringList(right).sort();
return (
normalizedLeft.length === normalizedRight.length &&
normalizedLeft.every((entry, index) => entry === normalizedRight[index])
);
};

Comment on lines +800 to +818
it("should drop empty allowed_routes when the key previously had no route override", async () => {
const keyData: KeyResponse = {
...MOCK_KEY_DATA,
user_id: "proxy-admin-user",
allowed_routes: [],
} as KeyResponse;

await enterEditMode(keyData);
await editViewMocks.onSubmit!({
key: keyData.token,
token: keyData.token,
allowed_routes: [],
});

expect(keyUpdateCall).toHaveBeenCalledWith(
expect.anything(),
expect.not.objectContaining({ allowed_routes: expect.anything() }),
);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing test: currentKeyData.allowed_routes is null or undefined

The most common case for a key that never had allowed_routes set is undefined (the field simply isn't present on KeyResponse), yet only [] is covered by the "previously had no route override" test. If normalizeStringList handles undefined correctly (it does — returns []), a test for that value makes the coverage explicit and guards against future regressions in the helper.

@codecov

codecov Bot commented May 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Bojun-Vvibe added a commit to Bojun-Vvibe/oss-contributions that referenced this pull request May 3, 2026
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.

[Bug]: Non-admin team admins cannot save Key Edit Settings — UI sends allowed_routes, but UpdateKeyRequest has no key_type to fall back to

2 participants