You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
按 Prime Directive #10 记录,#4093 A 档准备工作中发现。这条比 #4093 讨论的所有 plugin-dev stub 都严重,因为它不在 dev 插件里,而在 packages/runtime 的 dispatcher 里。
现象
packages/runtime/src/domains/auth.ts:
constauthService=awaitdeps.getService(CoreServiceName.enum.auth);if(authService&&typeofauthService.handler==='function'){return{handled: true,result: awaitauthService.handler(...)};}// 2. Mock fallback for MSW/test environments when no auth service is registeredreturnmockAuthFallback(normalizedPath,method,body);
mockAuthFallback 对 POST /api/v1/auth/sign-in/email(以及 login / sign-up/email / register):
按 Prime Directive #10 记录,#4093 A 档准备工作中发现。这条比 #4093 讨论的所有 plugin-dev stub 都严重,因为它不在 dev 插件里,而在
packages/runtime的 dispatcher 里。现象
packages/runtime/src/domains/auth.ts:mockAuthFallback对POST /api/v1/auth/sign-in/email(以及login/sign-up/email/register):密码根本没有被读取。任意邮箱 + 任意密码(或不带密码)→ 200 + 一个看起来完全正常的 user + session token + 24 小时有效期。
触发条件(不是 dev-only)
只要
auth槽位里没有带.handler方法的服务。具体地:os serve --preset minimal——TIER_PRESETS.minimal = ['core'],不含auth;@objectstack/plugin-auth的宿主 —— 这正是 Route parity: discovery-advertised routes must be reachable on the hono server (os serve/dev) — declared === enforced #3369 /@objectstack/restadvertisesmcpin /discovery with no way to serve it — declared ≠ enforced, and the route-parity gate'smcp: falseseam is never exercised #4024 已经认定为真实失效模式的那类("an embedder that mounts the dispatcher without plugin-mcp");handleRequest,不是handler,所以那个 stub 从来没被这个分支调用过 —— 占着槽位、被 discovery 报成stub,而真正应答/auth/*的一直是这个 mock。严重性
不是越权:mock 发出的 token 没有任何 session 存储支撑,身份解析走的是
authService.api.getSession()(packages/runtime/src/security/resolve-execution-context.ts:104-127),没有 auth 服务就返回 undefined → 请求保持匿名 →shouldDenyAnonymous照常拒绝数据访问。所以拿着mock_token_*读不到任何数据。但它是对客户端撒谎,而且是最不该撒谎的那件事:
POST /auth/sign-in/email用任意密码返回 200,是任何安全扫描/渗透测试都会直接标红的形状,无论后端是否真的放行。/analytics/query在没装 service-analytics 的装配里不注入 RLS/租户谓词,契约字段where也被静默忽略 #3891 学到的那条:"A fallback may degrade features, never security semantics" —— 而且 降级 analytics shim 把 ExecutionContext 丢在门口 ——/analytics/query在没装 service-analytics 的装配里不注入 RLS/租户谓词,契约字段where也被静默忽略 #3891 的对象(analytics shim)只是丢了 RLS 作用域,这一条是伪造认证成功。依赖面:查下来没有真实消费者
http-dispatcher.test.ts:907、domain-handler-registry.test.ts:528-531,后者断言token匹配/^mock_token_/)。../objectui:登录相关测试全部在 HTTP 客户端层自己 mock(packages/auth/src/__tests__/createAuthClient.test.ts等),不经过 dispatcher 的这个 fallback。也就是说,那句 "MSW/browser-only environments" 的理由,我在两个仓库里都找不到实际依赖它的消费者 —— 只有为它自己写的测试在支撑它。
建议
按 #3891 的先例走:退役这个 mock,空槽答 404。
/auth/*没有 auth 服务时 404,与 analytics 空槽同形 —— 这是诚实信号("没装 auth 插件"),而不是伪造一次成功登录。routes.auth按auth服务是否注册来广告,空槽时就是unavailable。目前的矛盾是 discovery 说没有、/auth/*却答 200 —— 一个declared ≠ enforced的反向实例。OS_ALLOW_*级别的显式开关),不是"槽位空了就自动伪造"。顺带:
plugin-dev的 auth dev stub 在这条修掉之前删也没有意义(它本来就没被/auth域调用)。#4093 A 档里的auth一项因此挂在这条上,我在那边也标了。关联:#4093、#4058、#4082、#3891、#3369、#4024、ADR-0076 D12。