Files
tamabox/dev/devcheck-restrict.sh
T
2026-10-18 21:27:02 +08:00

150 lines
5.2 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 处置链路部署后自检(L1 停止分发 / L4 整页停用 / CLI 可用性)
#
# 为什么需要它:本机沙箱起不了 web(无 redis),L1/L4 的 HTTP 行为只能在服务器上验证。
# 这个脚本把「施加处置 → 观察 HTTP → 自动撤销」串起来,避免手工操作忘了解除。
#
# 用法:
# BASE_URL=https://box-dev.example.com DOMAIN=<测试箱主域名> TAMABOX=/path/to/NekoBox \
# bash dev/devcheck-restrict.sh # 只打印将要执行的命令(dry-run)
#
# BASE_URL=... DOMAIN=... TAMABOX=... RUN=1 \
# bash dev/devcheck-restrict.sh # 真正执行,结束时自动撤销
#
# 注意:
# - DOMAIN 必须是**测试箱主**,不要用真实用户;脚本会临时施加 L4/L1 再撤销。
# - 站点默认语言可能是 ja,页面文案断言按日文/英文各查一次,避免误判「没生效」。
# - 只依赖 CLI 与 curl,不需要 psql 凭据。
set -uo pipefail
BASE_URL=${BASE_URL:?need BASE_URL, e.g. https://box-dev.example.com}
DOMAIN=${DOMAIN:?need DOMAIN, a TEST box domain only}
TAMABOX=${TAMABOX:-./NekoBox}
RUN=${RUN:-0}
DAYS=${DAYS:-1}
pass=0
fail=0
restricted=0
say() { printf '%s\n' "$*"; }
check() {
local name=$1 want=$2 got=$3
if [ "$want" = "$got" ]; then
say " PASS $name (=$got)"
pass=$((pass + 1))
else
say " FAIL $name (want $want, got $got)"
fail=$((fail + 1))
fi
}
code() { curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$1"; }
do_restrict() {
restricted=1
if [ "$RUN" = 1 ]; then
"$TAMABOX" restrict --domain "$DOMAIN" --level "$1" --days "$DAYS" --reason "deploy self-check" --yes
else
say " [dry-run] $TAMABOX restrict --domain $DOMAIN --level $1 --days $DAYS --reason 'deploy self-check' --yes"
fi
}
cleanup() {
if [ "$RUN" = 1 ] && [ "$restricted" = 1 ]; then
say ""
say "== 兜底撤销(无论中途是否失败)=="
"$TAMABOX" unrestrict --domain "$DOMAIN" || true
fi
}
trap cleanup EXIT
say "== 0. 二进制是否包含新命令 =="
if "$TAMABOX" --help 2>&1 | grep -q 'restrict'; then
say " PASS restrict 命令存在"
pass=$((pass + 1))
else
say " FAIL 二进制里没有 restrict —— 构建的是旧代码(注意入口是根目录 tamabox.go,或用 ./cmd/)"
fail=$((fail + 1))
say ""
say "结果: 无法继续,先修构建入口。"
exit 1
fi
say ""
say "== 1. 基线:处置前箱主页必须可访问 =="
base=$(code "$BASE_URL/_/$DOMAIN")
if [ "$base" != 200 ]; then
say " FAIL 基线不是 200(got $base),后续断言全部无意义,已中止。"
say ""
say " 302 的常见原因(按概率排序):"
say " 1) 域名不存在或账号已停用 —— 先确认 DOMAIN 拼写。查一个真实域名:"
say " curl -s $BASE_URL/explore | grep -o 'href=\"/_/[^\"]*\"' | head -5"
say " 或在库上执行:select domain from users where deleted_at is null order by id desc limit 5;"
say " 2) 该箱主设置了页面密码 —— 此时首页是 200(渲染密码页),不是 302。"
say ""
say " 注意:302 不能证明任何处置生效。上次自检就出现过「箱主不存在 → 302」被误判成 L4 生效。"
exit 1
fi
say " PASS box page = 200"
say ""
say "== 1b. 停用页是否部署(与处置无关,dry-run 也验)=="
check "restricted page reachable" 200 "$(code "$BASE_URL/restricted")"
body=$(curl -sL --max-time 10 "$BASE_URL/restricted")
if printf '%s' "$body" | grep -qE '一時的に利用できません|temporarily unavailable|暫時無法存取|暂时不可访问'; then
say " PASS restricted page copy rendered"
pass=$((pass + 1))
else
say " FAIL restricted page copy not found(i18n 或模板没部署上)"
fail=$((fail + 1))
fi
if [ "$RUN" != 1 ]; then
say ""
say "== dry-run:不做状态断言 =="
say " 状态没有被改动,断言 L4/L1 只会得到误导性结果。"
say " 基线已确认可访问,用 RUN=1 重跑以执行真实验证:"
say " RUN=1 BASE_URL=$BASE_URL DOMAIN=$DOMAIN TAMABOX=$TAMABOX bash $0"
exit 0
fi
say ""
say "== 2. L4 整页停用 =="
do_restrict L4
sleep 1
check "box page under L4" 302 "$(code "$BASE_URL/_/$DOMAIN")"
say ""
say "== 3. L1 停止分发:页面恢复、分享卡被拦 =="
do_restrict L1
sleep 1
check "box page under L1" 200 "$(code "$BASE_URL/_/$DOMAIN")"
qid=$(curl -s --max-time 10 "$BASE_URL/_/$DOMAIN" | grep -o "/_/$DOMAIN/[0-9]\+" | head -1 | grep -o '[0-9]\+$')
if [ -n "${qid:-}" ]; then
check "share card under L1 (qid=$qid)" 302 "$(code "$BASE_URL/_/$DOMAIN/$qid/share-card")"
else
say " SKIP 该箱主没有已公开回答,无法验证分享卡(换一个有已答问题的测试箱主)"
fi
say ""
say "== 4. 撤销 =="
if [ "$RUN" = 1 ]; then
"$TAMABOX" unrestrict --domain "$DOMAIN"
restricted=0
check "box page after unrestrict" 200 "$(code "$BASE_URL/_/$DOMAIN")"
else
say " [dry-run] $TAMABOX unrestrict --domain $DOMAIN"
fi
say ""
say "== 结果: PASS=$pass FAIL=$fail =="
if [ "$fail" -gt 0 ]; then
say "有失败项,把上面输出 + 服务日志(journalctl / docker logs 里搜 'Failed to query user restriction')一起发我。"
exit 1
fi
say "全部通过。仍需人工手测两项:L2(回答应保存为私密)、L3(回答应被拒绝)。"