Files
knowledge-governance/scripts/wiki_e2e_test5.sh
T
姚章浩 ea6e56b304 feat(release): 文档发布会带上知识库 wiki 快照并支持撤权剥离
发布通道原来只有三条:PostgreSQL 关系行、Elasticsearch 分片、OSS 对象。
WeKnora 的 wiki 图谱是 wiki_pages 一张纯 PG 表(in_links/out_links 存 slug),
所以它不在任何通道里——撤权后生产 wiki 会一直留着已撤权文档的页面与引用。

本次新增第 5 条通道:库级 wiki 快照,挂在现有文档发布包里,检索与 wiki
同一个 release 单元(同一次执行、同一次校验、同一次回滚):

- 导出:ExportWiki 按 knowledge_base_id 全量读 wiki_pages/wiki_folders;
  收敛门禁(库内无解析中/合成中文档)不满足直接失败并给中文原因;
  未启用 wiki 且无 wiki 行的库不参与同步(生产 wiki 保持原样)。
- 撤权:item.Action == "delete" 时在导出端剥离该文档的 wiki 贡献
  (source_refs/chunk_refs 去条目、无引用页面整页不带、摘死链、清 parent_slug、
  无页面引用的空文件夹及其祖先一并去掉),使“源端仍在只停止发布”和
  “源端删除”两种情况收敛到同一结果。
- 导入:库级 replace-by-kb(同一事务内 DELETE by kb 后灌入快照,文件夹先于页面),
  新增 ReplaceWiki 供撤权路径使用(文档行只 disable,wiki 整体替换)。
- 校验:VerifyWiki 用生产 WeKnora wiki API 比对页面 slug 集合,撤权时额外断言
  生产 wiki 不再引用被撤权文档。

驱动与验收:新增 cmd/release-channel-e2e(复用发布 worker 真实代码路径,
支持 publish/withdraw/rollback),scripts/wiki_e2e_test5.sh、
scripts/wiki_e2e_newkb.sh 两套端到端脚本;证据见
docs/WIKI_CO_TRANSPORT_ACCEPTANCE.md。
2026-09-30 10:54:07 +08:00

107 lines
6.5 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
# wiki 同搬通道 5 文档验收脚本(本地模拟生产 = 测试服 weknora-test-v071)
# 用法:bash scripts/wiki_e2e_test5.sh
# 前置:三条 ssh 隧道(172.17.0.1:25432/29200/28080)已起,dist/release-channel-e2e 已构建
set -uo pipefail
cd "$(dirname "$0")/.."
REPO=$PWD
KB=c12ff4d5-dd87-423b-ab0f-af745b9d54a7
WK=http://127.0.0.1:8080
CFG=/run/release-sim/release.sim.json
DIST=$REPO/dist/release-channel-e2e
api() { curl -s -K /tmp/wk_curl.cfg "$@"; }
prod_sql() { docker run --rm --network host --env-file /tmp/target_pg.env postgres:16-alpine psql -At -P pager=off -c "$1"; }
prod_es_count() { # 用 keyword 子字段精确匹配(knowledge_id 是 text 字段,UUID 会被分词)
curl -s "http://172.17.0.1:29200/weknora_test_chunks/_count" -H 'Content-Type: application/json' \
-d "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"knowledge_id.keyword\":\"$1\"}},{\"term\":{\"is_enabled\":true}}]}}}" \
| python3 -c "import sys,json;print(json.load(sys.stdin).get('count'))"
}
release() { # release <knowledge> <mode> <revision>
docker run --rm --user "$(id -u):$(id -g)" \
--network knowledge-governance-p1_default --network weknora071full-network \
--add-host prod-pg:host-gateway --add-host prod-es:host-gateway --add-host prod-weknora:host-gateway \
-v "$REPO/secrets/release-sim":/run/release-secrets:ro \
-v "$REPO/config/release.sim.json":/run/release-sim/release.sim.json:ro \
-v knowledge-governance-release-bundles:/var/lib/knowledge-governance/release-bundles \
-v "$DIST":/release-channel-e2e:ro \
--entrypoint /release-channel-e2e knowledge-governance-p1-release-worker:latest \
-config "$CFG" -knowledge "$1" -mode "$2" -revision "$3" 2>&1 | grep -E "STEP|bundle|wiki (before|after)|route kb"
}
echo "### 1. 上传 4 篇同主题文档(与首篇共贡 wiki 页)"
write_doc() { cat > "/tmp/wiki_e2e_$1.md"; }
write_doc b <<'EOF'
# 来源与目录:停止知识的语义
知识治理平台在“来源与目录”视图里可以停止某条知识。停止的含义是:生产端不再检索它。
需要注意,停止不会改动测试端 WeKnora 的 wiki:只有删除文档才会触发 wiki 清理链。
因此 wiki 快照在撤权时由发布通道负责剥离该文档的贡献。
EOF
write_doc c <<'EOF'
# 发布通道之 PostgreSQL 与 Elasticsearch
发布通道把知识治理平台评审通过的知识写进生产端 WeKnora。
PostgreSQL 负责关系行:knowledges、chunks、knowledge_tags、resources。
Elasticsearch 负责检索分片与向量,索引名称为 weknora_test_chunks。
撤权时 Elasticsearch 通过 delete-by-query 清空该文档分片。
EOF
write_doc d <<'EOF'
# 发布通道之 OSS 对象与图片资源
文档里的图片与附件存放在对象存储 OSS。发布时先写入暂存路径,再用 CopyObject 拷到生产桶。
resources 表保存 storage:// 定位符,搬运时只替换桶名。
知识治理平台与测试端 WeKnora、生产端 WeKnora 共用同一套对象通道实现。
EOF
write_doc e <<'EOF'
# 撤权与回滚演练
撤权(withdraw)会把生产端知识置为 disabled 并清空检索分片,同时重放 wiki 快照。
回滚(rollback)会整包还原上一版 revision,包括 wiki 快照。
因此生产端 WeKnora 永远不会出现“检索没了、wiki 还在”的中间态。
EOF
for k in b c d e; do
id=$(api -X POST -F "file=@/tmp/wiki_e2e_$k.md" -F "fileName=wiki-e2e-$k.md" "$WK/api/v1/knowledge-bases/$KB/knowledge/file" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
echo "doc $k -> $id"
printf '%s\n' "$id" > "/tmp/wiki_e2e_id_$k"
done
echo "### 2. 等 5 篇全部收敛(parse=completed 且 wiki 子任务为 0)"
for i in $(seq 1 40); do
pending=$(docker exec WKNFull-postgres psql -U weknora -d weknora_full -At -c "select count(*) from knowledges where knowledge_base_id='$KB' and deleted_at is null and (parse_status <> 'completed' or pending_subtasks_count > 0)")
total=$(docker exec WKNFull-postgres psql -U weknora -d weknora_full -At -c "select count(*) from knowledges where knowledge_base_id='$KB' and deleted_at is null")
pages=$(docker exec WKNFull-postgres psql -U weknora -d weknora_full -At -c "select count(*) from wiki_pages where knowledge_base_id='$KB' and deleted_at is null")
echo " [$i] docs=$total 未收敛=$pending wiki_pages=$pages"
[ "$total" -ge 5 ] && [ "$pending" = "0" ] && break
sleep 20
done
echo "### 3. 逐篇发布(每次发布会推整库 wiki 快照)"
i=0
for id in $(cat /tmp/wiki_e2e_id_b) 9be3e0fa-e699-4a8e-be0c-0d934ee33294 $(cat /tmp/wiki_e2e_id_c) $(cat /tmp/wiki_e2e_id_d) $(cat /tmp/wiki_e2e_id_e); do
i=$((i+1))
echo "--- publish #$i $id"
release "$id" publish "wiki-e2e-5doc-p$i" | tail -4
done
echo "### 4. 生产端证据(5 篇)"
prod_sql "select 'enabled='||count(*) filter (where enable_status='enabled')||' total='||count(*) from knowledges where knowledge_base_id='$KB'"
prod_sql "select 'wiki_pages='||(select count(*) from wiki_pages where knowledge_base_id='$KB')||' wiki_folders='||(select count(*) from wiki_folders where knowledge_base_id='$KB')"
echo "共贡页面(source_refs 多于一条):"
prod_sql "select slug||' <- '||source_refs::text from wiki_pages where knowledge_base_id='$KB' and jsonb_array_length(coalesce(source_refs,'[]'::jsonb)) > 1 order by slug limit 8"
for id in $(cat /tmp/wiki_e2e_id_b) $(cat /tmp/wiki_e2e_id_c) 9be3e0fa-e699-4a8e-be0c-0d934ee33294; do
echo " ES $id count=$(prod_es_count "$id")"
done
echo "### 5. 撤权其中一篇(doc b),验证共贡页面保留、专属页面消失、其它文档不受影响"
release "$(cat /tmp/wiki_e2e_id_b)" withdraw "wiki-e2e-5doc-w1" | tail -5
echo "--- 生产端证据(撤权后)"
prod_sql "select id||' enable='||enable_status from knowledges where knowledge_base_id='$KB' order by enable_status, id"
prod_sql "select 'wiki_pages='||count(*) from wiki_pages where knowledge_base_id='$KB'"
prod_sql "select 'folders='||count(*) from wiki_folders where knowledge_base_id='$KB'"
echo "还有引用被撤权文档的页面(应为 0):"
prod_sql "select count(*) from wiki_pages where knowledge_base_id='$KB' and source_refs::text like '%$(cat /tmp/wiki_e2e_id_b)%'"
echo "共贡页面是否仍在:"
prod_sql "select slug||' <- '||source_refs::text from wiki_pages where knowledge_base_id='$KB' and jsonb_array_length(coalesce(source_refs,'[]'::jsonb)) > 0 order by slug limit 8"
echo "ES 分片:"
for id in $(cat /tmp/wiki_e2e_id_b) $(cat /tmp/wiki_e2e_id_c); do echo " $id count=$(prod_es_count "$id")"; done