#!/usr/bin/env bash # leo21c-write-guard.sh 的迴歸測試(inkstone/ISEP#130) # # ── 這支在守什麼 ────────────────────────────────────────────────────── # 閘的判準是「**讀可以,寫不行**」(leo 2026-08-20:leo21c 是他本人在用的知識庫)。 # 2026-09-04 雲端 Routine 的 run log:**讀 notify_leo 的定義被擋** —— # 讀都讀不到,雲端就什麼都拿不到(inkstone/ISEP#130 開票的第一件)。 # # 這支之前**沒有任何測試**,所以「讀會不會被誤攔」從來沒被驗過。 # 下面的測資是 Routine 文件(cloud-worker.md/progress-guard.md)裡**真的會下的那幾條指令**, # 不是想像出來的例子。 # # 🔴 三個方向都要驗,缺一個就是假綠: # A 讀 ⇒ 放行(含 `tr -d`/`cut -d=` 這種唯讀的 -d,那正是 09-04 被擋的形狀) # B 寫 ⇒ 擋(心跳 POST/PATCH 收件匣/部署端點/別的 trigger) # C 閘印出來的「改法」指的是**現役**的 youlin 網址,不是 09-02 已死的舊名 # # 這支閘不寫任何檔案,直接跑真跡即可;全程離線。 # 用法:bash hooks/tests/leo21c-write-guard.test.sh set -u HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) HOOK="$HERE/../leo21c-write-guard.sh" PASS=0; FAIL=0 mk(){ python3 -c "import json,sys;print(json.dumps({'tool_name':'Bash','tool_input':{'command':sys.argv[1]}}))" "$1"; } t(){ # t <期望 pass|block> <說明> <指令> LAST_ERR=$(mk "$3" | bash "$HOOK" 2>&1 >/dev/null); rc=$? got=$([ "$rc" -eq 2 ] && echo block || echo pass) if [ "$got" = "$1" ]; then echo " ✅ $2"; PASS=$((PASS+1)) else echo " ❌ $2 —— 期望 $1,實得 $got(rc=$rc)"; FAIL=$((FAIL+1)); fi } L='https://arcrun-cypher-executor.leo21c.workers.dev' K='-H "X-Arcrun-API-Key: leo"' D='-d' echo "── A. 讀 ⇒ 放行(雲端 Routine 真的會下的形狀)──" t pass "① 讀收件匣(progress-guard.md 步驟 0 原句)" "curl -s \"$L/kbdb/entries?entry_type=inbox&limit=20\" $K" t pass "② 讀 notify_leo 定義(09-04 被擋的那一條)" "curl -s $L/webhooks/named/leo/notify_leo $K" t pass "③ 讀 + tr -d(唯讀的 -d,不是 body)" "curl -s $L/workflows/notify_leo $K | tr $D '\\r'" t pass "④ 讀 + cut -d=" "NS=\$(grep ns cfg | cut ${D}= -f2); curl -s $L/kbdb/entries?limit=1 $K" t pass "⑤ 讀 + sort -d / date -d" "curl -s $L/health | sort $D; date $D yesterday" t pass "⑥ 明寫 -X GET" "curl -s -X GET $L/kbdb/entries?entry_type=dash_beat $K" t pass "⑦ 讀心跳(progress-guard 2.6 原句)" "curl -s \"$L/kbdb/entries?entry_type=dash_beat&limit=30\" $K" t pass "⑧ git commit 訊息提到 leo21c 與 POST(git 寫不到那台)" "git commit -m 'fix: curl -X POST $L/kbdb/entries 會被擋'" t pass "⑨ 修這道閘自己" "sed -i 's/a/b/' hooks/leo21c-write-guard.sh" t pass "⑩ 打 youlin(09-02 起的新子網域)POST,不是 leo21c" "curl -X POST https://arcrun-cypher-executor.arcrun-yuga3bse.workers.dev/webhooks/named $D '{}'" t pass "⑪ 用 youlin 的 CF 帳號部署" "CLOUDFLARE_ACCOUNT_ID=1129efd7df2e8899d537e9c8fbabb6cb npx wrangler deploy" t pass "⑫ 發一則 notify_leo(通知型 trigger,什麼都沒改;同 prod-write-guard 白名單)" "curl -s -X POST $L/webhooks/named/leo/notify_leo/trigger -H 'Content-Type: application/json' $D '{\"text\":\"[總管] hi\"}'" echo "── B. 寫 ⇒ 擋 ──" t block "⑬ 打心跳 POST(cloud-worker.md 步驟 0 原句——它寫進 leo 的庫)" "curl -s -X POST \"$L/kbdb/entries\" $K -H 'Content-Type: application/json' $D '{\"entry_type\":\"dash_beat\"}'" t block "⑭ PATCH 收件匣" "curl -s -X PATCH \"$L/kbdb/entries/123\" $K $D '{\"content\":\"x\"}'" t block "⑮ DELETE" "curl -X DELETE $L/kbdb/entries/1 $K" t block "⑯ 只帶 -d 的隱式 POST" "curl $L/kbdb/entries $D '{}'" t block "⑰ --data-urlencode" "curl $L/kbdb/entries --data-urlencode text=hi" t block "⑱ --request PUT" "curl --request PUT $L/kbdb/entries/1 $D '{}'" t block "⑲ 別的工作流 trigger(ship_refresh_cdn 會動線上狀態)" "curl -X POST $L/webhooks/named/leo/ship_refresh_cdn/trigger $D '{}'" t block "⑳ 部署端點(無名字的 named webhook)" "curl -X POST $L/webhooks/named $D @def.yaml" t block "㉑ notify_leo 旁邊夾一個部署端點" "curl -X POST $L/webhooks/named/leo/notify_leo/trigger $D '{}' && curl -X POST $L/webhooks/named $D @x" t block "㉒ 寫 + tr -d(剪掉唯讀 -d 之後仍該擋)" "cat f | tr $D '\\r' | curl -X POST $L/kbdb/entries $D @-" t block "㉓ 用 leo21c 的 CF 帳號部署" "CLOUDFLARE_ACCOUNT_ID=51a01bfa2665bd7bc3fd080dc40cf3e1 npx wrangler deploy" echo "── C. 擋下時印的改法要指到活著的 youlin ──" mk "curl -X POST $L/kbdb/entries $D '{}'" | bash "$HOOK" 2>"$HERE/.leo21c-msg.$$" >/dev/null MSG=$(cat "$HERE/.leo21c-msg.$$"); rm -f "$HERE/.leo21c-msg.$$" if printf '%s' "$MSG" | grep -q 'arcrun-cypher-executor.arcrun-yuga3bse.workers.dev'; then echo " ✅ ㉔ 改法段印的是現役子網域 arcrun-yuga3bse"; PASS=$((PASS+1)) else echo " ❌ ㉔ 改法段沒有現役子網域 arcrun-yuga3bse"; FAIL=$((FAIL+1)); fi if printf '%s' "$MSG" | grep -q 'cypher : https://arcrun-cypher-executor.youlin-hsieh-dev'; then echo " ❌ ㉕ 改法段還教人打 09-02 已死的 youlin-hsieh-dev"; FAIL=$((FAIL+1)) else echo " ✅ ㉕ 改法段不再把死的舊名當網址教人"; PASS=$((PASS+1)); fi if printf '%s' "$MSG" | grep -q '讀可以,寫不行'; then echo " ✅ ㉖ 訊息講得出判準(讀可以,寫不行)"; PASS=$((PASS+1)) else echo " ❌ ㉖ 訊息沒講判準"; FAIL=$((FAIL+1)); fi echo echo "通過 $PASS 條,失敗 $FAIL 條" [ "$FAIL" -eq 0 ]