fix managed downstream deny-all semantics
This commit is contained in:
@@ -114,10 +114,10 @@ function resolveUpstreamPath(apiVersion: string, modelActionPath: string): strin
|
||||
return `/${normalizedVersion}/${normalizedAction}`;
|
||||
}
|
||||
|
||||
function hasDownstreamModelRestrictions(policy: { supportedModels?: unknown; allowedRouteIds?: unknown }): boolean {
|
||||
function hasDownstreamModelRestrictions(policy: { supportedModels?: unknown; allowedRouteIds?: unknown; denyAllWhenEmpty?: unknown }): boolean {
|
||||
const supportedModels = Array.isArray(policy.supportedModels) ? policy.supportedModels : [];
|
||||
const allowedRouteIds = Array.isArray(policy.allowedRouteIds) ? policy.allowedRouteIds : [];
|
||||
return supportedModels.length > 0 || allowedRouteIds.length > 0;
|
||||
return supportedModels.length > 0 || allowedRouteIds.length > 0 || policy.denyAllWhenEmpty === true;
|
||||
}
|
||||
|
||||
function extractGeminiListedModelName(item: unknown): string {
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { getProxyAuthContext } from '../../middleware/auth.js';
|
||||
import { isModelAllowedByPolicyOrAllowedRoutes, recordManagedKeyCostUsage } from '../../services/downstreamApiKeyService.js';
|
||||
import {
|
||||
EMPTY_DOWNSTREAM_ROUTING_POLICY,
|
||||
GLOBAL_UNRESTRICTED_DOWNSTREAM_ROUTING_POLICY,
|
||||
type DownstreamRoutingPolicy,
|
||||
} from '../../services/downstreamPolicyTypes.js';
|
||||
import { EMPTY_DOWNSTREAM_ROUTING_POLICY, type DownstreamRoutingPolicy } from '../../services/downstreamPolicyTypes.js';
|
||||
|
||||
export function getDownstreamRoutingPolicy(request: FastifyRequest): DownstreamRoutingPolicy {
|
||||
const authContext = getProxyAuthContext(request);
|
||||
if (!authContext) return EMPTY_DOWNSTREAM_ROUTING_POLICY;
|
||||
if (authContext.keyId === null) return GLOBAL_UNRESTRICTED_DOWNSTREAM_ROUTING_POLICY;
|
||||
return authContext.policy;
|
||||
}
|
||||
|
||||
@@ -21,7 +16,6 @@ export async function ensureModelAllowedForDownstreamKey(
|
||||
): Promise<boolean> {
|
||||
const authContext = getProxyAuthContext(request);
|
||||
if (!authContext) return true;
|
||||
if (authContext.keyId === null) return true;
|
||||
|
||||
if (await isModelAllowedByPolicyOrAllowedRoutes(requestedModel, authContext.policy)) {
|
||||
return true;
|
||||
|
||||
@@ -141,6 +141,7 @@ describe('downstreamApiKeyService', () => {
|
||||
supportedModels: [],
|
||||
allowedRouteIds: [],
|
||||
siteWeightMultipliers: {},
|
||||
denyAllWhenEmpty: true,
|
||||
};
|
||||
|
||||
expect(await service.isModelAllowedByPolicyOrAllowedRoutes('gpt-4o-mini', policy)).toBe(false);
|
||||
|
||||
@@ -234,7 +234,7 @@ export async function isModelAllowedByPolicyOrAllowedRoutes(model: string, polic
|
||||
const hasPatternRules = patterns.length > 0;
|
||||
const hasRouteRules = allowedRouteIds.length > 0;
|
||||
|
||||
if (!hasPatternRules && !hasRouteRules) return false;
|
||||
if (!hasPatternRules && !hasRouteRules) return policy.denyAllWhenEmpty === true ? false : true;
|
||||
|
||||
if (hasPatternRules && patterns.some((pattern) => matchesDownstreamModelPattern(model, pattern))) {
|
||||
return true;
|
||||
@@ -278,6 +278,7 @@ export function toPolicyFromView(view: Pick<DownstreamApiKeyPolicyView, 'support
|
||||
supportedModels: normalizeSupportedModelsInput(view.supportedModels),
|
||||
allowedRouteIds: normalizeAllowedRouteIdsInput(view.allowedRouteIds),
|
||||
siteWeightMultipliers: normalizeSiteWeightMultipliersInput(view.siteWeightMultipliers),
|
||||
denyAllWhenEmpty: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ export interface DownstreamRoutingPolicy {
|
||||
supportedModels: string[];
|
||||
allowedRouteIds: number[];
|
||||
siteWeightMultipliers: Record<number, number>;
|
||||
denyAllWhenEmpty?: boolean;
|
||||
}
|
||||
|
||||
export const EMPTY_DOWNSTREAM_ROUTING_POLICY: DownstreamRoutingPolicy = {
|
||||
@@ -9,9 +10,3 @@ export const EMPTY_DOWNSTREAM_ROUTING_POLICY: DownstreamRoutingPolicy = {
|
||||
allowedRouteIds: [],
|
||||
siteWeightMultipliers: {},
|
||||
};
|
||||
|
||||
export const GLOBAL_UNRESTRICTED_DOWNSTREAM_ROUTING_POLICY: DownstreamRoutingPolicy = {
|
||||
supportedModels: ['*'],
|
||||
allowedRouteIds: [],
|
||||
siteWeightMultipliers: {},
|
||||
};
|
||||
|
||||
@@ -137,6 +137,7 @@ describe('TokenRouter downstream policy', () => {
|
||||
allowedRouteIds: [],
|
||||
supportedModels: [],
|
||||
siteWeightMultipliers: {},
|
||||
denyAllWhenEmpty: true,
|
||||
});
|
||||
|
||||
expect(deniedPick).toBeNull();
|
||||
|
||||
@@ -537,7 +537,7 @@ function isModelAllowedByDownstreamPolicy(requestedModel: string, policy: Downst
|
||||
: [];
|
||||
const hasSupportedPatterns = supportedPatterns.length > 0;
|
||||
const hasAllowedRoutes = policy.allowedRouteIds.length > 0;
|
||||
if (!hasSupportedPatterns && !hasAllowedRoutes) return false;
|
||||
if (!hasSupportedPatterns && !hasAllowedRoutes) return policy.denyAllWhenEmpty === true ? false : true;
|
||||
const matchedSupportedPattern = supportedPatterns.some((pattern) => matchesModelPattern(requestedModel, pattern));
|
||||
if (matchedSupportedPattern) return true;
|
||||
if (hasAllowedRoutes) return true;
|
||||
|
||||
Reference in New Issue
Block a user