Repository navigation
/auth/* 转发层把内部请求对象直接交给 better-auth:未知 auth 子路径(如 POST /api/v1/auth/login)返回 500 并外漏内部 TypeError,而非干净 404/405 #5085
Description
Activity
🔒 认领:PM 循环第 3 轮(cli 车道)
会话:session_01VkPSGsX9o17MsGv3Lbxu2w
分支:claude/issue-5085-auth-forward-unknown-subpath
Worktree:objectstack-issue-5085
域:domain:cli(issue 自判:若实读发现转换责任在 plugin-auth 侧,停下按 needs_decision 报告,由 PM 转 identity 车道,⛔ 不越面直改)
文件面:packages/runtime的 auth 域转发层(domains/auth.ts/ dispatcher 请求转换段)+ 测试 + changeset。与同批 #4886(packages/rest)、#5225(examples)不相交。执行口径:两半都要 —— ①未匹配 auth 子路径干净 404/405(不把内部请求形状交给 better-auth 的 fetch handler);②任何 5xx 出口过
looksLikeInternalErrorLeak消毒惯例,raw TypeError 不外漏。同日 churn(高):domains/auth.ts与 dispatcher 今日刚被 #5385 重签名(context 首参、context.kernel),issue 基线29c6c9d已旧,以 origin/main 为准复现(阳性对照 sign-in/email 应保持 200)。
Generated by Claude Code
认领解除(cli 车道 PM,session_01VkPSGsX9o17MsGv3Lbxu2w,2026-08-05 06:5xZ):本单第 3 轮派发的 dev 已被维护者手动中止,零推送、零报告、无远端分支 —— 无需回滚任何东西,前期认领评论中的执行口径与 churn 注记对下一次派发仍然有效。摘 assignee 与
pm:dispatched,回pm:queue。是否重派等维护者示意(被维护者中止的任务不由 PM 自行重启)。
Generated by Claude Code
门解除 + 重新认领(PM 会话
session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)前任 PM(
session_01VkPSGsX9o17MsGv3Lbxu2w)06:00Z 记的「维护者手动中止」经维护者本人确认为误判——那次是 dev 子代理零推送自行消失,前任推断成手动中止并立了「未经示意不得重派」的门。维护者已明确示意未中止,门解除,本单正常重派。前任认领评论里的执行口径与 churn 注记仍有效,一并沿用。- 分支:
claude/issue-5085-auth-forward-unknown-subpath - 工作树:
../objectstack-5085(os-dev 自建) - 文件面:
packages/runtime的 auth 域转发层(domains/auth.ts/ dispatcher 请求转换段)+ 测试 + changeset。 - 执行口径两半:①未匹配 auth 子路径干净 404/405(不把内部请求形状交给 better-auth 的 fetch handler);②任何 5xx 出口过
looksLikeInternalErrorLeak消毒,raw TypeError 不外漏。 - churn 注记:
domains/auth.ts与 dispatcher 已被 fix(runtime): 每个请求从自己解析出的 kernel 取服务 —— 多租户 host 上两个请求不再互相串改 (#5155) #5385 重签名(context 首参、context.kernel),issue 基线29c6c9d旧,以 origin/main 为准复现(阳性对照 sign-in/email 应保持 200)。
Generated by Claude Code
- 分支:
开工(cli 车道 dev,受 PM 会话
session_016FNvXhtSdnEGEfLEsMmvxh02:42Z 重派 [门解除已确认误判])。分支:
claude/issue-5085-auth-forward-unknown-subpath
工作树:../objectstack-5085(基线 origin/mainef4efa8,非 issue 里的29c6c9d)已在最新 main 静态复现并定位到确切成因(与 issue「疑为某次级/回退分支漏转换」判读一致,落点确实在
packages/runtime,不涉 plugin-auth):- 正常端点
POST /auth/sign-in/email→ 200:走AuthPlugin的/auth/*通配(plugin-hono-server),转发c.req.raw(真实 FetchRequest),better-auth 正常路由。 - 未知子路径
POST /auth/login→ 500 泄漏:命中packages/runtime/src/dispatcher-plugin.ts:741的遗留显式路由server.post('${prefix}/auth/login'),它把 IHttpServer 的内部req(headers是普通对象,非Headers)经handleAuth('login', …, { request: req })直接交给 better-auth 的 fetch handler,后者调request.headers.get()→TypeError: request.headers.get is not a function→ 抛到errorResponseBase(:469),而looksLikeInternalErrorLeak只匹配 SQL/driver dump、不匹配 TypeError,故 raw message 原样出体(与 issue 贴的响应体逐字吻合)。/login本就不是 better-auth 端点。
修法(两半,均在
packages/runtime,责任面属 runtime 转发层):- 半一 干净 404:删除
dispatcher-plugin.ts的遗留/auth/login显式路由 —— 它是唯一把非 Fetch 请求喂给 better-auth 的产出方(contract-first:修产出方,不在消费方加宽容)。删后/auth/login与所有其它未知子路径一样落到/auth/*通配 → better-auth 用真实Request给出它自己的干净 404,「判端点归属」的责任正确留在 better-auth 侧(无需 runtime 内建 better-auth 路由表,故不触 plugin-auth 边界)。 - 半二 5xx 出口消毒:
domains/auth.tshandleAuthRequest给handleRequest调用加 try/catch —— better-auth 抛出属非预期内部故障,按 sendError 的显式状态直通覆盖 400–599,5xx 的原始驱动报错绕过全部泄漏启发式直达客户端(metadata-protocol 有活体产出方) #5437/fix(rest): a declared 5xx no longer ships its own message to the client (#5437) #5464 现行惯例无条件扣留原文(→INTERNAL_ERROR_MESSAGE,保状态与 code,原始错误落服务端日志),覆盖 cloud AuthProxyPlugin 等任何调用方,防任何 raw 内部错外漏。
阳性对照:sign-in/email 走的是通配路径,两处改动都不碰它,保持 200。接下来写回归用例(throw→消毒 500、遗留路由已摘)+
pnpm --filter @objectstack/runtime test/typecheck + changeset,PR 开出等 CI 收敛再交报告。
Generated by Claude Code
- 正常端点
继任接手 + 重派(cli 车道 PM,会话
session_01DWUR56YsttL5sTF72Q75TQ;前任session_016FNvXhtSdnEGEfLEsMmvxh03:07Z 注销,本单为交接的唯一在飞项)现状核验:02:53Z 开工的 dev 随前任会话注销而死 —— 远程无
claude/issue-5085-auth-forward-unknown-subpath分支、无 PR、零推送。其开工评论的定位(dispatcher-plugin.ts:741遗留/auth/login显式路由把内部 req 交给 better-auth fetch handler;looksLikeInternalErrorLeak不匹配 TypeError)与两半修法作为交接诊断沿用,但零推送即零验证,重派 dev 须在最新 origin/main 上先复核再实现。- 认领:继续既有认领(assignee 与
pm:dispatched不变),本评论记录会话交接 - 分支:
claude/issue-5085-auth-forward-unknown-subpath(不变) - Worktree:
objectstack-issue-5085(本会话容器全新,dev 自建) - 域:
domain:cli;文件面:packages/runtime(dispatcher-plugin.ts/domains/auth.ts)+ 测试 + changeset;实读若发现责任面在 plugin-auth 则停手报needs_decision转 identity,⛔ 不越面直改 - 执行口径两半不变:①未知 auth 子路径干净 404/405;②任何 5xx 出口过消毒,raw TypeError 不外漏;阳性对照
sign-in/email保持 200 - churn:以最新
origin/main(5e3c83b)为准;fix(runtime): 每个请求从自己解析出的 kernel 取服务 —— 多租户 host 上两个请求不再互相串改 (#5155) #5385 已重签domains/auth.ts(context 首参、context.kernel),issue 基线29c6c9d与死 dev 基线ef4efa8均旧
Generated by Claude Code
- 认领:继续既有认领(assignee 与
认领解除(cli 车道 PM,
session_01DWUR56YsttL5sTF72Q75TQ,2026-08-06 04:1xZ):03:15Z 重派的 dev 被维护者手动中止(宿主明确回报 stopped by the user、不会恢复——本次是宿主信号,非推断,与 08-05 06:00Z 那次误判不同质)。零推送、无远端分支,无需回滚。摘 assignee 与pm:dispatched,回pm:queue。是否重派等维护者示意(被维护者中止的任务不由 PM 自行重启)。既有评论中的执行口径、churn 注记与 02:53Z 死 dev 的定位诊断对下次派发仍然有效。
Generated by Claude Code
恢复认领 + 重派(cli 车道 PM,
session_01DWUR56YsttL5sTF72Q75TQ,2026-08-06 04:2xZ):维护者已示意「重派,继续循环」,04:1xZ 中止门解除。分支claude/issue-5085-auth-forward-unknown-subpath、worktree、执行口径与 churn 注记全部沿用 03:15Z 认领评论;基线取最新 origin/main(现889ae47)。
Generated by Claude Code
- added a commit that references this issue
on Aug 6, 2026 验收:ACCEPT(cli 车道 PM,
session_01DWUR56YsttL5sTF72Q75TQ,2026-08-06 05:0xZ)→ PR #5774- 两半齐落:①删除
dispatcher-plugin.ts的遗留POST ${prefix}/auth/login显式路由(全仓唯一把非 Fetch 请求喂给 better-auth 的产出方,PM 已在 origin/main 反查引用面证实;原位留 DELIBERATELY NOT MOUNTED 墓碑注释),未知子路径统一落/auth/*通配拿 better-auth 自己的干净 404;②domains/auth.ts对 handler throw 无条件扣留原文(500 +INTERNAL_ERROR+INTERNAL_ERROR_MESSAGE,原错误进服务端日志),按 sendError 的显式状态直通覆盖 400–599,5xx 的原始驱动报错绕过全部泄漏启发式直达客户端(metadata-protocol 有活体产出方) #5437/fix(rest): a declared 5xx no longer ships its own message to the client (#5437) #5464//meta/:type上一个未分类的服务端故障被报成 HTTP 400 —— handleRouteError 的兜底把 outage 说成客户端错误 #5489 既有纪律,强于 issue 要求的启发式消毒。 - 证据硬度:三态反向验证(修前 500 逐字泄漏 / 只消毒仍 500 错类别 / 两半都在 404)+ 真实 hono boot 集成测试(假 auth service 刻意做成 better-auth 形状、通配注册在最不利顺序);阳性对照 sign-in/email 200、better-auth 自有 401 直通、无 auth service 501(dispatcher 的 /auth 域内置 mock 登录:无 auth 服务时任意邮箱+任意密码都返回 200 + 伪造 session token —— 在发行装配里,不是 dev-only #4113)均有 pin。
- CI 亲核:23 检查 0 failure,ESLint conclusion=
success(completed);changeset 在、Check Changeset 绿。 - 界外发现 仓内两处文档仍把
/api/v1/auth/login(及/register、/logout、/session)列为已注册 auth 路由 —— 四条端点均不存在 #5772(两处仓内文档列不存在的 auth 端点)已立单待分诊。
转 ready + 挂 auto-merge 入队;落地后按两读数核验(queue refs + origin/main log),MERGED 后接续派 #5613(runtime 串行队列)。
Generated by Claude Code
- 两半齐落:①删除
- added a commit that references this issue
on Aug 21, 2026 - added a commit that references this issue
on Aug 23, 2026
在 #5078 的实测定级 boot 中发现(2026-08-04,
origin/main@29c6c9d,showcase,真实 boot 非 grep 推断),未认领。查重:headers.get全仓开放 issue 零命中。实测
阳性对照:
POST /api/v1/auth/sign-in/email(better-auth 真实路由)→ 200 +set-cookie: better-auth.session_token=…,同一 boot 同一转发层,工作正常。判读
request.headers.get is not a function表明/auth/*的某条转发路径把内部请求形状(headers 为普通对象)直接交给了 better-auth 的 fetch 风格 handler(其调用request.headers.get())。已知路由(sign-in/email)工作正常,说明主转发路径有正确的Request转换 —— 疑为某个次级/回退分支漏转换。两个问题叠加:/auth/login是极易被猜到的路径(行业惯用名),真实用户/集成方会撞上;looksLikeInternalErrorLeak消毒惯例(error-envelope 一族),此路径绕过了它。落点初判(分诊改标即可)
初判落
packages/runtime的 auth 域转发层或其请求转换(domain:cli);若实读发现转换责任在plugin-auth侧,分诊时改domain:identity。修法方向:未匹配的 auth 子路径在转发前给干净 404,或补全该分支的 FetchRequest转换;任一情况下 5xx 出口过消毒。复现
pnpm dev -- --fresh --seed-admin -p <port>(showcase)→curl -X POST http://localhost:<port>/api/v1/auth/login。关联:#5078(发现现场)、#3962(「失败说 HTTP」的错误统一先例)、ADR-0076(域属主)。