🛑 fix: Separate Agent Event Backpressure From User Bans (#15200)

* 🛑 fix: Separate Agent Event Backpressure From User Bans

* fix: Address Agent Event Review Findings

* fix: Mirror Case-Insensitive Agent Control Routing
This commit is contained in:
Danny Avila 2026-08-25 09:27:35 -04:00 committed by GitHub
parent e9dec7749a
commit d9e6250d05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 199 additions and 13 deletions

View file

@ -53,11 +53,15 @@ jest.mock('ua-parser-js', () => jest.fn(() => ({ browser: { name: 'Chrome' } }))
const checkBan = require('~/server/middleware/checkBan');
const { logger } = require('@librechat/data-schemas');
const { ViolationTypes } = require('librechat-data-provider');
const { findUser } = require('~/models');
const denyRequest = require('~/server/middleware/denyRequest');
const uap = require('ua-parser-js');
const createReq = (overrides = {}) => ({
ip: '192.168.1.1',
user: { id: 'user123' },
method: 'GET',
headers: { 'user-agent': 'Mozilla/5.0' },
body: {},
baseUrl: '/api',
@ -170,6 +174,110 @@ describe('checkBan middleware', () => {
expect(mockBanLogsGet).not.toHaveBeenCalled();
});
it.each(['/api/agents/chat/stream/stream-123', '/api/agents/chat/status/conversation-1'])(
'returns JSON for a banned browser GET without a request body: %s',
async (originalUrl) => {
mockBanCacheGet.mockResolvedValueOnce({ expiresAt: Date.now() + 60000 });
const req = createReq({
body: undefined,
baseUrl: '/api/agents',
originalUrl,
});
const res = createRes();
await checkBan(req, res, jest.fn());
expect(res.status).toHaveBeenCalledWith(403);
expect(res.json).toHaveBeenCalledWith({
message: 'Your account has been temporarily banned due to violations of our service.',
});
expect(denyRequest).not.toHaveBeenCalled();
},
);
it('preserves SSE denial for a banned browser interactive chat request', async () => {
mockBanCacheGet.mockResolvedValueOnce({ expiresAt: Date.now() + 60000 });
const req = createReq({
method: 'POST',
baseUrl: '/api/agents',
originalUrl: '/api/agents/chat/agents',
});
const res = createRes();
await checkBan(req, res, jest.fn());
expect(denyRequest).toHaveBeenCalledWith(req, res, { type: ViolationTypes.BAN });
expect(res.status).not.toHaveBeenCalled();
});
it.each(['active', 'status', 'stream'])(
'preserves SSE denial when a custom endpoint uses the POST-only name %s',
async (endpoint) => {
mockBanCacheGet.mockResolvedValueOnce({ expiresAt: Date.now() + 60000 });
const req = createReq({
method: 'POST',
baseUrl: '/api/agents',
originalUrl: `/api/agents/chat/${endpoint}`,
});
const res = createRes();
await checkBan(req, res, jest.fn());
expect(denyRequest).toHaveBeenCalledWith(req, res, { type: ViolationTypes.BAN });
expect(res.status).not.toHaveBeenCalled();
},
);
it('returns JSON for a bodyless browser POST to an interactive chat path', async () => {
mockBanCacheGet.mockResolvedValueOnce({ expiresAt: Date.now() + 60000 });
const req = createReq({
body: undefined,
method: 'POST',
baseUrl: '/api/agents',
originalUrl: '/api/agents/chat/agents',
});
const res = createRes();
await checkBan(req, res, jest.fn());
expect(res.status).toHaveBeenCalledWith(403);
expect(denyRequest).not.toHaveBeenCalled();
});
it.each(['abort', 'Abort', 'STEER', 'sTeEr'])(
'returns JSON for a banned browser agent control request: %s',
async (route) => {
mockBanCacheGet.mockResolvedValueOnce({ expiresAt: Date.now() + 60000 });
const req = createReq({
method: 'POST',
baseUrl: '/api/agents',
originalUrl: `/api/agents/chat/${route}`,
});
const res = createRes();
await checkBan(req, res, jest.fn());
expect(res.status).toHaveBeenCalledWith(403);
expect(denyRequest).not.toHaveBeenCalled();
},
);
it('keeps non-browser agent chat denial as JSON', async () => {
uap.mockReturnValueOnce({ browser: {} });
mockBanCacheGet.mockResolvedValueOnce({ expiresAt: Date.now() + 60000 });
const req = createReq({
method: 'POST',
baseUrl: '/api/agents',
originalUrl: '/api/agents/chat/agents',
});
const res = createRes();
await checkBan(req, res, jest.fn());
expect(res.status).toHaveBeenCalledWith(403);
expect(denyRequest).not.toHaveBeenCalled();
});
});
describe('active ban (positive timeLeft)', () => {