import { Logger } from '@nestjs/common'; import type { NestExpressApplication } from '@nestjs/platform-express'; import { configureApp, describeTrustProxy, trustProxySetting, } from './app.config'; describe('trustProxySetting', () => { const original = process.env.TRUST_PROXY; afterEach(() => { if (original === undefined) delete process.env.TRUST_PROXY; else process.env.TRUST_PROXY = original; }); it('defaults to one hop when unset or blank', () => { delete process.env.TRUST_PROXY; expect(trustProxySetting()).toBe(1); process.env.TRUST_PROXY = ' '; expect(trustProxySetting()).toBe(1); }); it('parses a number as hop count and anything else as a list', () => { process.env.TRUST_PROXY = '2'; expect(trustProxySetting()).toBe(2); process.env.TRUST_PROXY = 'loopback, 10.42.0.0/16'; expect(trustProxySetting()).toBe('loopback, 10.42.0.0/16'); }); }); describe('describeTrustProxy', () => { it('reports the hop count mode and the default fallback', () => { expect(describeTrustProxy(1, false)).toBe( 'TRUST_PROXY not set, using default of 1 trusted hop', ); expect(describeTrustProxy(2, true)).toBe('TRUST_PROXY: 2 trusted hop(s)'); }); it('reports the list mode with entry count but not the entries', () => { const text = describeTrustProxy( 'loopback, 10.42.0.0/16, 2400:cb00::/32', true, ); expect(text).toBe('TRUST_PROXY: list of 3 trusted proxy range(s)'); }); }); describe('configureApp trust proxy logging', () => { it('logs the active mode once at startup', () => { const log = jest.spyOn(Logger.prototype, 'log').mockImplementation(); const app = { set: jest.fn(), useBodyParser: jest.fn(), use: jest.fn(), useGlobalFilters: jest.fn(), enableCors: jest.fn(), setGlobalPrefix: jest.fn(), enableVersioning: jest.fn(), useGlobalPipes: jest.fn(), }; configureApp(app as unknown as NestExpressApplication); expect( log.mock.calls.filter(([m]) => String(m).startsWith('TRUST_PROXY')), ).toHaveLength(1); log.mockRestore(); }); }); describe('configureApp trust proxy warning', () => { const originalProxy = process.env.TRUST_PROXY; const originalEnv = process.env.NODE_ENV; afterEach(() => { if (originalProxy === undefined) delete process.env.TRUST_PROXY; else process.env.TRUST_PROXY = originalProxy; if (originalEnv === undefined) delete process.env.NODE_ENV; else process.env.NODE_ENV = originalEnv; }); function configure(): jest.SpyInstance { const warn = jest.spyOn(Logger.prototype, 'warn').mockImplementation(); jest.spyOn(Logger.prototype, 'log').mockImplementation(); const app = { set: jest.fn(), useBodyParser: jest.fn(), use: jest.fn(), useGlobalFilters: jest.fn(), enableCors: jest.fn(), setGlobalPrefix: jest.fn(), enableVersioning: jest.fn(), useGlobalPipes: jest.fn(), }; configureApp(app as unknown as NestExpressApplication); return warn; } function trustProxyWarnings(warn: jest.SpyInstance): unknown[][] { const calls = warn.mock.calls as unknown[][]; return calls.filter(([m]) => String(m).includes('TRUST_PROXY')); } afterEach(() => jest.restoreAllMocks()); it('warnt in Produktion, wenn TRUST_PROXY fehlt', () => { process.env.NODE_ENV = 'production'; delete process.env.TRUST_PROXY; expect(trustProxyWarnings(configure())).toHaveLength(1); }); it('warnt nicht, wenn TRUST_PROXY gesetzt ist', () => { process.env.NODE_ENV = 'production'; process.env.TRUST_PROXY = 'loopback, 10.42.0.0/16'; expect(trustProxyWarnings(configure())).toHaveLength(0); }); it('warnt nicht in der Entwicklung', () => { process.env.NODE_ENV = 'development'; delete process.env.TRUST_PROXY; expect(trustProxyWarnings(configure())).toHaveLength(0); }); });