fix(admission): pilotläge utan reservation #439
@@ -306,7 +306,7 @@ export async function POST(request: NextRequest) {
|
||||
dataClass,
|
||||
maxInputTokens: policy.maxInputTokens,
|
||||
maxOutputTokens: policy.maxOutputTokens,
|
||||
maximumCredits: Math.max(1, maximumCredits),
|
||||
maximumCredits,
|
||||
},
|
||||
policy: {
|
||||
tenantId,
|
||||
|
||||
@@ -47,8 +47,11 @@ export function admitModelExecution(
|
||||
|| !Array.isArray(policy.allowedModelIds) || !Array.isArray(policy.allowedDataClasses)
|
||||
|| !['none', 'low', 'medium', 'high', 'restricted'].includes(request.dataClass)
|
||||
|| !['internal', 'external'].includes(policy.destination) || typeof policy.externalTransferAllowed !== 'boolean'
|
||||
|| ![request.maxInputTokens, request.maxOutputTokens, request.maximumCredits, policy.maxInputTokens, policy.maxOutputTokens]
|
||||
.every((n) => Number.isSafeInteger(n) && n > 0)) return { allowed: false, reason: 'invalid_request' };
|
||||
|| ![request.maxInputTokens, request.maxOutputTokens, policy.maxInputTokens, policy.maxOutputTokens]
|
||||
.every((n) => Number.isSafeInteger(n) && n > 0)
|
||||
|| !Number.isSafeInteger(request.maximumCredits) || request.maximumCredits < 0) {
|
||||
return { allowed: false, reason: 'invalid_request' };
|
||||
}
|
||||
if (request.tenantId !== policy.tenantId || request.projectId !== policy.projectId) return { allowed: false, reason: 'scope_mismatch' };
|
||||
if (!policy.allowedModelIds.includes(request.modelId)) return { allowed: false, reason: 'model_not_allowed' };
|
||||
if (!policy.allowedDataClasses.includes(request.dataClass)) return { allowed: false, reason: 'data_class_not_allowed' };
|
||||
@@ -58,9 +61,13 @@ export function admitModelExecution(
|
||||
if (request.maxInputTokens > policy.maxInputTokens || request.maxOutputTokens > policy.maxOutputTokens) {
|
||||
return { allowed: false, reason: 'token_limit_exceeded' };
|
||||
}
|
||||
if (!reservation || reservation.tenantId !== request.tenantId || reservation.projectId !== request.projectId
|
||||
// maximumCredits === 0 means the operator runs this route without a wallet
|
||||
// (explicit pilot mode), so no reservation is required. Any positive amount
|
||||
// still requires an active, matching reservation.
|
||||
if (request.maximumCredits > 0 && (
|
||||
!reservation || reservation.tenantId !== request.tenantId || reservation.projectId !== request.projectId
|
||||
|| reservation.jobId !== request.jobId || reservation.status !== 'reserved'
|
||||
|| !Number.isSafeInteger(reservation.credits) || reservation.credits < request.maximumCredits) {
|
||||
|| !Number.isSafeInteger(reservation.credits) || reservation.credits < request.maximumCredits)) {
|
||||
return { allowed: false, reason: 'reservation_required' };
|
||||
}
|
||||
return { allowed: true };
|
||||
|
||||
@@ -18,6 +18,14 @@ describe('model execution admission', () => {
|
||||
expect(admitModelExecution(request, policy, { ...hold, status: 'settled' })).toEqual({ allowed: false, reason: 'reservation_required' });
|
||||
expect(admitModelExecution(request, policy, { ...hold, jobId: 'other' })).toEqual({ allowed: false, reason: 'reservation_required' });
|
||||
});
|
||||
it('pilot mode (maximumCredits 0) requires no reservation but still enforces every other rule', () => {
|
||||
const pilot = { ...request, maximumCredits: 0 };
|
||||
expect(admitModelExecution(pilot, policy, undefined)).toEqual({ allowed: true });
|
||||
expect(admitModelExecution(pilot, { ...policy, allowedModelIds: [] }, undefined)).toEqual({ allowed: false, reason: 'model_not_allowed' });
|
||||
expect(admitModelExecution(pilot, { ...policy, projectId: 'other' }, undefined)).toEqual({ allowed: false, reason: 'scope_mismatch' });
|
||||
expect(admitModelExecution({ ...pilot, maximumCredits: -1 }, policy, undefined)).toEqual({ allowed: false, reason: 'invalid_request' });
|
||||
expect(admitModelExecution(request, policy, undefined)).toEqual({ allowed: false, reason: 'reservation_required' });
|
||||
});
|
||||
it('rejects invalid limits and never treats an unknown destination as local', () => {
|
||||
expect(admitModelExecution({ ...request, maxInputTokens: NaN }, policy, hold).allowed).toBe(false);
|
||||
expect(admitModelExecution(request, { ...policy, destination: 'unknown' as never }, hold).allowed).toBe(false);
|
||||
|
||||
Reference in New Issue
Block a user