Skip to content

feat(cache): back the Redis URL and Database Index UI fields end-to-end - #32075

Merged
yuneng-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_/admiring-sammet-3b1831
Jul 7, 2026
Merged

feat(cache): back the Redis URL and Database Index UI fields end-to-end#32075
yuneng-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_/admiring-sammet-3b1831

Conversation

@yuneng-berri

@yuneng-berri yuneng-berri commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

LIT-3996 (UI Deficiencies: Database Selection & Cache Config)

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

Backend behavior against a proxy with STORE_MODEL_IN_DB='True' and a database connected. The url-precedence resolver runs on both the test and save paths, so the discrete host/port/db/username/password fields are dropped when a full URL is supplied, and a stored password-bearing URL is masked on read

  1. Save a cache config through the UI with only a Redis URL ending in /1 (e.g. redis://:pw@host:6379/1) and confirm the value persists on reload and the cache connects to logical DB 1
  2. Save a config with both a Redis URL and separate Host/Port/Username/Database Index, then confirm the stored config keeps only the URL (the discrete fields are dropped) and the connection matches the URL
  3. Reload the page and confirm the Redis URL field comes back masked (the inline password is not shown in plaintext), the same way the discrete Password field is masked
  4. Switch Redis Type to Cluster, supply Startup Nodes plus discrete fields, and confirm the discrete fields are retained (cluster mode is exempt from URL precedence)

Type

🆕 New Feature

Changes

The typed cache-settings form (shipped in #31939) already renders a "Redis URL" and a "Database Index" field, but the backend never defined them. Two consequences: GET /cache/settings builds its field list from CACHE_SETTINGS_FIELDS, so a saved url/db could not round-trip back into the form on reload; and the "When set, it takes precedence over Host, Port, Password, and Database Index" help text the UI shows for the URL field was not enforced anywhere on the backend

This adds the url and db entries to CACHE_SETTINGS_FIELDS so the endpoint knows about them, and introduces _resolve_cache_url_precedence. When a non-empty url is present it wins and the discrete host/port/db/username/password fields are dropped before the settings are tested or persisted, which matches how litellm._redis resolves the connection at runtime (redis.Redis.from_url ignores those fields when a URL is given). Cluster mode (redis_startup_nodes) is exempt because it authenticates via the discrete fields rather than a URL. Both the test path (POST /cache/settings/test) and the save path (POST /cache/settings) go through the resolver, so the persisted config is unambiguous

Because a Redis/Valkey URL can carry an inline password (redis://:secret@host:6379/1), url is added to the set of credential fields that are masked on read, so a stored password-bearing URL is never returned in plaintext by GET /cache/settings; it gets the same masked-on-read treatment as the discrete password field. username is likewise encodable in a URL, so it is dropped under URL precedence alongside password, and the URL field help text now lists Username among the fields the URL overrides

This completes LIT-3996: operators can now isolate the cache into a specific logical database (e.g. redis://host:6379/1) entirely from the Admin UI instead of falling back to hardcoding REDIS_URL via the environment. TTL and namespace were already configurable via existing fields; the missing piece was full-URI and logical-database support, which the UI advertised but the backend did not yet honor

Tests cover the field definitions exposing url/db, the resolver dropping discrete fields (including username) only when a non-empty URL is present, blank-URL and cluster-mode exemptions, both endpoints persisting the resolved settings, and GET /cache/settings masking a password-bearing URL while leaving non-credential fields untouched

The typed cache-settings form already renders a Redis URL and a Database
Index field, but the backend never defined them, so GET /cache/settings
could not round-trip a saved value into the form and the "URL takes
precedence over Host/Port/Password/Database Index" help text the UI shows
was not actually enforced anywhere.

Add the url and db entries to CACHE_SETTINGS_FIELDS so the endpoint knows
about them, and add _resolve_cache_url_precedence: when a non-empty url is
present it wins and the discrete host/port/db/password fields are dropped
before the settings are tested or persisted, matching how litellm._redis
resolves the connection at runtime (redis.Redis.from_url ignores them).
Cluster mode is exempt because it authenticates via the discrete fields
rather than a url. Both test and save paths go through the resolver so the
stored config is unambiguous.

This finishes LIT-3996: operators can now isolate the cache into a logical
database (e.g. redis://host:6379/1) entirely from the Admin UI instead of
hardcoding REDIS_URL in the environment.
@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR wires up the Redis URL and Database Index fields end-to-end: both are added to CACHE_SETTINGS_FIELDS (so GET /cache/settings can round-trip them through the form), url is added to _CACHE_SENSITIVE_FIELDS (masked on read), and _resolve_cache_url_precedence is introduced to drop discrete connection fields when a full URL is present before testing or saving.

  • URL precedence resolver (_resolve_cache_url_precedence): drops host, port, db, password, and username when a non-empty url is supplied; cluster mode (redis_startup_nodes) is correctly exempted since it authenticates via discrete fields.
  • Credential masking: url is added to _CACHE_SENSITIVE_FIELDS alongside password and sentinel_password, so a password-bearing URL is never returned in plaintext by GET /cache/settings.
  • Comprehensive tests: new tests cover field-definition assertions, resolver behaviour (URL wins, blank URL/cluster exemptions), both endpoint flows, and GET masking of a credential-bearing URL.

Confidence Score: 5/5

Safe to merge. The change is additive, well-tested, and the two credential-exposure issues flagged in the prior review are both resolved in this version.

The resolver logic is correct and handles every edge case tested (blank URL, cluster exemption, username stripping). The url field is now masked on GET alongside password and sentinel_password. All six new tests are properly mocked, no assertions were weakened, and existing test behaviour is unchanged. The only remaining rough edge — the POST response echoing back the unmasked URL — is the same pre-existing pattern used for the discrete password field and is not introduced by this PR.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/management_endpoints/cache_settings_endpoints.py Adds url to _CACHE_SENSITIVE_FIELDS, introduces _resolve_cache_url_precedence (with correct cluster-mode exemption), and calls it in both test and save paths. Both P1s from the previous review (username omitted from _URL_OVERRIDDEN_CONNECTION_FIELDS, url not masked on GET) are addressed.
litellm/types/management_endpoints/cache_settings_endpoints.py Adds url (String) and db (Integer) entries to CACHE_SETTINGS_FIELDS with correct types, descriptions, and redis_type=None (common fields). Changes are purely additive and backward-compatible.
tests/test_litellm/proxy/management_endpoints/test_cache_settings_endpoints.py Adds six new unit tests covering field-definition assertions, resolver logic (URL wins, blank URL, cluster exemption), both endpoint flows under URL precedence, and GET masking. All tests are properly mocked with no real network calls. Existing tests changed for formatting only — no assertions weakened.

Reviews (2): Last reviewed commit: "fix(cache): use builtin dict annotation ..." | Re-trigger Greptile

Comment thread litellm/proxy/management_endpoints/cache_settings_endpoints.py Outdated
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Comment thread litellm/types/management_endpoints/cache_settings_endpoints.py
@veria-ai

veria-ai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 1 · PR risk: 0/10

…der url precedence

Two follow-ups from review of the url/db work.

A Redis/Valkey url can embed a password (redis://:secret@host:6379/1), but
_CACHE_SENSITIVE_FIELDS only masked the discrete password and sentinel_password,
so a stored password-bearing url came back in plaintext from every
GET /cache/settings. Add url to the masked set so it gets the same masked-on-read
treatment as password.

The url-precedence resolver dropped host/port/db/password but not username, even
though a url can encode a username too (redis://user:pass@host). Left in, the
discrete username rode along and could contradict the url. Add username to the
overridden set and update the Redis URL help text to list it among the fields url
takes precedence over.

Tests: GET masks a password-bearing url (secret never returned verbatim) while a
non-credential field is untouched, and the resolver drops a discrete username when
a url is present.
@yuneng-berri

Copy link
Copy Markdown
Contributor Author

@veria-ai review

@yuneng-berri

Copy link
Copy Markdown
Contributor Author

@greptile

@yuneng-berri
yuneng-berri enabled auto-merge July 7, 2026 01:12
@yuneng-berri
yuneng-berri merged commit 4851cba into litellm_internal_staging Jul 7, 2026
124 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_/admiring-sammet-3b1831 branch July 7, 2026 13:33
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.

2 participants