From 91ee063fc2a4c02d05e7253b8f776f540e7c8844 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Sun, 18 Oct 2026 14:35:01 +0200 Subject: [PATCH] test(story-mode): another user's session is a 404 on both Story routes Co-Authored-By: Claude Opus 5.5 (1M context) --- test/routes/story-routes.test.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/routes/story-routes.test.ts b/test/routes/story-routes.test.ts index 92477276..5b694d05 100644 --- a/test/routes/story-routes.test.ts +++ b/test/routes/story-routes.test.ts @@ -41,6 +41,37 @@ afterEach(() => { rmSync(dir, { recursive: true, force: true }); }); +describe('Story routes: multi-user scoping', () => { + let saved: string | undefined; + beforeEach(() => { + saved = process.env.CODEMAN_MULTIUSER; + process.env.CODEMAN_MULTIUSER = '1'; + }); + afterEach(() => { + if (saved === undefined) delete process.env.CODEMAN_MULTIUSER; + else process.env.CODEMAN_MULTIUSER = saved; + }); + + it("another user's session is a 404 on both routes, its owner's a page", async () => { + writeFileSync(transcript, jsonl(demoTurn())); + const as = async (username: string) => { + const h = await createRouteTestHarness((app, ctx) => registerStoryRoutes(app, ctx), { + authUser: { username, role: 'user' }, + }); + (h.ctx._session as unknown as { owner?: string }).owner = 'alice'; + h.ctx.getTranscriptPath.mockReturnValue(transcript); + return h.app; + }; + const bob = await as('bob'); + expect((await bob.inject({ method: 'GET', url: URL })).statusCode).toBe(404); + expect((await bob.inject({ method: 'GET', url: `${URL}/helpers/abc123` })).statusCode).toBe(404); + const alice = await as('alice'); + const res = await alice.inject({ method: 'GET', url: URL }); + expect(res.statusCode).toBe(200); + expect(res.json().data.page.panels.length).toBeGreaterThan(0); + }); +}); + describe('GET /api/sessions/:id/story: which file is read', () => { it('a hook path outside the Claude projects folder is never read, nor a symlink out of it', async () => { const outside = mkdtempSync(join(tmpdir(), 'story-outside-'));