Skip to content

fix: 上传/SEO/搜索 多点加固 (SVG + 大小 + MIME 控制字符 + robots) (#320) #143

fix: 上传/SEO/搜索 多点加固 (SVG + 大小 + MIME 控制字符 + robots) (#320)

fix: 上传/SEO/搜索 多点加固 (SVG + 大小 + MIME 控制字符 + robots) (#320) #143

Workflow file for this run

name: Docs Backfill (on docs changes)
# 2026-04-17 起从"GH runner 直连 Neon"改为"SSH 进自建服务器跑脚本"。
# 原因:DB 从 Neon 迁到服务器自建 PG 后只绑 127.0.0.1:5432,不对公网暴露。
# 设计权衡见 wiki Frontend-Auth-And-Admin / 后端 docs/database.md。
#
# ⚠️ 这个 workflow 维护的是**贡献者署名记录的生命线**——谁写了哪篇文档、
# 文件改名/移动后署名不丢,全靠底层两个脚本:
# - scripts/uuid.mjs 生成/保持 docId frontmatter(永不改写已有值)
# - scripts/backfill-contributors.mjs 按 docId 累加 GitHub commits 到 DB,
# doc_paths 表维护历史路径并集跨改名追踪
# 若本 workflow 跑坏了(生成错 docId / 写坏 JSON / 写错 DB),署名可能丢失。
# 下面每一步前都有防御性检查,出错就 fail loud 不吞错。
#
# Secrets 依赖:
# SERVER_HOST / SERVER_USER / SERVER_SSH_KEY — SSH 远程登录三件套
# (私钥生成方式 + 公钥已写入服务器 ~/.ssh/authorized_keys,见 wiki)
on:
push:
branches:
- main
- feat/contributor
paths:
- "app/docs/**"
- "scripts/uuid.mjs"
- "scripts/backfill-contributors.mjs"
- "package.json"
- "pnpm-lock.yaml"
- ".github/workflows/sync-uuid.yml"
- "generated/doc-contributors.json"
workflow_dispatch: {}
concurrency:
group: backfill-${{ github.ref }}
cancel-in-progress: true
jobs:
backfill:
# 防止 fork、限定 main / feat/contributor、并避免机器人循环
if:
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/feat/contributor') &&
github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
steps:
- name: Run backfill on server via SSH
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
# 超时 15 分钟:backfill-contributors 要遍历所有 docs + 拉 GitHub API,
# 大改动一次跑 3-5 分钟,留足余量
command_timeout: 15m
# set -euo pipefail + BRANCH 透传,脚本内任何一步失败都让整个 action fail
envs: GITHUB_REF_NAME
script: |
set -euo pipefail
BRANCH="${GITHUB_REF_NAME:-main}"
# SSH 非交互 shell 不加载 ~/.bashrc / ~/.zshrc,nvm + pnpm 的 PATH
# 要手动 source 进来。否则 pnpm: command not found 直接卡住后面所有步骤。
# -s 开头表示"if file exists" 兼容 nvm 没装的极端情况。
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
cd /home/ubuntu/involution-hell-project/frontend
# ============================================================
# 0. 脏工作树检查
# ------------------------------------------------------------
# 为什么重要:下一步 git reset --hard 会抹掉所有未提交改动。
# 如果上次 workflow 跑到一半 uuid.mjs 写了 docId 但 backfill 失败没
# commit,这些"生成了的新 docId"在脏树里。reset 后 uuid.mjs 会生成
# 不同的新 UUID——不丢署名(因为从未 commit 到 main),但浪费 id
# 且可能造成 docId 分叉留给下一次排查。
#
# 更严重的场景:如果有人手工在服务器上 hotfix MDX 忘 commit,
# reset 会悄悄抹掉。一律 fail loud 强制人工介入更安全。
# ============================================================
if [[ -n "$(git status --porcelain)" ]]; then
echo "::error::服务器 frontend 工作树不干净,拒绝 reset。先人工处理后再重跑。"
git status --short
exit 1
fi
# 同步仓库到触发本次 workflow 的 commit
git fetch --prune origin
git checkout "$BRANCH"
git reset --hard "origin/$BRANCH"
# ============================================================
# 1. 加载环境变量 + 必要字段校验
# ------------------------------------------------------------
# DATABASE_URL 缺失时 backfill 会隐性降级(shouldSyncDb=false),
# 生成的 JSON 内容是"本轮快照"而非"DB 累计值",覆盖 commit 回仓
# 会把累计呈现变成单次快照——**视觉上像数据丢了**但 DB 没动。
# 直接 fail 不给它走降级路径。
# ============================================================
set -a && . ./.env && set +a
if [[ -z "${DATABASE_URL:-}" ]]; then
echo "::error::DATABASE_URL 未配置,拒绝运行以免 JSON 降级成本轮快照"
exit 1
fi
if [[ -z "${GITHUB_TOKEN:-}" ]]; then
echo "::warning::GITHUB_TOKEN 未配置,GitHub API rate limit 60/h 会打爆"
fi
# ============================================================
# 2. DB 健康检查
# ------------------------------------------------------------
# 如果本地 PG 意外被清库或未迁移完成,doc_contributors 表可能是空的。
# 从空 DB 起增量累计 → 早期已经超出 GitHub API 单文件 commits 最多 N 页
# 范围的老 commits 永远拉不回来 → 署名丢失。
#
# 下限 200 行是保守值:迁移完成后 doc_contributors 约 295 行,
# 低于 200 视为"异常状态",要人工确认后才能继续。
# ============================================================
CONTRIB_COUNT=$(docker exec involution-postgres \
psql -U neondb_owner -d involution_hell -tAc \
"SELECT count(*) FROM doc_contributors;" 2>/dev/null || echo "0")
if [[ "$CONTRIB_COUNT" -lt 200 ]]; then
echo "::error::doc_contributors 只有 $CONTRIB_COUNT 行(预期 >= 200),DB 状态异常,拒绝运行。"
echo "::error::如果是故意重置 DB,临时把本检查注释掉,一次跑完再恢复。"
exit 1
fi
echo "DB 健康检查通过:doc_contributors 有 $CONTRIB_COUNT 行"
# 3. 依赖和 Prisma client
pnpm install --frozen-lockfile
pnpm prisma generate
# ============================================================
# 4. 跑脚本
# ------------------------------------------------------------
# uuid.mjs:幂等补 docId;已有 docId 的文件绝对不改。
# backfill-contributors.mjs:按 docId 增量累加,doc_paths 表合并历史路径,
# 翻译版跳过,失败即 exit 1 让本 step fail 不进 commit。
# ============================================================
pnpm exec node scripts/uuid.mjs
pnpm exec tsx scripts/backfill-contributors.mjs
# ============================================================
# 5. 自动提交
# ------------------------------------------------------------
# 只 commit MDX frontmatter 改动 + 生成的 JSON,不包含任何其他脏文件。
# [skip ci] 防止自提交再次触发本 workflow 死循环。
# ============================================================
if ! git diff --quiet -- 'app/docs/**/*.md' 'app/docs/**/*.mdx' generated/doc-contributors.json; then
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add 'app/docs/**/*.md' 'app/docs/**/*.mdx' generated/doc-contributors.json
git commit -m "chore(docs): sync doc metadata [skip ci]"
git push origin "$BRANCH"
else
echo "No metadata changes to commit."
fi