import request from 'supertest'; import app from '../../src/app'; import { pool } from '../../src/db'; import { resetDb, closeDb } from './setup/testDb'; // ADMIN_GATE_SECRET is read per request rather than at import, so it can be set // here without reloading the app, and is restored afterwards so this file // cannot change how anything later in the same process behaves. Same shape as // adminGate.integration.test.ts. const SECRET = 'integration-version-secret'; const original = process.env.ADMIN_GATE_SECRET; let warn: jest.SpyInstance; beforeEach(async () => { await resetDb(); warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined); }); afterEach(() => { warn.mockRestore(); if (original === undefined) { delete process.env.ADMIN_GATE_SECRET; } else { process.env.ADMIN_GATE_SECRET = original; } }); afterAll(async () => { await pool.end(); await closeDb(); }); describe('reporting which build is running', () => { it('returns a commit and a build time', async () => { const res = await request(app).get('/api/admin/version'); expect(res.status).toBe(200); expect(typeof res.body.commit).toBe('string'); expect(res.body.commit.length).toBeGreaterThan(0); // Null under test, where nothing has been built. The contract is that the // key is always present, so the admin never has to distinguish "absent" // from "unbuilt". expect(res.body).toHaveProperty('builtAt'); }); // The whole point is that this is not on public /api/config. A commit hash // there would tell any visitor which revision of a public repository is // deployed. it('is behind the admin gate', async () => { process.env.ADMIN_GATE_SECRET = SECRET; const res = await request(app).get('/api/admin/version'); expect(res.status).toBe(403); expect(res.body.error).toBe('forbidden'); }); it('does not leak the commit through the public config endpoint', async () => { const res = await request(app).get('/api/config'); expect(res.status).toBe(200); expect(res.body).not.toHaveProperty('commit'); expect(res.body).not.toHaveProperty('builtAt'); }); });