新增 leo21c-mcp-guard.sh:擋下打向 leo 真庫的 Arcrun/KBDB MCP 呼叫(ISEP#69)

leo 2026-08-27:「我從頭的指令就叫你去打 youlin,stage 環境是它你不知道嗎?
為什麼打算用我的真庫測試?」

實況(總管當天實查):這台機器同時掛兩條 Arcrun MCP 連線,工具名是兩串 UUID——
mcp__00402d88-...__* → logged_in_as: leo21c(真庫),mcp__d0eaf65b-...__* →
logged_in_as: youlin(測試場)。總管整天用第一條,測試資料卻寫在第二條,
造成三次假結論(「wiki 沒送上去」「排在 1691 筆後面」「ingest 沒寫進去」——
全是查錯庫),而總管自己每張派工單都寫著「測試一律用 youlin」,卻一次都沒套用。

判準:任何打向 leo21c 座標的 kbdb_*/arcrun_* MCP 呼叫一律擋,除非明說
(touch /tmp/.leo21c-mcp-ok,單次 15 分鐘、會留痕到 .claude/hooks/
leo21c-mcp-guard.log)。讀寫都擋,但訊息不同:唯讀提示「你可能查錯地方」,
寫入提示「這會汙染真資料」。arcrun_whoami 本身永遠放行(唯一能確認身份的
工具,擋它會造成死結)。

已知限制(查過但查不到穩定識別法,不是猜測):MCP server 的 UUID 是這次連線
分配的,不是穩定識別碼,重裝/換 session 會換掉;~/.claude.json 等本機設定檔
裡找不到這兩條連線的來源設定,判斷是雲端 connector 層動態配的。因此這兩個
UUID 是寫死的(2026-08-27 由 arcrun_whoami 實測得到),且會過期。設計上不是
「表格以外的一律放行」,而是「不在表格裡的 UUID 一樣擋,且訊息明講清單可能
過期」——大聲失敗,不靜默放行到身份不明的目標(fail-closed)。

測試:hooks/tests/leo21c-mcp-guard.test.sh 19/19 通過,涵蓋擋(真庫讀/寫)、
放行(測試場讀/寫)、不擋(whoami 三種座標)、不擋(無關工具)、擋(未知UUID)、
戳記單次放行+留痕。既有測試套件(ask-user-question/dispatch-format/
factory-idle/main-and-prod-push/prod-write/stage-before-prod/sdd-guard)
全部重跑一遍,均維持原本通過狀態,未受本次改動影響。

hooks.json 新增一條 PreToolUse matcher:.*mcp__[0-9a-fA-F-]+__(kbdb_|arcrun_).*
docs/hooks-inventory.md 補上新閘一行,並記錄目前實際磁碟數(49 檔/60 條)
跟這份表既有列表(47/57)之間還有既存落差(isep-presence-beacon.sh/
milestone-due-guard.sh 疑似兩支舊閘未收錄)——不是本票動的閘,未一併查證,
留給總管或後續票核實。

plugin.json 0.5.0 → 0.5.1(改完不升版沒人吃得到;check-version-consistency.sh
在本分支照慣例是紅的,tag 於 merge 時打)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 15:01:29 +08:00
parent 8e28041ba4
commit b8060ca263
5 changed files with 293 additions and 6 deletions
+9 -4
View File
@@ -1,4 +1,4 @@
# 46 支閘,白話盤點表
# 47 支閘,白話盤點表
> 回應 `inkstone/InkStoneCo#40`:「如果加入了,我應該可以白話文看到 hooks 的內容?」
> 這份表就是那個「白話文」——不用點開任何 `.sh` 檔,一行看懂一支閘在管什麼。
@@ -7,14 +7,18 @@
## 一句話結論
`hooks/` 底下有 **46 個 `.sh` 檔**`hooks.json` 實際掛上 **56 條註冊**(同一支閘常被多種情境同時掛上);
`hooks/` 底下有 **47 個 `.sh` 檔**`hooks.json` 實際掛上 **57 條註冊**(同一支閘常被多種情境同時掛上);
其中 **3 支檔案存在但沒被掛上**(2 支是待人填的空範本、1 支是刻意留著沒開的止血帶,見下面「未生效」表)。
下面按「你會在什麼時候撞到它」分組,一支一行。
> 🔴 **這兩個數字上一版是錯的(2026-08-26 實際數過才發現)**:本頁原本寫「43 個檔、53 條註冊」,
> 而當時真實是 **45 個檔、55 條註冊**——中間有兩支閘進來時沒有回頭改這裡。
> 現在的寫法是實際數出來的:
> `ls hooks/*.sh | wc -l` 46`hooks.json` 展開後的 command 條目 56。
> +1+1 是本次(ISEP#69)新增的 `leo21c-mcp-guard.sh`。
>
> ⚠️ **這份表本身可能又已經漂移**`ls hooks/*.sh | wc -l` 在本分支實測是 49
> (比這裡寫的 47 多 2),初步比對疑似是 `isep-presence-beacon.sh`
> `milestone-due-guard.sh` 兩支已經掛進 `hooks.json` 卻沒被收進這張表——
> 但那兩支不是本票(ISEP#69)動的閘,沒有一併查證+改動,留給總管或後續票核實。
> **一份會偷偷過期的盤點表,跟沒有盤點表差不多**——見本頁最後「怎麼跟實況對帳」那段。
---
@@ -42,6 +46,7 @@
| `prod-write-guard.sh` | AI 想做任何「會真的改到線上正式帳號(leo21c)」的操作(不只是 push,也包含直接呼叫會寫入的工具)就擋下,交回總管處理。 | 🛑 擋 |
| `not-my-branch-guard.sh` | AI 想 commit 到「別的 subagent 正在施工中」的分支(登記在 `branch-holds.md`)就擋下,避免兩個 AI 互踩同一條分支。 | 🛑 擋 |
| `leo21c-write-guard.sh` | AI 想寫東西到你私人帳號 `leo21c` 就擋下——這個帳號只准你自己用,AI 的實驗一律走別的測試帳號。 | 🛑 擋 |
| `leo21c-mcp-guard.sh` | AI 想用 ArcrunKBDB 的 MCP 工具查或寫**你的真庫(leo21c)**就擋下(不管讀寫)——測試場是另一條 MCP 連線,沒指定就該用那條。`arcrun_whoami` 本身不擋(用來確認身份);真的要碰真庫要明說(`touch /tmp/.leo21c-mcp-ok`),會留痕。連線的 server id 若不在已知清單裡也擋(清單可能過期,寧可先擋不要靜默放行)。 | 🛑 擋 |
| `release-tag-guard.sh` | AI 想打版本 tag,但 `plugin.json` 裡寫的版本號跟 tag 對不上就擋下——避免「這裡說 0.2.0、那裡說 0.1.0」各說各話。 | 🛑 擋 |
| `ticket-api-bypass-guard.sh` | AI 想繞過 `scripts/ticket` 工具、直接打 API 開新 Gitea 票(會漏掉「開票前先搜過」這道檢查)就擋下。 | 🛑 擋 |
| `reply-identity-guard.sh` | 直接打 Gitea API 貼留言到票上時,內文第一行沒有 `【身份】``總管``subagent``leo`)就擋下——票上多條線並行時,看不出哪一則是誰寫的。純讀取、走 `scripts/ticket` 正門、指令裡加 `reply-identity-ok` 都放行。 | 🛑 擋 |