From a1d1f99216e53c0051043b7fb50e0ace47822b88 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Mon, 4 May 2026 19:56:41 +0200 Subject: [PATCH] proxy: add /ideas to protectedRoutes; verify demo-guard for /api/ideas (M12 T-501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - proxy.ts: /ideas added to protectedRoutes — unauthenticated users get redirected to /login when navigating to /ideas or /ideas/[id] - existing demo-guard catch-all (\`/api/* + non-GET\`) already blocks POST/PATCH/DELETE /api/ideas* with 403 — confirmed via 3 new tests - server-action endpoints (start-grill / start-make-plan / materialize / promote-to-idea) carry their own \`session.isDemo\` checks inside actions/ideas.ts and actions/todos.ts (defense in depth) Tests: 9/9 in proxy demo-guard suite (added 3 idea cases). Co-Authored-By: Claude Opus 4.7 (1M context) --- __tests__/proxy/demo-guard.test.ts | 20 ++++++++++++++++++++ proxy.ts | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/__tests__/proxy/demo-guard.test.ts b/__tests__/proxy/demo-guard.test.ts index f229a8f..1ae94a2 100644 --- a/__tests__/proxy/demo-guard.test.ts +++ b/__tests__/proxy/demo-guard.test.ts @@ -30,6 +30,26 @@ beforeEach(() => { }) describe('proxy demo-guard', () => { + it('demo + POST /api/ideas → 403 (M12)', async () => { + mockUnsealData.mockResolvedValue({ userId: 'demo-user', isDemo: true }) + const req = makeRequest('POST', '/api/ideas', true) + const res = await proxy(req) + expect(res?.status).toBe(403) + }) + + it('demo + PATCH /api/ideas/abc → 403 (M12)', async () => { + mockUnsealData.mockResolvedValue({ userId: 'demo-user', isDemo: true }) + const req = makeRequest('PATCH', '/api/ideas/abc', true) + const res = await proxy(req) + expect(res?.status).toBe(403) + }) + + it('demo + GET /api/ideas → passthrough (M12)', async () => { + const req = makeRequest('GET', '/api/ideas', true) + const res = await proxy(req) + expect(res?.status).not.toBe(403) + }) + it('demo + POST /api/todos → 403', async () => { mockUnsealData.mockResolvedValue({ userId: 'demo-user', isDemo: true }) const req = makeRequest('POST', '/api/todos', true) diff --git a/proxy.ts b/proxy.ts index afbfd55..24fc34d 100644 --- a/proxy.ts +++ b/proxy.ts @@ -3,7 +3,7 @@ import type { NextRequest } from 'next/server' import { unsealData } from 'iron-session' import { sessionOptions, type SessionData } from '@/lib/session' -const protectedRoutes = ['/dashboard', '/products', '/todos', '/settings', '/solo'] +const protectedRoutes = ['/dashboard', '/products', '/todos', '/ideas', '/settings', '/solo'] const authRoutes = ['/login', '/register'] const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS'])