// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 第十三批回归闸门:用户/风控读接口的敏感字段与鉴权收口 */ describe('第十三批用户读接口隐私闸门 (全量用户 / 360画像 / 风控日志 / 个人资产)', () => { const rootDir = path.resolve(__dirname, '../../'); const indexCode = fs.readFileSync(path.join(rootDir, 'server/src/index.ts'), 'utf-8'); const routeBlock = (marker: string, len = 1600) => { const start = indexCode.indexOf(marker); expect(start).toBeGreaterThan(-1); return indexCode.slice(start, start + len); }; describe('1. 管理端专属读接口必须鉴权', () => { it('全量用户列表仅管理员可见', () => { expect(indexCode).toContain("app.get('/api/users', requireAdmin"); }); it('用户360画像仅管理员可见', () => { expect(indexCode).toContain("app.get('/api/users/:id/detail', requireAdmin"); }); it('风控日志仅管理员可见', () => { expect(indexCode).toContain("app.get('/api/safety/audit-logs', requireAdmin"); }); }); describe('2. 用户基本信息:敏感字段仅本人/管理员可见', () => { it('GET /api/users/:id 必须做本人/管理员判断并剥离敏感字段', () => { const block = routeBlock("app.get('/api/users/:id',", 8000); expect(block).toContain('isVerifiedAdminRequest(req)'); expect(block).toContain('publicUser'); expect(block).not.toContain('phone: user.phone'); expect(block).not.toContain('balance: user.balance'); }); }); describe('3. 个人资产/流水仅本人可读', () => { it('提现记录与财务流水必须经 resolveSecureUserId', () => { expect(routeBlock("app.get('/api/users/:id/withdrawals'")).toContain("'查看提现记录'"); expect(routeBlock("app.get('/api/users/:id/finance-records'")).toContain("'查看财务流水'"); }); }); });