diff --git a/server/src/app.ts b/server/src/app.ts index c4788faa..24661ad7 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -112,6 +112,7 @@ export function createApp(): express.Application { if (shouldForceHttps) { app.use((req: Request, res: Response, next: NextFunction) => { + if (req.path === '/api/health') return next(); if (req.secure || req.headers['x-forwarded-proto'] === 'https') return next(); res.redirect(301, 'https://' + req.headers.host + req.url); }); diff --git a/server/tests/integration/misc.test.ts b/server/tests/integration/misc.test.ts index 3da8476b..fe0596a7 100644 --- a/server/tests/integration/misc.test.ts +++ b/server/tests/integration/misc.test.ts @@ -94,8 +94,22 @@ describe('Photo endpoint auth', () => { }); describe('Force HTTPS redirect', () => { - it('MISC-004 — FORCE_HTTPS redirect sends 301 for HTTP requests', async () => { + it('MISC-004 — FORCE_HTTPS redirect sends 301 for HTTP requests on non-health paths', async () => { // createApp() reads FORCE_HTTPS at call time, so we need a fresh app instance + process.env.FORCE_HTTPS = 'true'; + let httpsApp: Express; + try { + httpsApp = createApp(); + } finally { + delete process.env.FORCE_HTTPS; + } + const res = await request(httpsApp) + .get('/api/addons') + .set('X-Forwarded-Proto', 'http'); + expect(res.status).toBe(301); + }); + + it('MISC-008 — FORCE_HTTPS does not redirect /api/health (probes must reach it over HTTP)', async () => { process.env.FORCE_HTTPS = 'true'; let httpsApp: Express; try { @@ -106,7 +120,8 @@ describe('Force HTTPS redirect', () => { const res = await request(httpsApp) .get('/api/health') .set('X-Forwarded-Proto', 'http'); - expect(res.status).toBe(301); + expect(res.status).toBe(200); + expect(res.body.status).toBe('ok'); }); it('MISC-004 — no redirect when FORCE_HTTPS is not set', async () => {