import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { authenticateTelemetry } from '../../src/lib/server/auth/telemetry.js'; import { newFixture, type Fixture } from '../helpers/fixture.js'; import { gameEvent } from '../helpers/telemetry.js'; const token = 'ec_telemetry_0123456789abcdef0123456789abcdef'; const otherToken = 'ec_telemetry_fedcba9876543210fedcba9876543210'; const request = (values: Record = {}, url = 'http://localhost/api/telemetry') => { const headers = new Headers({ 'Content-Type': 'application/json' }); for (const [key, value] of Object.entries(values)) if (value !== undefined) headers.set(key, value); return new Request(url, { method: 'POST', headers, body: JSON.stringify(gameEvent('heartbeat')) }); }; beforeEach(() => { vi.stubEnv('EC_TELEMETRY_TOKEN', token); }); afterEach(() => { vi.unstubAllEnvs(); vi.restoreAllMocks(); }); describe('machine telemetry credentials', () => { it.each([ { Authorization: `Bearer ${token}` }, { authorization: `bearer ${token}` }, { 'X-EC-Telemetry-Token': token }, { Authorization: `Bearer ${token}`, 'X-EC-Telemetry-Token': token } ])('accepts an explicit telemetry secret without a browser session: %j', headers => { expect(authenticateTelemetry(request(headers))).toEqual({ ok: true }); }); it.each([undefined, '', 'too-short', 'x'.repeat(513), 'x'.repeat(40) + ' not-header-safe'])('fails closed when configuration is unusable: %s', configured => { vi.stubEnv('EC_TELEMETRY_TOKEN', configured); expect(authenticateTelemetry(request({ Authorization: `Bearer ${token}` }))).toMatchObject({ ok: false, status: 503 }); }); it.each([ {}, { Cookie: `ec_session=${token}` }, { Authorization: `Bearer ${otherToken}` }, { 'X-EC-Telemetry-Token': otherToken }, { Authorization: `Basic ${token}`, 'X-EC-Telemetry-Token': token }, { Authorization: `Bearer ${token}` }, { Authorization: `Bearer ${token}, Bearer ${token}` }, { Authorization: `Bearer ${token}`, 'X-EC-Telemetry-Token': otherToken }, { Authorization: `Bearer ${otherToken}`, 'X-EC-Telemetry-Token': token }, { Authorization: 'Bearer short', 'X-EC-Telemetry-Token': token }, { Authorization: `Bearer ec_host_${'1'.repeat(43)}` }, { Authorization: `Bearer ec_enroll_${'1'.repeat(43)}` } ])('rejects missing, wrong, ambiguous or unrelated credentials: %j', headers => { const authentication = authenticateTelemetry(request(headers)); expect(authentication).toMatchObject({ ok: false, status: 401 }); expect(JSON.stringify(authentication)).not.toContain(token); expect(JSON.stringify(authentication)).not.toContain(otherToken); }); it('does not accept tokens placed in query parameters', () => { expect(authenticateTelemetry(request({}, `http://localhost/api/telemetry?token=${token}`))).toMatchObject({ ok: false, status: 401 }); }); it('retains existing transport behavior for authenticated local machine relays', () => { expect(authenticateTelemetry(request({ 'X-EC-Telemetry-Token': token }, 'http://controller.internal/api/telemetry'))).toEqual({ ok: true }); }); it('uses the current configured token after rotation and safely rejects differing token lengths', () => { expect(authenticateTelemetry(request({ Authorization: `Bearer ${token}` }))).toEqual({ ok: true }); vi.stubEnv('EC_TELEMETRY_TOKEN', otherToken); expect(authenticateTelemetry(request({ Authorization: `Bearer ${token}` }))).toMatchObject({ ok: false, status: 401 }); expect(authenticateTelemetry(request({ Authorization: `Bearer ${otherToken}` }))).toEqual({ ok: true }); expect(authenticateTelemetry(request({ Authorization: `Bearer ${'x'.repeat(32)}` }))).toMatchObject({ ok: false, status: 401 }); }); }); describe('telemetry endpoint authentication boundary', () => { let fixture: Fixture; beforeEach(async () => { vi.resetModules(); fixture = await newFixture(); const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); await seedServerRegistry(); }); afterEach(async () => { await fixture.cleanup(); }); it.each([401, 503])('returns %s before parsing or storing untrusted evidence', async status => { if (status === 503) vi.stubEnv('EC_TELEMETRY_TOKEN', undefined); const { POST } = await import('../../src/routes/api/telemetry/+server.js'); const { db } = await import('../../src/lib/server/db/index.js'); const { listTelemetry } = await import('../../src/lib/server/fleet/telemetry.js'); const { subscribe } = await import('../../src/lib/server/pipeline/bus.js'); const incoming = request({ Cookie: 'ec_session=browser-user' }); const parse = vi.spyOn(incoming, 'json'); const listener = vi.fn(); const unsubscribe = subscribe(listener); const response = await POST({ request: incoming }); unsubscribe(); expect(response.status).toBe(status); expect(response.headers.get('cache-control')).toBe('no-store'); expect(parse).not.toHaveBeenCalled(); expect(incoming.bodyUsed).toBe(false); expect(listTelemetry()).toEqual([]); expect(db().prepare('SELECT COUNT(*) AS count FROM telemetry_requests').get()).toEqual({ count: 0 }); expect(listener).not.toHaveBeenCalled(); }); it('accepts authenticated automation with the unchanged event payload and excludes headers from diagnostics', async () => { const { POST } = await import('../../src/routes/api/telemetry/+server.js'); const { listTelemetryRequests } = await import('../../src/lib/server/fleet/telemetry-requests.js'); const payload = gameEvent('heartbeat'); const response = await POST({ request: request({ 'X-EC-Telemetry-Token': token }) }); expect(response.status).toBe(200); expect(await response.json()).toMatchObject({ ok: true, telemetry: payload }); const history = listTelemetryRequests(payload.server); expect(history).toHaveLength(1); expect(JSON.stringify(history)).not.toContain(token); expect(JSON.parse(history[0].payload!)).toEqual(payload); }); });