From 0c0910055a26c13aba2dd02e9bfc0afc04b30536 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Wed, 26 Aug 2026 07:15:10 +0000 Subject: [PATCH] fix(security): declare 204 response schema on PATCH /session Co-Authored-By: Claude Sonnet 4.6 --- src/api_productions.ts | 2 +- src/api_validation.test.ts | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/api_productions.ts b/src/api_productions.ts index 2914c64..31dcf35 100644 --- a/src/api_productions.ts +++ b/src/api_productions.ts @@ -756,7 +756,7 @@ const apiProductions: FastifyPluginCallback = ( 'Provide client local SDP description as request body to finalize connection protocol.', params: SessionIdParams, response: { - 200: Type.String(), + 204: Type.Null(), 400: Type.String(), 500: Type.String() } diff --git a/src/api_validation.test.ts b/src/api_validation.test.ts index d0120de..e3af63a 100644 --- a/src/api_validation.test.ts +++ b/src/api_validation.test.ts @@ -93,6 +93,11 @@ const mockProductionManager = { .mockImplementation((lines: any[], id: string) => lines.find((l: any) => l.id === id) ), + requireLine: jest.fn().mockImplementation((lines: any[], id: string) => { + const found = lines.find((l: any) => l.id === id); + if (!found) throw new Error(`Line ${id} not found`); + return found; + }), updateUserLastSeen: jest.fn().mockReturnValue(true), deleteProductionLine: jest.fn().mockResolvedValue(undefined), deleteProduction: jest.fn().mockResolvedValue(true), @@ -234,6 +239,25 @@ describe('Input Validation', () => { expect(response.statusCode).not.toBe(400); }); + test('PATCH /session/:sessionId returns 204 with empty body on success', async () => { + mockDbManager.getSession.mockResolvedValueOnce({ + productionId: '1', + lineId: 'lid-1', + endpointId: 'endpoint-1', + sessionDescription: { audio: {} } + }); + mockCoreFunctions.handleAnswerRequest = jest + .fn() + .mockResolvedValue(undefined); + const response = await server.inject({ + method: 'PATCH', + url: '/api/v1/session/valid-session-id', + body: { sdpAnswer: 'v=0\r\n' } + }); + expect(response.statusCode).toBe(204); + expect(response.body).toBe(''); + }); + test('DELETE /session/:sessionId accepts non-empty sessionId', async () => { const response = await server.inject({ method: 'DELETE',