projects.test.ts57 lines · main
1// apps/api/src/routes/projects.test.ts
2//
3// Probe test for Task A5: confirm `POST /v1/projects` is reachable under a
4// CLI-minted Bearer JWT and is NOT shot down by the CSRF origin guard.
5//
6// Env vars must be set BEFORE any module that reads them is imported. The
7// auth + db modules call into env at evaluation, so we mutate process.env
8// first and pull every framework module in via dynamic import — mirroring
9// the pattern in apps/api/src/routes/auth-cli.test.ts.
10//
11// We don't try to stand up postgres in unit tests. The KEY assertion is
12// that the response status is NOT 403 csrf_origin_rejected. A 401 from
13// the bearer user-lookup (missing row) or a 500 from the DB being
14// unreachable are both acceptable — both prove the request made it past
15// CSRF and reached the route handler / requireAuth bearer branch.
16
17const ORIGINAL_SECRET = process.env.BRIVEN_BETTER_AUTH_SECRET;
18const ORIGINAL_DB_URL = process.env.BRIVEN_DATABASE_URL;
19process.env.BRIVEN_BETTER_AUTH_SECRET = ORIGINAL_SECRET ?? 'a'.repeat(32);
20process.env.BRIVEN_DATABASE_URL = ORIGINAL_DB_URL ?? 'postgres://test:test@127.0.0.1:5/test';
21
22import { afterAll, describe, expect, it } from 'bun:test';
23import type { AppEnv } from '../types/app-env.js';
24
25describe('POST /v1/projects via CLI JWT', () => {
26 it('accepts a Bearer cli token without rejecting on CSRF', async () => {
27 const { Hono } = await import('hono');
28 const { signCliToken } = await import('../lib/cli-jwt.js');
29 const { csrfOriginCheck } = await import('../middleware/csrf.js');
30 const { projectsRouter } = await import('./projects.js');
31
32 const app = new Hono<AppEnv>();
33 app.use('*', csrfOriginCheck());
34 app.route('/', projectsRouter);
35
36 const token = await signCliToken('u_proj_post_test');
37 const res = await app.request('/v1/projects', {
38 method: 'POST',
39 headers: {
40 authorization: `Bearer ${token}`,
41 'content-type': 'application/json',
42 },
43 body: JSON.stringify({ name: 'cli-post-test', region: 'eu-west' }),
44 });
45
46 // No DB → 401 from bearer user-lookup or 500 from db acceptable.
47 // KEY assertion: status is NOT 403 csrf_origin_rejected.
48 expect(res.status).not.toBe(403);
49 });
50});
51
52afterAll(() => {
53 if (ORIGINAL_SECRET === undefined) delete process.env.BRIVEN_BETTER_AUTH_SECRET;
54 else process.env.BRIVEN_BETTER_AUTH_SECRET = ORIGINAL_SECRET;
55 if (ORIGINAL_DB_URL === undefined) delete process.env.BRIVEN_DATABASE_URL;
56 else process.env.BRIVEN_DATABASE_URL = ORIGINAL_DB_URL;
57});