feat(api-manager): add provider-level model permissions (#9313)

* feat(api-manager): add provider-level model permissions

Persist canonical provider wildcards alongside exact model grants and
preserve explicit restricted-empty deny-all semantics across API, SQLite,
JSON import, sync, runtime policy, and the dashboard.

Invalidate filtered model catalogs on permission changes and guard against
stale in-flight catalog builders repopulating invalidated cache entries.

* fix(api-manager): show provider and model counts separately in summary

Provider wildcard selections (provider/*) are no longer counted as
individual models in the Selected Models Summary. The header now shows
"N providers · M models" when both are present, or just the non-empty
category when only one type is selected.

* fix(api-manager): separate provider and model permission displays

* fix(api-manager): separate provider wildcard permissions in UI
This commit is contained in:
Xiangzhe
2026-08-11 21:29:28 +08:00
committed by GitHub
parent 3898305df0
commit def5334768
24 changed files with 2227 additions and 358 deletions

View File

@@ -73,6 +73,7 @@ interface AccessSchedule {
export interface ApiKeyMetadata {
id: string;
name?: string;
modelAccessMode?: "all" | "restricted";
allowedModels?: string[];
allowedCombos?: string[];
allowedConnections?: string[];
@@ -319,7 +320,8 @@ async function validateStandardRoutingTarget(
}
const hasModelRestrictions =
(apiKeyInfo.allowedModels && apiKeyInfo.allowedModels.length > 0) ||
apiKeyInfo.modelAccessMode === "restricted" ||
Boolean(apiKeyInfo.allowedModels?.length) ||
apiKeyInfo.disableNonPublicModels === true;
if (!requestedComboName && hasModelRestrictions && modelStr.startsWith("auto/")) {
requestedComboName = modelStr;
@@ -525,7 +527,9 @@ async function validateModelAccess(context: PolicyContext): Promise<Response | n
let requestedComboName = comboAccess.comboName;
const hasModelRestrictions =
Boolean(apiKeyInfo.allowedModels?.length) || apiKeyInfo.disableNonPublicModels === true;
apiKeyInfo.modelAccessMode === "restricted" ||
Boolean(apiKeyInfo.allowedModels?.length) ||
apiKeyInfo.disableNonPublicModels === true;
if (!requestedComboName && hasModelRestrictions) {
if (modelStr.startsWith("auto/") || modelStr.startsWith("qtSd/")) {
requestedComboName = modelStr;