branding-logo-corp.test.ts49 lines · main
1/**
2 * Branding-logo Cross-Origin-Resource-Policy override (bug: logo renders as a
3 * broken-image icon on the dashboard).
4 *
5 * The public logo route serves 200/image-png fine, but secureHeaders() stamps
6 * `Cross-Origin-Resource-Policy: same-origin` on every response — so a browser
7 * refuses to render the image when it's embedded cross-origin (dashboard at
8 * briven.tech, logo at api.briven.tech). index.ts fixes this with a path-scoped
9 * middleware registered BEFORE secureHeaders, whose post-`next()` write is the
10 * OUTERMOST and therefore wins, flipping ONLY the logo route to `cross-origin`.
11 *
12 * This test pins that ordering invariant in isolation (no DB/env): the override
13 * must win on the logo path, and every other path must stay same-origin.
14 */
15import { describe, expect, test } from 'bun:test';
16import { Hono } from 'hono';
17import { secureHeaders } from 'hono/secure-headers';
18
19const LOGO_PATH = '/v1/projects/:id/auth/branding/logo';
20
21function buildApp() {
22 const app = new Hono();
23 // Mirror index.ts ordering EXACTLY: the override is registered BEFORE
24 // secureHeaders so it wraps it and its post-next() set runs last.
25 app.use(LOGO_PATH, async (c, next) => {
26 await next();
27 c.res.headers.set('Cross-Origin-Resource-Policy', 'cross-origin');
28 });
29 app.use('*', secureHeaders());
30 app.get(LOGO_PATH, () => new Response('PNGBYTES', { headers: { 'content-type': 'image/png' } }));
31 app.get('/v1/other', (c) => c.json({ ok: true }));
32 return app;
33}
34
35describe('branding logo CORP override', () => {
36 test('logo route serves Cross-Origin-Resource-Policy: cross-origin (override wins)', async () => {
37 const app = buildApp();
38 const res = await app.request('/v1/projects/p_abc123/auth/branding/logo');
39 expect(res.status).toBe(200);
40 expect(res.headers.get('content-type')).toBe('image/png');
41 expect(res.headers.get('cross-origin-resource-policy')).toBe('cross-origin');
42 });
43
44 test('every other route keeps the secure default (same-origin)', async () => {
45 const app = buildApp();
46 const res = await app.request('/v1/other');
47 expect(res.headers.get('cross-origin-resource-policy')).toBe('same-origin');
48 });
49});