Files
admin 452924d89c feat(config): 涉密内容外置到配置目录(档案 140)
把散落在代码里的真实部署值统一收进 config/,代码改为引用配置,
使仓库副本/开源导出不再带出生产域名、IP、内网路径与凭据。

新增 config/:platform.env.example(模板)· load.sh(shell 加载器)·
index.cjs(node 加载器)· README.md(键一览与优先级)。
真实值放 config/platform.env —— 已 .gitignore 排除,不入库、不进导出。

TS 侧新增 src/platform-paths.ts 作部署路径的唯一解析处(零副作用):
platformDir/stateDir/backupDir/artifactDir/installDir/scriptPath。
config.ts 接入这些字段;内置中继种子由生产 URL 改为空(改由
DSHS_OVERLAY_BOOTSTRAP_SEEDS 提供)。修掉 5 处硬编码绝对路径,
src/** 注释中性化 116 行/53 文件。

scripts/** 36 个内部运维脚本:真令牌/PG 口令/隧道目标/主机号/路径
一律改从配置取;web/wake.html 的注册域白名单改为运行时从
location.hostname 推导;test/** 夹具 119 行/13 文件改 RFC 2606/5737
保留值,并把「内置种子必须为空」固化为回归断言。

取证:tsc 0 错;npm test 373/375(唯一失败 lease 属既有);
全仓扫描(大小写不敏感)代码面涉密标识 = 0;已部署 47 并零回归
(/opt/dsh/* 未搬家,/var/lib/dshs/platform 未被误建)。
2026-09-19 15:12:19 +08:00

81 lines
5.4 KiB
Bash
Raw Permalink 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
# 最终验证(在 47 上跑):清污染 → 重置锚点 → 重验两条路径
# ① 既有用户 guest:留 <host-a> + 工作区有历史数据 + 实例页正常
# ② 新用户:落 <host-b> + **文件真的写到 106 的盘** + 实例页正常
set -uo pipefail
. "$(cd "$(dirname "$0")/.." && pwd)/config/load.sh"
export PGPASSWORD=dshs_cluster_2026
Q() { /usr/bin/psql -h 127.0.0.1 -p 15432 -U dshs -d dshs -tAc "$1"; }
M=http://127.0.0.1:3080
DOMAIN="${DSHS_BASE_DOMAIN:?config/platform.env 缺 DSHS_BASE_DOMAIN}"
T47="$DSHS_CLUSTER_AGENT_TOKEN"
T106="$DSH_PEER_AGENT_TOKEN"
SSH106="ssh -n -i /root/.ssh/dshworker_ed25519 -o BatchMode=yes -o StrictHostKeyChecking=accept-new root@"$DSH_PEER_PUBLIC_IP""
mksess() {
local u="$1" T H
T=$(openssl rand -hex 32); H=$(printf '%s' "$T" | sha256sum | cut -d' ' -f1)
Q "insert into sessions (token_hash,user_id,created_at,expires_at,ip,user_agent)
select '$H', id, (extract(epoch from now())*1000)::bigint, (extract(epoch from now())*1000)::bigint+1800000, '127.0.0.1','switch-verify' from users where username='$u'" >/dev/null
printf '%s' "$T"
}
owner() { Q "select coalesce(i.host_id,'NULL')||' epoch='||coalesce(i.epoch,0) from users u left join dsh_instances i on i.user_id=u.id where u.username='$1'"; }
agent() { curl -s -m 6 -H "x-dsh-agent-token: $2" "http://127.0.0.1:$1/healthz" | grep -o '"instances":[0-9]*'; }
isapp() { grep -q '<base href=' <<<"$1" && echo "✓实例页" || echo "✗非实例页"; }
echo "########## 0) 清污染:停所有实例 + 删测试用户 ##########"
systemctl restart dshs-worker; sleep 4
$SSH106 'systemctl restart dshs-worker' >/dev/null 2>&1; sleep 4
echo " 重启后 "$DSHS_CLUSTER_HOST_ID"=$(agent 19100 $T47) "$DSH_PEER_HOST_ID"=$(agent 19000 $T106)"
AT=$(mksess admin); AC="sid=$AT"
for u in $(Q "select id from users where username like 'switchtest%' or username like 'swtest%'"); do
echo " 删测试用户 $u → $(curl -s -m 20 -X DELETE -b "$AC" "$M/api/admin/users/$u" -o /dev/null -w '%{http_code}')"
done
echo " 剩余用户: $(Q "select string_agg(username,', ') from users")"
echo "########## 1) 重置 guest 锚点(host_id="$DSHS_CLUSTER_HOST_ID") ##########"
Q "update dsh_instances set host_id='w-1', epoch=0, lease_until=0, status='stopped'
where user_id=(select id from users where username='guest')" >/dev/null
echo " $(owner guest)"
echo
echo "########## 2) 路径①:既有用户 guest ##########"
GT=$(mksess guest); GC="sid=$GT"
E=$(curl -s -m 60 -X POST -b "$GC" -H 'content-type: application/json' -d '{}' "$M/api/dsh/enter")
sleep 3
echo " 归属: $(owner guest) ← 期望 "$DSHS_CLUSTER_HOST_ID""
echo " "$DSHS_CLUSTER_HOST_ID"=$(agent 19100 $T47) "$DSH_PEER_HOST_ID"=$(agent 19000 $T106)"
echo " 工作区条目: $(curl -s -m 10 -b "$GC" "$M/api/desktop/tree" | grep -o '"name":"[^"]*"' | head -4 | tr '\n' ' ')"
PAGE=$(curl -s -m 25 -L -b "$GC" -H "Host: guest.$DOMAIN" "$M/" | head -c 300)
echo " 实例页: $(isapp "$PAGE")"
echo
echo "########## 3) 路径②:新用户 ##########"
NU="swtest2$(date +%H%M%S)"
echo " register=$(curl -s -m 15 -X POST -H 'content-type: application/json' -d "{\"username\":\"$NU\",\"password\":\"SwitchTest123\"}" "$M/api/auth/register" -o /dev/null -w '%{http_code}')"
NID=$(Q "select id from users where username='$NU'")
echo " approve=$(curl -s -m 15 -X POST -b "$AC" "$M/api/admin/users/$NID/approve" -o /dev/null -w '%{http_code}')"
NC=$(curl -s -m 15 -X POST -H 'content-type: application/json' -d "{\"username\":\"$NU\",\"password\":\"SwitchTest123\"}" -D - "$M/api/auth/login" -o /dev/null | grep -i '^set-cookie' | head -1 | grep -oP 'sid=[^;]+')
echo " mkdir=$(curl -s -m 15 -X POST -b "$NC" -H 'content-type: application/json' -d '{"path":"proj"}' "$M/api/fs/mkdir" -o /dev/null -w '%{http_code}') ← 首次触达应把归属钉住"
echo " 钉住后归属: $(owner "$NU") ← 期望 "$DSH_PEER_HOST_ID"(与下面的 launch 必须同台)"
echo " upload=$(curl -s -m 20 -X POST -b "$NC" -H 'content-type: application/json' -d "{\"path\":\"proj\",\"name\":\"hello.txt\",\"data\":\"$(printf 'hi-from-switch' | base64 -w0)\"}" "$M/api/fs/upload" -o /dev/null -w '%{http_code}')"
echo " launch=$(curl -s -m 60 -X POST -b "$NC" -H 'content-type: application/json' -d '{"folder":"proj"}' "$M/api/dsh/launch" -o /dev/null -w '%{http_code}')"
sleep 4
echo " 归属: $(owner "$NU") ← 期望 "$DSH_PEER_HOST_ID"(粘性保持)"
echo " "$DSH_PEER_HOST_ID"=$(agent 19000 $T106) "$DSHS_CLUSTER_HOST_ID"=$(agent 19100 $T47)"
echo " --- 落盘取证 ---"
L47=$($SSH106 "ls "$DSHS_DATA_ROOT"/users/$NID/ws/proj/hello.txt 2>/dev/null" 2>/dev/null || true)
echo " 106 盘: ${L47:-不存在}"
echo " 47 盘: $(ls "$DSHS_DATA_ROOT"/users/$NID/ws/proj/hello.txt 2>/dev/null || echo 不存在(应不存在 ✓))"
NP=$(curl -s -m 25 -L -b "$NC" -H "Host: $NU.$DOMAIN" "$M/" | head -c 300)
echo " 实例页(Host: $NU.$DOMAIN): $(isapp "$NP")"
echo
echo "########## 收尾 ##########"
curl -s -m 40 -X POST -b "$GC" "$M/api/dsh/stop" -o /dev/null -w " guest stop=%{http_code}\n"
curl -s -m 40 -X POST -b "$NC" "$M/api/dsh/stop" -o /dev/null -w " newuser stop=%{http_code}\n"
echo " stop 后 guest 归属(**不应再被清空**): $(owner guest)"
Q "delete from sessions where user_agent='switch-verify'" >/dev/null
echo " 残留临时 session: $(Q "select count(*) from sessions where user_agent='switch-verify'")(应 0)"
echo " 新用户待清: $NU / $NID"