games-development-ai/deploy/tests/test-collect-dogfood-account-report.sh

170 lines
7.4 KiB
Bash
Executable File
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
# 账号报告采集器回归:使用假 SSH/MySQL 输出,不连接真实内网主机。
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SCRIPT="$ROOT_DIR/deploy/collect-dogfood-account-report.sh"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
fail() {
printf 'TEST_FAIL %s\n' "$*" >&2
exit 1
}
openssl genpkey -algorithm ED25519 -out "$TMP_DIR/private.pem" >/dev/null 2>&1
openssl pkey -in "$TMP_DIR/private.pem" -pubout -out "$TMP_DIR/public.pem" >/dev/null 2>&1
{
for index in $(seq 1 10); do
printf 'ACCOUNT\t%d\tdogfoodc%02d\tcreator\tACTIVE\t%d\tCLAIMED\t6849315\t%d\t%d\n' \
"$((1000 + index))" "$index" "$((2000 + index))" "$((4000 + index))" "$((5000 + index))"
done
for index in $(seq 1 30); do
printf 'ACCOUNT\t%d\tdogfoodp%02d\tplayer\tACTIVE\t%d\tCLAIMED\t6849315\t%d\t%d\n' \
"$((1100 + index))" "$index" "$((2100 + index))" "$((4100 + index))" "$((5100 + index))"
done
for index in $(seq 1 12); do
printf 'RESERVE\t%d\t%d\t%d\tFREE\t6849315\t\t\t\t\n' \
"$((3000 + index))" "$((4200 + index))" "$((5200 + index))"
done
} >"$TMP_DIR/mysql.tsv"
{
for index in $(seq 1 10); do
printf 'TOKEN|%d|neice_%03d|%d|1|0|-1|6849315\n' \
"$((4000 + index))" "$index" "$((5000 + index))"
done
for index in $(seq 1 30); do
printf 'TOKEN|%d|neice_%03d|%d|1|0|-1|6849315\n' \
"$((4100 + index))" "$((10 + index))" "$((5100 + index))"
done
for index in $(seq 1 12); do
printf 'TOKEN|%d|neice_%03d|%d|1|0|-1|6849315\n' \
"$((4200 + index))" "$((40 + index))" "$((5200 + index))"
done
} >"$TMP_DIR/newapi.tsv"
cat >"$TMP_DIR/fake-ssh" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >"$DOGFOOD_TEST_SSH_ARGS"
cat >"$DOGFOOD_TEST_SQL_CAPTURE"
cat "$DOGFOOD_TEST_MYSQL_ROWS"
SH
chmod +x "$TMP_DIR/fake-ssh"
cat >"$TMP_DIR/fake-docker" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >"$DOGFOOD_TEST_DOCKER_ARGS"
cat >"$DOGFOOD_TEST_PG_SQL_CAPTURE"
cat "$DOGFOOD_TEST_NEWAPI_ROWS"
SH
chmod +x "$TMP_DIR/fake-docker"
export DOGFOOD_COLLECTOR_TEST_MODE=1
export DOGFOOD_COLLECTOR_TEST_SSH_BIN="$TMP_DIR/fake-ssh"
export DOGFOOD_COLLECTOR_TEST_SIGNER_KEY="$TMP_DIR/private.pem"
export DOGFOOD_COLLECTOR_TEST_OPENSSL_BIN="$(command -v openssl)"
export DOGFOOD_COLLECTOR_TEST_DOCKER_BIN="$TMP_DIR/fake-docker"
export DOGFOOD_TEST_SSH_ARGS="$TMP_DIR/ssh-args"
export DOGFOOD_TEST_SQL_CAPTURE="$TMP_DIR/mysql.sql"
export DOGFOOD_TEST_MYSQL_ROWS="$TMP_DIR/mysql.tsv"
export DOGFOOD_TEST_DOCKER_ARGS="$TMP_DIR/docker-args"
export DOGFOOD_TEST_PG_SQL_CAPTURE="$TMP_DIR/newapi.sql"
export DOGFOOD_TEST_NEWAPI_ROWS="$TMP_DIR/newapi.tsv"
report="$TMP_DIR/account-report.json"
"$SCRIPT" \
--activation-run-id activation-20260723T010203Z \
--rc-commit 1111111111111111111111111111111111111111 \
--output "$report"
[ -f "$report" ] && [ -f "$report.sig" ] || fail '没有生成报告及 detached signature'
[ "$(stat -f '%Lp' "$report" 2>/dev/null || stat -c '%a' "$report")" = 600 ] || fail '报告权限不是 0600'
[ "$(stat -f '%Lp' "$report.sig" 2>/dev/null || stat -c '%a' "$report.sig")" = 600 ] || fail '签名权限不是 0600'
openssl pkeyutl -verify -pubin -inkey "$TMP_DIR/public.pem" -rawin \
-in "$report" -sigfile "$report.sig" >/dev/null 2>&1 || fail 'detached signature 无法验证'
grep -q 'root@100.64.0.7' "$TMP_DIR/ssh-args" || fail 'SSH 目标不是固定 mini-desktop'
grep -q '^START TRANSACTION READ ONLY;' "$TMP_DIR/mysql.sql" || fail 'MySQL 查询未进入服务端只读事务'
grep -q 'FROM game_player p' "$TMP_DIR/mysql.sql" || fail '固定账号查询缺失'
grep -q 'FROM newapi_quota_pool q' "$TMP_DIR/mysql.sql" || fail '固定额度池查询缺失'
if grep -Eqi 'newapi_token_key|password|access_token|refresh_token' "$TMP_DIR/mysql.sql"; then
fail '固定查询选择了敏感列'
fi
grep -q 'infra-postgres' "$TMP_DIR/docker-args" || fail 'new-api PostgreSQL 容器不是固定值'
grep -q 'new-api' "$TMP_DIR/docker-args" || fail 'new-api PostgreSQL 数据库不是固定值'
grep -q '^BEGIN TRANSACTION READ ONLY;' "$TMP_DIR/newapi.sql" || fail 'new-api 查询未进入只读事务'
grep -q 'FROM users u' "$TMP_DIR/newapi.sql" || fail 'new-api users 固定查询缺失'
grep -q 'JOIN tokens t' "$TMP_DIR/newapi.sql" || fail 'new-api tokens 固定查询缺失'
if grep -Eqi 'SELECT[^;]*(key|access_token|password)' "$TMP_DIR/newapi.sql"; then
fail 'new-api 固定查询选择了敏感凭据'
fi
grep -q "SIGNER_PRIVATE_KEY='/root/dogfood-r1-signer/r1-ed25519-private.pem'" "$SCRIPT" || \
fail '生产 signer 私钥路径不是固定值'
grep -q 'realpath.*signer_key' "$SCRIPT" || fail '生产 signer 私钥未校验 canonical 路径'
grep -q "stat -c '%u'.*signer_key" "$SCRIPT" || fail '生产 signer 私钥未校验 root 所有权'
python3 - "$report" <<'PY'
import json
import sys
report = json.load(open(sys.argv[1], encoding="utf-8"))
assert report["schema"] == "dogfood-account-database-report/2"
assert report["issuer"] == "r1-mini-infra"
assert report["queryId"] == "dogfood-account-readiness-v2"
assert report["querySchema"] == "dogfood-account-readiness-row/2"
assert report["rcCommit"] == "1" * 40
assert len(report["accounts"]) == 40
assert len(report["reserves"]) == 12
for item in report["accounts"] + report["reserves"]:
assert item["newapiUsername"].startswith("neice_")
assert item["tokenStatus"] == "ENABLED"
assert item["tokenRemainQuota"] > 0
assert item["tokenUnlimitedQuota"] is False
assert item["tokenExpiredTime"] == -1
serialized = json.dumps(report)
for secret_name in ("tokenKey", "password", "accessToken", "refreshToken"):
assert secret_name not in serialized
PY
# 精确规模是签发前置条件39 个 CLAIMED 账号必须失败且不得留下半成品。
head -n 51 "$TMP_DIR/mysql.tsv" >"$TMP_DIR/incomplete.tsv"
export DOGFOOD_TEST_MYSQL_ROWS="$TMP_DIR/incomplete.tsv"
if "$SCRIPT" --activation-run-id activation-20260723T010203Z \
--rc-commit 1111111111111111111111111111111111111111 \
--output "$TMP_DIR/incomplete.json" >/dev/null 2>&1; then
fail '不完整 40+12 数据仍被签发'
fi
[ ! -e "$TMP_DIR/incomplete.json" ] && [ ! -e "$TMP_DIR/incomplete.json.sig" ] || fail '失败后遗留半成品'
# new-api 权威状态异常、ID 关联漂移或一名用户匹配多行时都不得签发。
for mutation in disabled zero id-drift multi-row; do
case "$mutation" in
disabled)
awk -F'|' 'BEGIN{OFS="|"} NR==1{$5=0} {print}' "$TMP_DIR/newapi.tsv" >"$TMP_DIR/newapi-$mutation.tsv"
;;
zero)
awk -F'|' 'BEGIN{OFS="|"} NR==1{$8=0} {print}' "$TMP_DIR/newapi.tsv" >"$TMP_DIR/newapi-$mutation.tsv"
;;
id-drift)
awk -F'|' 'BEGIN{OFS="|"} NR==1{$4=999999} {print}' "$TMP_DIR/newapi.tsv" >"$TMP_DIR/newapi-$mutation.tsv"
;;
multi-row)
cp "$TMP_DIR/newapi.tsv" "$TMP_DIR/newapi-$mutation.tsv"
head -n 1 "$TMP_DIR/newapi.tsv" >>"$TMP_DIR/newapi-$mutation.tsv"
;;
esac
export DOGFOOD_TEST_NEWAPI_ROWS="$TMP_DIR/newapi-$mutation.tsv"
if "$SCRIPT" --activation-run-id activation-20260723T010203Z \
--rc-commit 1111111111111111111111111111111111111111 \
--output "$TMP_DIR/$mutation.json" >/dev/null 2>&1; then
fail "new-api 异常仍被签发 mutation=$mutation"
fi
[ ! -e "$TMP_DIR/$mutation.json" ] && [ ! -e "$TMP_DIR/$mutation.json.sig" ] || \
fail "new-api 异常后遗留半成品 mutation=$mutation"
done
printf 'TEST_PASS 账号报告固定 SSH/MySQL、40+12、签名、权限与脱敏校验通过\n'