import { Logger } from '@nestjs/common'; import { identityApp, type IdentityApp } from './helpers/identity-app'; import { randomUUID } from 'node:crypto'; describe('HTTP security boundaries', () => { let ctx: IdentityApp; beforeAll(async () => { ctx = await identityApp(); }, 60000); afterAll(async () => { await ctx?.close(); }); afterEach(() => jest.restoreAllMocks()); it('bounds bodies and rejects malformed JSON with distinct codes', async () => { const large = await ctx .api() .post('/api/v1/products') .auth(ctx.token, { type: 'bearer' }) .send({ name: 'A', slug: 'a', description: 'x'.repeat(40000) }) .expect(413); expect(large.body.code).toBe('REQUEST_TOO_LARGE'); const invalid = await ctx .api() .post('/api/v1/products') .set('Content-Type', 'application/json') .send('{"invalid":') .expect(400); expect(invalid.body.code).toBe('REQUEST_MALFORMED'); }); it('generates its own request IDs and ignores cookie credentials', async () => { const response = await ctx .api() .get('/api/v1/addresses') .set('X-Request-Id', 'attacker-controlled') .set('Cookie', 'accessToken=' + ctx.token) .expect(401); expect(response.body.requestId).toMatch(/^[a-f0-9-]{36}$/); expect(response.headers['x-request-id']).toBe(response.body.requestId); expect(response.headers['cache-control']).toBe('no-store'); }); it('treats SQL-looking input as data and prevents field injection', async () => { const name = "Robert'); DROP TABLE users;--"; await ctx .api() .post('/api/v1/products') .auth(ctx.token, { type: 'bearer' }) .send({ name, slug: randomUUID() }) .expect(201); expect(await ctx.db.user.count()).toBeGreaterThan(0); await ctx .api() .get('/api/v1/products?limit=999999') .auth(ctx.token, { type: 'bearer' }) .expect(400); }); it('logs an unexpected database failure without exposing sensitive text', async () => { const logger = jest.spyOn(Logger.prototype, 'error').mockImplementation(); jest .spyOn(ctx.db.product, 'findMany') .mockRejectedValueOnce(new Error('SELECT secret password=SECRET')); const response = await ctx .api() .get('/api/v1/products') .auth(ctx.token, { type: 'bearer' }) .expect(500); expect(response.body.code).toBe('INTERNAL_FAILURE'); expect(JSON.stringify([response.body, logger.mock.calls])).not.toContain( 'SECRET', ); }); });