ef75ac8034
⑪「合規內文通過身份閘」之後 scripts/ticket 會真的往下打 API;舊版假設離線, 但在有 token 的機器上它打得出去:08-27~09-19 在 #30 留下 69 則 「【身份】subagent/inkstone/ISEP/feat/x 做完了」(最近一則 c9156 是 09-19 本機跑全套測試留下的)。 改法照 test-baton-handback-guard 等既有寫法:TICKET_HOST=http://127.0.0.1:9、假 token、不重試。 驗:真 token 在環境裡時跑一次,#30 留言數前後都是 116;11/11 通過。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
106 lines
5.1 KiB
Bash
Executable File
106 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 身份欄的兩道閘(inkstone/ISEP#30 comment 4325:「subagent 回覆時要表明身份」)。
|
||
#
|
||
# 貼留言到票上有**兩條路**,所以測兩道閘:
|
||
# 正門 scripts/ticket say / decide —— 檢查在打任何 API 之前,所以本測試離線跑得動
|
||
# 側門 直接打 Gitea API —— hooks/reply-identity-guard.sh
|
||
#
|
||
# **離線、不打網路。** 正門的案例全部在 `die()` 之前就結束,不會真的送出留言。
|
||
#
|
||
# 用法:hooks/tests/reply-identity.test.sh
|
||
|
||
set -u
|
||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
ROOT="$(cd "$HERE/../.." && pwd)"
|
||
HOOK="$ROOT/hooks/reply-identity-guard.sh"
|
||
TICKET="$ROOT/scripts/ticket"
|
||
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
|
||
|
||
PASS=0; FAIL=0; N=0
|
||
|
||
ok() { printf ' ✅ %s\n' "$1"; PASS=$((PASS+1)); N=$((N+1)); }
|
||
bad() { printf ' ❌ %s\n' "$1"; shift; printf '%s\n' "$*" | sed -n '1,6p' | sed 's/^/ /'
|
||
FAIL=$((FAIL+1)); N=$((N+1)); }
|
||
|
||
# ── 側門:hooks/reply-identity-guard.sh ─────────────────────────────────
|
||
h() { # h <期望 exit> <說明> <command 字串>
|
||
want="$1"; desc="$2"; cmd="$3"
|
||
body=$(python3 - "$cmd" <<'PY'
|
||
import json, sys
|
||
print(json.dumps({"tool_name": "Bash", "tool_input": {"command": sys.argv[1]}},
|
||
ensure_ascii=False))
|
||
PY
|
||
)
|
||
err=$(printf '%s' "$body" | bash "$HOOK" 2>&1 >/dev/null); rc=$?
|
||
if [ "$rc" -eq "$want" ]; then ok "$desc"; else
|
||
bad "$desc —— 期望 exit=$want,實得 exit=$rc" "$err"; fi
|
||
}
|
||
|
||
echo "── 側門(直接打 Gitea API)─────────────────────────────────────"
|
||
|
||
h 2 "① POST 留言但沒有【身份】→ 擋" \
|
||
'curl -X POST -H "Authorization: token $T" -d @body.json https://git.uncle6.me/api/v1/repos/inkstone/ISEP/issues/30/comments'
|
||
|
||
h 0 "② POST 留言且內文帶【身份】→ 放行" \
|
||
'curl -X POST -d "{\"body\":\"【身份】subagent/inkstone/ISEP/feat/x\n做完了\"}" https://git.uncle6.me/api/v1/repos/inkstone/ISEP/issues/30/comments'
|
||
|
||
h 0 "③ 純讀取(GET 撈留言)→ 放行,這是最常做的動作,誤攔它比漏擋更糟" \
|
||
'curl -s -H "Authorization: token $T" https://git.uncle6.me/api/v1/repos/inkstone/ISEP/issues/30/comments?limit=60'
|
||
|
||
h 0 "④ 走正門 scripts/ticket → 放行(正門有自己的閘,兩支同時擋會互相打架)" \
|
||
'scripts/ticket say inkstone/ISEP#30 -F /tmp/body.md'
|
||
|
||
h 0 "⑤ 開新票的端點(不帶票號)→ 不是本閘的地盤" \
|
||
'curl -X POST -d @t.json https://git.uncle6.me/api/v1/repos/inkstone/ISEP/issues'
|
||
|
||
h 0 "⑥ 逃生口 reply-identity-ok → 放行(留在指令歷史上)" \
|
||
'curl -X POST -d @body.json https://git.uncle6.me/api/v1/repos/inkstone/ISEP/issues/30/comments # reply-identity-ok'
|
||
|
||
h 0 "⑦ 只是在講這件事(把端點寫進文件)而沒有 POST → 不擋" \
|
||
'echo "留言端點是 issues/30/comments" >> docs/notes.md'
|
||
|
||
echo
|
||
echo "── 正門(scripts/ticket)───────────────────────────────────────"
|
||
|
||
# 🔴 正門的案例一律指到連不上的主機(跟 test-baton-handback-guard 等同一個寫法)。
|
||
# ⑪ 是「合規內文通過身份閘」——通過之後 scripts/ticket 會真的往下打 API。
|
||
# 舊版假設「離線環境打不出去」,但在有 token 的機器上(本機 .env、雲端 env)它真的打得出去:
|
||
# 2026-08-27 到 09-19 在 inkstone/ISEP#30 留下 69 則「【身份】subagent/…/feat/x 做完了」。
|
||
OFF_ENV=(env TICKET_HOST=http://127.0.0.1:9 GITEA_TOKEN_CLAUDE_CODE=fake ISEP_API_RETRIES=0)
|
||
|
||
g() { # g <期望 exit> <說明> <內文>
|
||
want="$1"; desc="$2"; content="$3"
|
||
printf '%s' "$content" > "$TMP/body.md"
|
||
err=$("${OFF_ENV[@]}" python3 "$TICKET" say inkstone/ISEP#30 -F "$TMP/body.md" 2>&1 >/dev/null); rc=$?
|
||
if [ "$rc" -eq "$want" ]; then ok "$desc"; else
|
||
bad "$desc —— 期望 exit=$want,實得 exit=$rc" "$err"; fi
|
||
}
|
||
|
||
g 2 "⑧ 內文沒有身份欄 → 在打 API 之前就擋(所以這一格離線也測得動)" \
|
||
'做完了,分支是 feat/x'
|
||
|
||
g 2 "⑨ 有【身份】但角色不在三選一之內 → 擋" \
|
||
'【身份】機器人/inkstone/ISEP/feat/x
|
||
|
||
做完了'
|
||
|
||
g 2 "⑩ 身份欄不在第一行 → 擋(要一眼看得到,不是藏在中間)" \
|
||
'做完了
|
||
【身份】subagent/inkstone/ISEP/feat/x'
|
||
|
||
# ⑪ 合規的內文要能通過身份檢查——它會往下走到打 API,
|
||
# 離線環境打不出去所以 exit 非 0;判準改成「錯誤訊息不是身份欄那一段」。
|
||
printf '%s' '【身份】subagent/inkstone/ISEP/feat/x
|
||
|
||
做完了' > "$TMP/ok.md"
|
||
err=$("${OFF_ENV[@]}" python3 "$TICKET" say inkstone/ISEP#30 -F "$TMP/ok.md" 2>&1 >/dev/null || true)
|
||
if printf '%s' "$err" | grep -q '第一行要表明身份'; then
|
||
bad "⑪ 合規的內文被身份閘擋掉了(誤攔)" "$err"
|
||
else
|
||
ok "⑪ 合規的內文通過身份閘(之後成不成功是網路的事,不是本閘的事)"
|
||
fi
|
||
|
||
echo
|
||
echo "══ $PASS/$N 通過${FAIL:+,$FAIL 個失敗} ══"
|
||
[ "$FAIL" -eq 0 ]
|