news 2026/9/10 23:47:52

Mastra Agent Builder 权限与 RBAC 冒烟测试指南:角色门控、权限矩阵与归属校验的端到端验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mastra Agent Builder 权限与 RBAC 冒烟测试指南:角色门控、权限矩阵与归属校验的端到端验证

Mastra Agent Builder 权限与 RBAC 冒烟测试指南:角色门控、权限矩阵与归属校验的端到端验证

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

本指南围绕 Mastra 仓库中 Agent Builder 功能分支的冒烟测试(builder-smoke-test)展开,聚焦 Studio 与 Agent Builder 场景下基于角色的访问控制(RBAC)验证。文章以.claude/skills/builder-smoke-test/references/permissions.md为骨架,结合脚手架工程中的角色映射实现与packages/server中的归属校验源码,完整讲解owner / admin / member / viewer四类角色的路由级权限门控(#16271)、组件级门控、UI 端角色模拟(#15864)以及关闭认证后的旁路行为(#16107)。读完本文,你将掌握如何在--auth on--auth off两种模式下,用 curl 对存储型 Agent/Skill 的读写、执行、发布、删除与可见性切换进行逐角色的预期状态码断言,并能从源码层面理解"404 隐藏存在性""admin 等价 owner""member 仅能改自己的记录"等设计决策。

背景:为什么需要一套独立的 RBAC 冒烟测试

Mastra 的 Agent Builder 涉及stored-agentsstored-skillsstored-workspaces等由用户创建并拥有(owner)的存储型实体。当接入 WorkOS 认证后,这些实体带上了authorIdvisibility元数据,所有读写、执行、发布、删除操作都必须经过角色与归属双重校验。为了在不依赖完整示例工程的前提下覆盖这条 EE 面,仓库在.claude/skills/builder-smoke-test/SKILL.md中定义了一个"构建器冒烟测试"技能:它通过scripts/scaffold.sh生成一个封闭(hermetic)的测试工程,并用pnpm link:将当前工作树的packages/stores/auth/等目录链接进去,从而在每次mastra dev重启后立即生效。权限/RBAC 是其中的第 11 个必测小节,可通过--test permissions单独运行,也可通过--scope rbac(包含 permissions 与 auth 两节)执行。

该小节要验证的核心内容(来自 permissions.md 开头)包括:

  • 路由级 RBAC(requiresPermission门控);
  • 组件级门控(#16271,UI 侧按角色裁剪侧边栏与按钮);
  • 仅存在于 UI 层的角色模拟(#15864,无服务端角色覆盖头);
  • 关闭认证后的全量旁路(#16107)。

默认角色与权限授予(Default roles)

脚手架工程并不依赖 core 包中的DEFAULT_ROLES,而是在自身项目的src/mastra/auth.ts中配置了 WorkOS 的roleMapping(对应仓库模板文件 auth.ts)。这份映射把四个角色的权限授予定义如下:

角色权限授予
owner*(一切权限,包括删除)
admin*(通过 WorkOS 映射与 owner 等价,见下方说明)
member*:read*:executestored-agents:writestored-skills:writestored-workspaces:write
viewer*:read

模板中MastraRBACWorkos的构造参数值得注意两点:

  1. cache: { ttlMs: 1 }—— 注释明确说明这是刻意为之:1ms 的 TTL 等效于禁用缓存,每次请求都会从 WorkOS 重新拉取角色与权限,保证测试过程中对roleMapping的改动和对上游角色的调整能立即生效,这正是冒烟测试断言"实时 RBAC 行为"的前提。
  2. _default: []—— 任何未在映射中列出的 WorkOS 角色默认不获得任何权限。

此外还有三条重要的语义说明:

  • 公共存储实体的短路读取:公开的 stored skills/agents 会短路读检查(见 authorship.ts 中assertReadAccessvisibility === 'public'的提前返回)。
  • 关闭认证直接旁路AUTH_PROVIDER未配置时,角色检查被整体跳过。
  • member 的写权限是窄的:member 可以创建/PATCH 自己名下的 stored agents/skills/workspaces(因此 Library Copy、Stars、编辑等流程可以在非管理员角色下演练),但不能:publish:delete:share。归属规则仍然生效:member PATCH 别人的记录会得到 403。这份映射只存在于脚手架工程的auth.ts,core 中的DEFAULT_ROLES保持不变。
  • WorkOS admin → owner 等价:脚手架把admin映射为['*'],所以 WorkOS 预置的 admin 在本工程中携带permissions: ["*"],能够通过 DELETE 检查。在矩阵判断中,admin 应被当作 owner 对待。

如何选定要测试的角色

--auth on模式下,冒烟测试以当前登录的 WorkOS 用户实际拥有的角色运行。--role标志(默认admin)只是 Agent 的预期值;setup 阶段会断言它与/api/auth/me返回的roles字段一致,不一致则终止运行。

本构建中没有服务端"按角色预览"请求头。UI 中的 "View as role"(角色模拟)功能纯粹是前端状态(详见 ui.md 的 Impersonation UI 小节),它不会改变 API 的返回结果。要在 API 层验证角色门控,登录用户必须真实持有该角色。

如果当前以admin登录但想测试 viewer 行为,只有两个途径:

  1. 把 WorkOS 角色改为viewer,重启mastra dev,再用--role viewer重跑;
  2. 保持--role admin运行,走 UI 专属的角色模拟流程(详见 ui.md 第 8 步)。

注意:角色模拟是纯 UI 行为。在模拟 viewer 的同时用 curl 请求同一端点,得到的仍是 admin 的响应——这是预期结果,应在报告中如实记录,而不是当作 bug 上报。

角色预期矩阵(Role expectation matrix)

以下矩阵按角色给出代表性端点的通过标准,Agent 在--role为非 admin 时会据此为每个小节设置预期状态码:

端点 / 动作owneradminmemberviewer
GET /stored/agents200200200200
GET /stored/skills200200200200
POST /stored/agents(创建)200200200403
POST /stored/skills(创建)200200200403
PATCH /stored/agents/:id(自己的)200200200403
PATCH /stored/agents/:id(他人的)200200404404
DELETE /stored/agents/:id(自己的)200200403403
PATCH /stored/skills/:idvisibility200200200403
POST /stored/skills/:id/publish200200403403
POST /agents/:id/chat(执行)200200200403
GET /editor/builder/infrastructure200200200200
PUT /stored/agents/:id/favorite200200200200

矩阵背后的两个设计要点值得展开:

  • member 之所以能对自己的记录创建/PATCH,是因为脚手架授予了stored-{agents,skills,workspaces}:write;而 publish/delete/share 仍然仅限 admin(即*)。
  • member PATCH 他人记录返回404 Not Found而非 403:可见性/归属过滤器在 handler 执行前就隐藏了该行,非属主无法区分"记录不存在"与"被禁止访问"。这是 REST 中标准的"不暴露存在性"(don't reveal existence)模式,其实现依据可在 authorship.ts 的resolveAuthorFilter中看到:非属主查询他人authorId时解析为ownedOrPublicOthers过滤器,matchesAuthorFilter只放行"既是该属主又是 public"的行。

逐步骤验证流程(Steps)

1. 确认当前登录角色

curl -s -H "$SESSION" "$BASE/auth/me" | jq '{roles, permissions}'
  • roles包含通过--role传入的值
  • permissions与"默认角色"表中该角色的授予一致

若不匹配,立即停止并参考 auth.md 第 1b 步处理。注意$SESSION取自 WorkOS 会话 Cookie;该 Cookie 是httpOnly的,无法用document.cookie在浏览器中读取,需要通过脚手架提供的调试路由GET /smoke-test/cookie(由.env中的SMOKE_TEST_COOKIE_LEAK=1开启)获取,详见 auth.md 第 0 步。此外该路由在mastra dev启动时一次性从环境变量构建,若启动后才写入该标志需要重启服务才能生效。

2. 读取对每个角色都放行

curl -s -o /dev/null -w '%{http_code}\n' -H "$SESSION" "$BASE/stored/agents" curl -s -o /dev/null -w '%{http_code}\n' -H "$SESSION" "$BASE/stored/skills"
  • 无论角色如何,两者都应返回 200
  • 响应体是 JSON,而不是 HTML 或堆栈跟踪
  • 属于其他用户的私有 agents/skills 不应出现在列表中(除非调用者是 admin/owner)

这一条对应resolveAuthorFilter的默认分支ownedOrPublic:只返回"自己的行 + 无属主的遗留行 + 任意公开行"。

3. 写操作按角色门控

按当前--role对照矩阵中的 POST 行发起请求,预期状态码见上表:

curl -s -o /dev/null -w '%{http_code}\n' -H "$SESSION" \ -X POST "$BASE/stored/agents" \ -H 'Content-Type: application/json' \ -d '{ "name": "Role Gating Test", "instructions": "x", "model": { "provider": "openai", "name": "gpt-4o-mini" } }'
  • 状态码与--role在矩阵中的预期一致
  • 403 的响应体是带错误信息的 JSON(无堆栈跟踪、无 HTML)

4. 执行与写入随资源不同(member 场景)

--role member

  • POST /stored/agents→ 200(持有stored-agents:write
  • 对现有公开 agent 执行POST /agents/:id/chat→ 200(持有:execute
  • 对自己草稿执行POST /stored/skills/:id/publish→ 403(无:publish
  • PATCH 另一位作者的stored/skills/:id→ 403(归属检查,而非权限检查)

--role viewer

  • POST /agents/:id/chat→ 403(无:execute
  • POST /stored/agents→ 403(无:write

5. 删除仅限属主

脚手架将admin映射为['*'],因此本工程中的 admin 能通过 DELETE 检查(与 owner 等价)。只有viewermember在 DELETE 时看到 403。

  • --role owner--role admin:删除自己的DELETE /stored/agents/:id→ 200
  • --role member:同样的 DELETE → 403
  • --role viewer:同样的 DELETE → 403

如果矩阵与线上响应不一致,那就是发现(finding),请记录下来;在核对脚手架auth.ts中的roleMapping之前,不要擅自"修正"矩阵。

6. 可见性切换与发布语义

stored-skills/stored-agents上的:share:publish动作没有接入路由的requiresPermission(该元数据字段定义在 packages/core/src/server/types.ts)。相反,handler 在 PATCH/POST 内部调用assertShareAccess(ctx, record)(发布有对应的等价辅助函数)。该辅助函数在以下任一条件成立时放行(源码见 authorship.ts):

  1. 记录没有属主(遗留/无主记录);
  2. 调用者是该记录的authorId
  3. 调用者持有该资源的 admin 旁路权限(如不带记录过滤的stored-skills:write);
  4. 调用者的角色授予中显式持有<resource>:share<resource>:publish

注意第 3 条依赖的hasAdminBypass会识别*<resource>:*<resource>:admin三种通配形态,且只有带资源 ID 段的细粒度授权(如agents:read:agent-123)才会被当作逐记录覆盖,宽泛的角色级授权不会二次生效,以免破坏属主/可见性模型(见 authorship.ts)。

通过 API 验证:

  • 属主能切换自己 skill 的可见性:PATCH /stored/skills/:id携带{"visibility":"public"}返回 200,且响应中的visibility"public"
  • admin 能切换非自己skill 的可见性:对他人 skill 执行相同 PATCH 返回 200
  • viewer / member 不能切换非自己 skill 的可见性:相同 PATCH 返回 403 且错误体为 JSON
  • 认证关闭模式会旁路这些检查(getCallerAuthorId(ctx)返回null时 handler 短路);记录为 "auth-off bypass",而不是当作矩阵测试

7. 关闭认证的旁路(Auth-off bypass)

注释掉.env中的AUTH_PROVIDER,重启服务,一切接口都应无需角色检查即可访问(#16107)。mastra dev只在启动时读取一次.env,因此任何改动都必须重启;建议先用.claude/skills/builder-smoke-test/scripts/preflight.sh --expect off确认模式(详见 auth.md)。

curl -s -o /dev/null -w '%{http_code}\n' "$BASE/stored/agents" curl -s "$BASE/auth/me"
  • /stored/agents返回 200
  • /auth/me返回 200 且响应体为null(不是 401,也不是用户对象)——路由把缺失的调用者解析为null而不是拒绝
  • UI 无需登录即可加载
  • 所有操作入口(affordances)均可见
  • 新建记录的authorIdnull

getCallerAuthorId的实现印证了这一点:它优先读取MASTRA_RESOURCE_ID_KEY(由authConfig.mapUserToResourceId写入),回退到认证用户对象上的user.id,两者都取不到时返回null(见 authorship.ts)。assertReadAccess等辅助函数在callerAuthorId为空且请求上下文无用户时直接放行——因为一旦配置了认证,coreAuthMiddleware会在 handler 之前用 401 拒绝未认证请求,所以"无用户"在这里只可能意味着"未配置认证"。

8. UI 门控(按角色的侧边栏 / 操作入口)

在浏览器中以--role用户登录时:

  • 与该角色权限匹配的侧边栏项可见,未授权的项被隐藏
  • 创建/编辑/删除按钮与该角色的权限一致
  • 直接导航到被门控的路由(如 viewer 访问/agent-builder/agents/:id/edit)会重定向到只读视图或被拒绝

如果--role admin(或owner),还应执行 ui.md 中的UI 角色模拟子集——这是不重新认证就能演练 viewer/member UI 门控的唯一可靠途径。该功能由role-impersonation-context.tsx实现,仅为前端状态:页面顶部出现角色预览横幅,退出入口标记为Exit role preview,且仅 admin/owner 能看到模拟菜单。

汇总清单(Checklist)

  • /auth/me的 roles 与--role一致
  • 所有角色的读操作通过
  • 写操作按矩阵通过/失败
  • 执行操作按矩阵通过/失败(member ≠ viewer)
  • 删除仅限属主
  • 可见性切换受归属 / admin 旁路 / 显式:share门控
  • 关闭认证旁路所有角色检查
  • UI 操作入口随角色收窄

源码级补充:权限校验在 Mastra 中的落点

最后把上述行为映射到仓库的实现位置,方便深入阅读:

  • RBAC 提供方与角色映射:脚手架工程的 auth.ts 中MastraRBACWorkos(来自@mastra/auth-workos)的roleMapping定义了本文全部角色矩阵的权限基础;AUTH_PROVIDER=workos时同时构造MastraAuthWorkos,未配置时两个 provider 均为undefined,Mastra 构造器收到server.auth: undefined,编辑器权限检查因此短路为"无调用者 authorId"。
  • 归属与访问断言辅助函数:authorship.ts 集中实现了getCallerAuthorIdgetCallerPermissionshasAdminBypasshasScopedPermissionresolveAuthorFiltermatchesAuthorFilter,以及assertReadAccess/assertExecuteAccess/assertWriteAccess/assertShareAccess四类断言。读/执行/写/分享四种动作的放行条件各不相同:例如visibility: 'public'足以放行读与执行,但不能放行写(编辑/删除)与分享(切换可见性),这从机制上防止了"任何能读到的人都能把私有记录公开"的越权。
  • 路由级门控元数据requiresPermission声明在 packages/core/src/server/types.ts,是路由层 RBAC 的入口;而:share/:publish刻意不走该字段,而是在 handler 内部用上述断言函数做细粒度控制。
  • 测试用例印证:归属/可见性相关行为在 authorship.test.ts 中有对应测试,可作为矩阵预期之外的补充验证手段。
  • 认证模式切换与预检AUTH_PROVIDERWORKOS_*变量的开关细节、会话 Cookie 提取、401 错误形状检查,见 auth.md。

需要注意的是,本指南的矩阵与命令均面向.claude/skills/builder-smoke-test所生成的脚手架工程,其角色映射是刻意收窄的测试配置(admin 映射为*、member 仅授予有限写权限);其他工程若自定义了roleMapping,应以各自auth.ts中的实际授予为准,先核对映射再调整预期。

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 23:46:45

EPLAN电气设计实战:变频器与PLC1500图纸设计技巧

1. EPLAN电气设计实战经验分享作为一名从事工业自动化电气设计10年的工程师&#xff0c;我深刻理解EPLAN在电气图纸设计中的重要性。今天我想分享几个实际项目中积累的EPLAN使用技巧和图纸设计经验&#xff0c;特别是针对变频器、伺服系统和西门子PLC1500等常见设备的图纸设计要…

作者头像 李华
网站建设 2026/9/10 23:46:24

DLL劫持技术与系统领空调试实战指南

1. 项目概述&#xff1a;DLL劫持与系统领空分析的核心价值逆向工程领域有个经典场景&#xff1a;当你用OllyDbg&#xff08;简称OD&#xff09;调试某个程序时&#xff0c;发现关键逻辑被封装在系统DLL中&#xff0c;常规断点根本无法拦截执行流程。这时候DLL劫持技术就派上用场…

作者头像 李华
网站建设 2026/9/10 23:45:53

《基于SpringBoot的庭院玫瑰栽培养护知识交互式科普平台设计与实现》

一、前言本系统功能全、亮点实在&#xff0c;很适合拿来当毕业设计用。平台把知识百科、栽培课堂、品种图鉴、玫瑰文化、实用价值等内容都搭了起来&#xff0c;用户能看视频、查图鉴、逛社区&#xff1b;又用协同过滤算法分析用户的浏览和收藏行为&#xff0c;做个性化首页推荐…

作者头像 李华
网站建设 2026/9/10 23:43:54

智能电梯群控系统:跨品牌调度与算法优化实践

1. 项目背景与核心价值 电梯作为现代建筑的核心垂直交通工具&#xff0c;其运行效率直接影响着整栋建筑的运营品质。传统电梯控制系统存在三个典型痛点&#xff1a;品牌间协议壁垒导致的调度割裂、高峰时段运力分配不均、特殊人群服务缺失。我们设计的这套智能群控系统&#xf…

作者头像 李华
网站建设 2026/9/10 23:43:07

冲床自动送料机设计全解析:液压系统与CAD图纸实战

“冲床自动送料机”这类课题&#xff0c;这几年在毕业设计和工厂设备改造里出现的频率非常高。原因很简单&#xff0c;它把机械结构、液压传动、电气控制三块硬内容全占了&#xff0c;再加上一整套CAD图纸和设计说明书要出&#xff0c;对综合能力的要求非常全面。去年我完整跟过…

作者头像 李华