# -*- coding: utf-8 -*- r'''端到端验证「监测 + 预案 + 报告分区」。 验这些: 1. /rescue/ 不带登录 -> 401(不能匿名下诊断报告) 2. /rescue/ 带登录 -> 200 且内容正确 3. 报告文件名的目录穿越被挡住 4. monitor.sh 能跑通并写状态 5. rescue.sh 在网站正常时**什么都不做**就退出(不能瞎折腾) 6. 后台页里有「抢救报告」分区 7. 监测定时器在跑 ''' from __future__ import annotations import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) from devssh import run # noqa: E402 REMOTE = r''' RELAY=/root/lanremote-relay PASS=$(cat $RELAY/data/admin_password.txt 2>/dev/null) B=http://127.0.0.1:8080 echo "════ 准备:造一份演练报告 ════" DEMO=$RELAY/rescue_reports/19700101-000000-demo.txt printf '这是一份演练报告。\n\n 判断:**本机是好的,问题在隧道或 Cloudflare 那一侧**。\n' > $DEMO echo " $(ls $RELAY/rescue_reports | wc -l) 份" echo echo "════ 1. 不带登录下载(应该 401)════" printf ' HTTP %s\n' "$(curl -s -o /dev/null -w '%{http_code}' --max-time 8 $B/rescue/19700101-000000-demo.txt)" echo echo "════ 2. 带登录下载(应该 200 且有内容)════" # 先登录拿 cookie curl -s -c /tmp/ck.txt -o /dev/null --max-time 8 \ -d "password=$PASS" $B/login 2>/dev/null CODE=$(curl -s -b /tmp/ck.txt -o /tmp/rep.txt -w '%{http_code}' --max-time 8 \ $B/rescue/19700101-000000-demo.txt) printf ' HTTP %s\n' "$CODE" echo " 内容:$(head -2 /tmp/rep.txt | tail -1)" printf ' 缓存头: %s\n' "$(curl -s -b /tmp/ck.txt -D- -o /dev/null --max-time 8 $B/rescue/19700101-000000-demo.txt | grep -i cache-control | tr -d '\r')" echo echo "════ 3. 目录穿越(应该 400/404,绝不能读到别的文件)════" for bad in "../relay.py" "..%2Frelay.py" "x/../../etc/passwd"; do printf ' %-24s -> HTTP %s\n' "$bad" "$(curl -s -b /tmp/ck.txt -o /dev/null -w '%{http_code}' --max-time 8 "$B/rescue/$bad")" done echo echo "════ 4. monitor.sh 跑一次 ════" rm -f $RELAY/monitor_state.txt bash $RELAY/monitor.sh echo " 状态文件:" cat $RELAY/monitor_state.txt 2>/dev/null | sed 's/^/ /' echo " 日志尾部:" tail -3 $RELAY/monitor.log 2>/dev/null | sed 's/^/ /' echo echo "════ 5. rescue.sh 在网站正常时应该**什么都不做** ════" BEFORE=$(md5sum $RELAY/rescue_knowledge.md 2>/dev/null | cut -d' ' -f1) timeout 120 bash $RELAY/rescue.sh "端到端验证(网站正常)" 2>&1 | tail -8 | sed 's/^/ /' AFTER=$(md5sum $RELAY/rescue_knowledge.md 2>/dev/null | cut -d' ' -f1) if [ "$BEFORE" = "$AFTER" ]; then echo " ✅ 网站正常时没有误触发抢救(知识库没变)" else echo " ❌ 网站正常却动了抢救" fi echo " 报告份数:$(ls $RELAY/rescue_reports | wc -l)(正常时不该新增)" echo echo "════ 6. 后台页里的「抢救报告」分区 ════" N=$(curl -s -b /tmp/ck.txt --max-time 8 $B/zhongzhuanzhan | grep -c '抢救报告') printf ' 匹配 %s 次\n' "$N" curl -s -b /tmp/ck.txt --max-time 8 $B/zhongzhuanzhan | grep -o '19700101-000000-demo.txt' | head -1 | sed 's/^/ 列表里有: /' echo echo "════ 7. 定时器 ════" printf ' monitor.timer: %s\n' "$(systemctl is-active lanremote-monitor.timer)" systemctl list-timers lanremote-monitor.timer --no-pager 2>/dev/null | sed -n '1,2p' | sed 's/^/ /' echo echo "════ 收尾:删掉演练报告 ════" rm -f $DEMO /tmp/ck.txt /tmp/rep.txt echo " 剩 $(ls $RELAY/rescue_reports | wc -l) 份" ''' def main() -> int: out = run(REMOTE, timeout=400) text = out[1] if isinstance(out, tuple) else str(out) print(text) return 0 if __name__ == "__main__": sys.exit(main())