fix(auth): per-user allowed-models checklist ignores cache, [None] doesn't block (#3355)

Three issues combined to make the per-user 'Allowed models' checklist
unreliable (#3032):

1. admin.js _loadModelsForUser fetched /api/models, which is backed by
   cached_models — endpoints that haven't been probed yet (e.g. a
   freshly-added DeepSeek API endpoint) simply didn't show up in the
   checklist. Switched to /api/model-endpoints, which always reflects
   every configured endpoint regardless of cache state.

2. _saveModels sent allowed_models: [] both when the admin clicked
   [All] (no restriction) and [None] (block everything) — the backend
   had no way to distinguish the two.

3. _enforce_chat_privileges treated an empty allowed_models list as
   'no restriction' (falsy -> skip the check), so [None] had no effect.

Added an explicit block_all_models privilege flag (defaulting to False,
and forced to False for admins) that admin.js now sets when zero models
are checked. _enforce_chat_privileges checks it first and 403s
regardless of allowed_models contents.
This commit is contained in:
Lucas Daniel
2026-06-08 17:52:39 -03:00
committed by GitHub
parent 0a324f20d2
commit 5462030cde
4 changed files with 114 additions and 14 deletions
+9
View File
@@ -31,11 +31,20 @@ DEFAULT_PRIVILEGES = {
"max_messages_per_day": 0,
"allowed_models": [],
"allowed_models_restricted": False,
# Explicit "block every model" sentinel. An empty `allowed_models` list is
# ambiguous — it's also what gets sent when the admin clicks "[All]" — so
# we need a dedicated flag to express "this user may use no models at all"
# distinctly from "this user has no restriction".
"block_all_models": False,
}
# Admins get everything
ADMIN_PRIVILEGES = {k: (True if isinstance(v, bool) else (0 if isinstance(v, int) else [])) for k, v in DEFAULT_PRIVILEGES.items()}
ADMIN_PRIVILEGES["allowed_models_restricted"] = False
# Admins must never be blocked from using models — the generic dict
# comprehension above flips every boolean default to True, which would be
# backwards for this sentinel.
ADMIN_PRIVILEGES["block_all_models"] = False
from src.constants import AUTH_FILE
DEFAULT_AUTH_PATH = AUTH_FILE