/** * route-auth-gate.test.js —— 38 号文档 Phase 1 的守卫测试 * * 只验证一件事:"这个 router 的 requireAuth/requireAdmin/requireAuthOrInternal 是不是真的 * 挂在最前面",不发真实 HTTP 请求、不碰 DB —— 结构检查:`router.stack` 里能不能找到那个 * 中间件函数本身(同一个函数引用,不是同名重写),且它排在所有具体路由(`layer.route` 有值 * 的层)前面。真正打 HTTP 会 401 由各业务测试文件顺带覆盖(jwt-auth.js 的 * FORCE_REAL_AUTH 默认在测试环境放行,这里显式打开验证真实拦截效果)。 * * 这条测试存在的理由:67 处业务路由测试全靠 supertest 直打路由,从没设过登录 cookie—— * 如果只跑那些测试,`router.use(requireAuth)` 被误删也不会被任何测试发现(默认放行, * 删不删都是 200)。这条测试专门盯"锁挂了没有"这一件事,跟业务逻辑测试互不重叠。 */ import { describe, it, expect, afterAll } from 'vitest'; process.env.NODE_ENV = 'test'; process.env.FORCE_REAL_AUTH = '1'; // 关掉 jwt-auth.js 的测试环境默认放行 const { requireAuth, requireAdmin, requireAuthOrInternal, } = require('../../middleware/jwt-auth'); /** router.stack 里有没有这个中间件函数本身,且排在第一条具体路由之前 */ function gateIndex(router, middlewareFn) { const stack = router.stack || []; return stack.findIndex((layer) => layer.handle === middlewareFn); } function firstRouteIndex(router) { const stack = router.stack || []; return stack.findIndex((layer) => !!layer.route); } function expectGated(router, middlewareFn, label) { const gateAt = gateIndex(router, middlewareFn); const routeAt = firstRouteIndex(router); expect(gateAt, `${label}: 没有挂上预期的鉴权中间件`).toBeGreaterThanOrEqual(0); expect(gateAt, `${label}: 鉴权中间件排在了具体路由后面,前面那些路由没被拦到`) .toBeLessThan(routeAt === -1 ? Infinity : routeAt); } describe('route-auth-gate(38 号文档 Phase 1)', () => { afterAll(() => { delete process.env.FORCE_REAL_AUTH; }); it('company.js 挂了 requireAuth', () => { expectGated(require('../../routes/company.js'), requireAuth, 'company.js'); }); it('tasks.js 挂了 requireAuth', () => { expectGated(require('../../routes/tasks.js'), requireAuth, 'tasks.js'); }); it('devloop.js 挂了 requireAuth', () => { expectGated(require('../../routes/devloop.js'), requireAuth, 'devloop.js'); }); it('graph-run.js 两个挂载点都挂了 requireAuth(router + companyRouter)', () => { const graphRun = require('../../routes/graph-run.js'); expectGated(graphRun, requireAuth, 'graph-run.js router'); expectGated(graphRun.companyRouter, requireAuth, 'graph-run.js companyRouter'); }); it('okr.js 挂了 requireAuth', () => { expectGated(require('../../routes/okr.js'), requireAuth, 'okr.js'); }); it('arena.js 挂了 requireAuth', () => { expectGated(require('../../routes/arena.js'), requireAuth, 'arena.js'); }); it('config.js 挂了 requireAuth', () => { expectGated(require('../../routes/config.js'), requireAuth, 'config.js'); }); it('evolution.js 挂了 requireAuth', () => { expectGated(require('../../routes/evolution.js'), requireAuth, 'evolution.js'); }); it('whatsapp-auth.js 挂了 requireAuth', () => { expectGated(require('../../routes/whatsapp-auth.js'), requireAuth, 'whatsapp-auth.js'); }); it('dream.js 挂了 requireAdmin(系统级,只有 admin 能看,不是登录即可看)', () => { expectGated(require('../../routes/dream.js'), requireAdmin, 'dream.js'); }); it('agent-chat.js 挂了 requireAuthOrInternal(不是普通 requireAuth——三处服务端自环调用要放行)', () => { expectGated(require('../../routes/agent-chat.js'), requireAuthOrInternal, 'agent-chat.js'); }); it('open-api.js 不该挂 cookie 鉴权(它自己一套 OPEN_API_KEYS 体系,面向外部 Skill 市场调用方)', () => { const openApi = require('../../routes/open-api.js'); expect(gateIndex(openApi, requireAuth)).toBe(-1); expect(gateIndex(openApi, requireAuthOrInternal)).toBe(-1); }); it('auth.js 自身不挂全局鉴权(登录/注册端点必须对未登录用户可达)', () => { const auth = require('../../routes/auth.js'); expect(gateIndex(auth, requireAuth)).toBe(-1); }); });