Files
stack/apps/gateway/src/chat/__tests__/chat-security.test.ts
Jason Woltje 50edfb6613
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/pr/ci Pipeline failed
fix(tests): correct provider.service and chat-security test assertions
- Fix ProviderService constructor call: pass null for optional credentialsService
- Update Anthropic model order to match AnthropicAdapter registration (opus first)
- Update OpenAI model list to match OpenAIAdapter (codex-gpt-5-4 only)
- Update Z.ai assertion to verify glm-5 is present (Pi registry includes additional models)
- Add reflect-metadata import to chat-security test to fix Reflect.getMetadata error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 19:24:35 -05:00

82 lines
2.3 KiB
TypeScript

import 'reflect-metadata';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { validateSync } from 'class-validator';
import { describe, expect, it, vi } from 'vitest';
import { SendMessageDto } from '../../conversations/conversations.dto.js';
import { ChatRequestDto } from '../chat.dto.js';
import { validateSocketSession } from '../chat.gateway-auth.js';
describe('Chat controller source hardening', () => {
it('applies AuthGuard and reads the current user', () => {
const source = readFileSync(resolve('src/chat/chat.controller.ts'), 'utf8');
expect(source).toContain('@UseGuards(AuthGuard)');
expect(source).toContain('@CurrentUser() user: { id: string }');
});
});
describe('WebSocket session authentication', () => {
it('returns null when the handshake does not resolve to a session', async () => {
const result = await validateSocketSession(
{},
{
api: {
getSession: vi.fn().mockResolvedValue(null),
},
},
);
expect(result).toBeNull();
});
it('returns the resolved session when Better Auth accepts the headers', async () => {
const session = { user: { id: 'user-1' }, session: { id: 'session-1' } };
const result = await validateSocketSession(
{ cookie: 'session=abc' },
{
api: {
getSession: vi.fn().mockResolvedValue(session),
},
},
);
expect(result).toEqual(session);
});
});
describe('Chat DTO validation', () => {
it('rejects unsupported message roles', () => {
const dto = Object.assign(new SendMessageDto(), {
content: 'hello',
role: 'moderator',
});
const errors = validateSync(dto);
expect(errors.length).toBeGreaterThan(0);
});
it('rejects oversized conversation message content above 10000 characters', () => {
const dto = Object.assign(new SendMessageDto(), {
content: 'x'.repeat(10_001),
role: 'user',
});
const errors = validateSync(dto);
expect(errors.length).toBeGreaterThan(0);
});
it('rejects oversized chat content above 10000 characters', () => {
const dto = Object.assign(new ChatRequestDto(), {
content: 'x'.repeat(10_001),
});
const errors = validateSync(dto);
expect(errors.length).toBeGreaterThan(0);
});
});