test(authz): e2e-prove the MCP HTTP surface is identity-admitted; upgrade the matrix row to high-risk (#3167)#3225
Merged
Conversation
…rade the matrix row to high-risk (#3167) PR-B of #3167. During implementation the premise shifted: the CLI ALREADY auto-loads MCPServerPlugin in `os serve`/`dev` when isMcpServerEnabled() (serve.ts — requires.push('mcp')), on the SAME decision point that gates the dispatcher /mcp route, with stdio staying opt-in. So decisions A/B/C (dev default-on, HTTP-only, unified off-switch) were already shipped — my #3167 "wired nowhere" claim was a stale read (a grep of the wrong path). The one genuinely-missing piece was the end-to-end proof the mcp-http-identity row (#3202) explicitly deferred. This lands that proof: showcase-mcp-http-identity.dogfood.test.ts boots the real showcase + security + MCPServerPlugin and drives POST /api/v1/mcp through the real HTTP + RLS stack: - an anonymous MCP tools/call is 401 before any tool runs (fail-closed); - a member's query_records over the owner-private showcase_private_note returns ONLY their own rows, symmetric across two members — if the tool had run unscoped/system (the stdio posture, mcp-stdio-authority) the other owner's rows would leak, so this is the load-bearing RLS-through-MCP assertion; - tool discovery (tools/list) is gated on the same admitted identity. The mcp-http-identity matrix row is upgraded to HIGH_RISK with this proof, closing the deferral noted on it in #3202. Dispatcher-level unit coverage (http-dispatcher.mcp.test.ts 401 + EC-to-bridge; .mcp-oauth.test.ts scope 403) already existed; this adds the whole-stack authorization outcome the unit mocks cannot show. Test-only + a dev-dep on @objectstack/mcp in the private @objectstack/dogfood gate — no runtime change, no changeset. authz-conformance + the new proof: 13/13 green locally. Refs #3167, ADR-0096, ADR-0056 D10, #3202, #2698. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 18, 2026 15:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#3167 的 PR-B。实现过程中前提再次变化——而且这次是个好消息:接线早已存在。
关键发现:决策 A/B/C 早已 ship
serve.ts在isMcpServerEnabled()为真时requires.push('mcp'),与 dispatcher/mcp路由同一决策点自动加载MCPServerPlugin;os devspawnos serve --dev继承之;stdio 仍 opt-in。也就是说我们"批准"的三个决策——dev 默认开、仅 HTTP、off-switch 统一——平台早就实现了(甚至 serve/prod 也默认开,因为准入已强制所以安全)。我 #3167 里"从未接线"的判断是过时误读(当初 grep 了不存在的packages/tools/cli,实际在packages/cli)。已在 #3167 更新说明。所以 PR-B 唯一真正缺的,是
mcp-http-identity行(#3202)明确延后的那块——端到端证明。本 PR:补上端到端证明 + 升级矩阵行
showcase-mcp-http-identity.dogfood.test.ts启动真实 showcase + 安全栈 + MCPServerPlugin,经真实 HTTP + RLS 栈驱动POST /api/v1/mcp:tools/call→ 401(任何工具执行之前 fail-closed);query_recordsover owner-privateshowcase_private_note→ 只返回自己的行,两个成员对称——若工具跑在无 scope/system(即 stdio 姿态)下,另一 owner 的行就会泄漏,所以这是 RLS-穿透-MCP 的承重断言;tools/list)同样受已准入身份门控。mcp-http-identity行升级为 HIGH_RISK + proof,关掉 #3202 在该行留的延后注记。dispatcher 层单元覆盖(http-dispatcher.mcp.test.ts的 401 + EC-传-bridge;.mcp-oauth.test.ts的 scope 403)本已存在;本 proof 补上单元 mock 无法展示的整栈授权结果。范围与验证
@objectstack/dogfood门包加一个@objectstack/mcpdev-dep;不动运行时、不改任何默认(接线本就在 main 上)→ 无 changeset。authz-conformance+ 新 proof 13/13 绿;checkLedger 校验通过(high-risk 有 proof、proof 文件存在、基线 sound);eslint 干净。剩余可选项(未纳入本 PR,保持聚焦):dev 启动打印 MCP 连接指引(URL / skill / connect-UI)——纯 DX 补充,值得单独小改。
Refs #3167(PR-B)、ADR-0096、ADR-0056 D10、#3202、#2698。
🤖 Generated with Claude Code
https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
Generated by Claude Code