LibreChat/api/server/routes/presets.test.js
Danny Avila 67b7b441b2
🛂 feat: Filter Model-Bound Content by Source (#14425)
* feat: introduce optional content protection seam

* feat: enforce source-aware content filters

* feat: complete source-aware content enforcement

* test: activate skill file-text fail-close fixtures

* fix: harden source-aware content filters

* fix: harden model-bound content filtering

* fix: preserve legacy filters and generated files

* fix: inspect shared scalar metadata

* test: align mocks with current dev dependencies

* feat: add persisted content filter safeguards

* feat: complete source-aware content filter enforcement

* fix: move resume content preflight into TypeScript

* fix: close content inspection edge cases

* fix: harden content protection boundaries

* fix: complete content protection safeguards

* test: align persisted memory filter coverage

* fix: reconcile content protection with current dev

* fix: reconcile content protection with latest dev

* fix: close content protection review gaps

* fix: enforce source-aware provider boundaries

* fix: preserve legacy PII preflight semantics

* test: stabilize stored branch preflight fixture

* fix: defer agent writes until protected model admission

* perf: harden source-aware model-bound filtering

* fix: canonicalize provider lineage before validation

* fix: satisfy model-bound callback type checks

* perf: Bound content protection filtering work

* fix: Bound submission array traversal

* fix: Stabilize bounded content snapshots

* fix: Scope model-bound traversal overflows

* fix: Preserve scoped content inspection

* fix: Accumulate aggregate traversal scopes

* fix: centralize content policy boundaries

* test: align deferred tool policy context

* test: align controller policy mocks

* style: normalize content protection imports

* fix: close content policy review gaps

* fix: narrow active skill policy config

* fix: address content protection review boundaries

* fix: retain exact provenance overflow sentinel

* fix: preserve literal and scoped provenance updates

* fix: narrow persisted edit provenance

* fix: isolate exact overflow attribution

* fix: centralize stored prompt protection

* fix: fail closed on incomplete transcript evidence

* fix: align canonical transcript routing

* refactor: centralize content policy preflights

* fix: isolate upload policy error typing

* style: sort policy preflight imports

* refactor: centralize content policy boundaries
2026-08-21 22:43:32 -04:00

192 lines
4.9 KiB
JavaScript

const express = require('express');
const request = require('supertest');
let mockAppConfig = {};
const mockGetPresets = jest.fn();
const mockSavePreset = jest.fn();
const mockDeletePresets = jest.fn();
jest.mock('~/models', () => ({
getPresets: mockGetPresets,
savePreset: mockSavePreset,
deletePresets: mockDeletePresets,
}));
jest.mock('~/server/middleware', () => ({
requireJwtAuth: (req, _res, next) => {
req.user = { id: 'user-1' };
next();
},
configMiddleware: (req, _res, next) => {
req.config = mockAppConfig;
next();
},
}));
const app = express();
app.use(express.json());
app.use('/api/presets', require('./presets'));
const privatePattern = {
starterPatterns: [],
customPatterns: [{ id: 'private', label: 'private value', regex: 'PRIVATE-[A-Z]+' }],
};
describe('preset content filtering', () => {
beforeEach(() => {
mockAppConfig = {};
mockGetPresets.mockReset();
mockSavePreset.mockReset();
mockDeletePresets.mockReset();
});
it('returns stored presets unchanged when filters are not configured', async () => {
const storedPreset = {
presetId: 'preset-1',
title: 'PRIVATE-TITLE',
promptPrefix: 'PRIVATE-PROMPT',
endpoint: 'openAI',
};
mockGetPresets.mockResolvedValue([storedPreset]);
const response = await request(app).get('/api/presets').expect(200);
expect(response.body).toEqual([storedPreset]);
expect(mockGetPresets).toHaveBeenCalledWith('user-1');
});
it('redacts every policy-covered field from blocked stored presets', async () => {
const safePreset = {
presetId: 'safe-preset',
title: 'Safe preset',
promptPrefix: 'Safe instructions',
endpoint: 'openAI',
};
const blockedPreset = {
_id: 'blocked-record',
presetId: 'blocked-preset',
user: 'user-1',
title: 'PRIVATE-TITLE',
promptPrefix: 'PRIVATE-PROMPT',
system: 'PRIVATE-SYSTEM',
context: 'PRIVATE-CONTEXT',
instructions: 'PRIVATE-INSTRUCTIONS',
additional_instructions: 'PRIVATE-ADDITIONAL',
greeting: 'PRIVATE-GREETING',
examples: [{ input: 'PRIVATE-INPUT', output: 'PRIVATE-OUTPUT' }],
endpoint: 'openAI',
model: 'gpt-safe',
order: 2,
};
mockGetPresets.mockResolvedValue([safePreset, blockedPreset]);
mockAppConfig = {
filters: {
prompts: {
pii: privatePattern,
},
},
};
const response = await request(app).get('/api/presets').expect(200);
expect(response.body[0]).toEqual(safePreset);
expect(response.body[1]).toEqual({
_id: 'blocked-record',
presetId: 'blocked-preset',
user: 'user-1',
title: '',
endpoint: 'openAI',
model: 'gpt-safe',
order: 2,
contentFilterBlocked: true,
});
expect(JSON.stringify(response.body)).not.toContain('PRIVATE-');
});
it('redacts blocked nested model request fields under the model-parameter scope', async () => {
mockGetPresets.mockResolvedValue([
{
presetId: 'blocked-options',
title: 'Safe title',
endpoint: 'openAI',
options: {
vendor: {
routingHint: 'PRIVATE-ROUTE',
},
},
},
]);
mockAppConfig = {
filters: {
modelParameters: {
pii: privatePattern,
},
},
};
const response = await request(app).get('/api/presets').expect(200);
expect(response.body).toEqual([
{
presetId: 'blocked-options',
title: '',
endpoint: 'openAI',
contentFilterBlocked: true,
},
]);
expect(JSON.stringify(response.body)).not.toContain('PRIVATE-ROUTE');
});
it('fails closed when selected stored preset fields exceed bounded traversal', async () => {
mockGetPresets.mockResolvedValue([
{
presetId: 'oversized-examples',
title: 'Safe title',
endpoint: 'openAI',
examples: Array.from({ length: 4_097 }, () => ({
input: 'Safe input',
output: 'Safe output',
})),
},
]);
mockAppConfig = {
filters: {
prompts: {
pii: { ...privatePattern, fields: ['example_input'] },
},
},
};
const response = await request(app).get('/api/presets').expect(200);
expect(response.body).toEqual([
{
presetId: 'oversized-examples',
title: '',
endpoint: 'openAI',
contentFilterBlocked: true,
},
]);
});
it('does not apply a message-only policy to stored preset content', async () => {
const storedPreset = {
presetId: 'preset-1',
title: 'PRIVATE-TITLE',
promptPrefix: 'PRIVATE-PROMPT',
endpoint: 'openAI',
};
mockGetPresets.mockResolvedValue([storedPreset]);
mockAppConfig = {
filters: {
messages: {
pii: privatePattern,
},
},
};
const response = await request(app).get('/api/presets').expect(200);
expect(response.body).toEqual([storedPreset]);
});
});