fix(mirror): 翻 public 的时机、快照强推、上游不可用时降级

四处修复,都来自本次重跑 openwork 时实际踩到的失败:

1. 翻 public 从「推送之前」移到「推送成功之后」
   原实现先翻可见性再推,踩出「仓库已 public + 内容还是旧快照」的窗口期:
   --set-public 成功 → 推送被拒(source-only 历史不连续) → 公开了旧版本。
   旧内容虽不含 ee/(合法),但公开了不该公开的版本,正是最该避免的局面。
   正确顺序:先推对内容,再翻可见性;任一步失败都停在 private,无害。
   收紧方向(private)仍留在同步前——锁起来永远安全,早做没代价。

2. source-only 快照改强推
   每次快照都是 checkout → git init → 单次 commit,与远端上次快照无血缘,
   永远不可能 fast-forward。改了排除项后重跑必被拒:"! [rejected] fetch first"。
   强推在此语义正确:source-only 保的是当前源码状态,不是历史链。

3. 新增 --no-fetch
   GitHub 连不上(Empty reply from server)时脚本在 fetch 阶段就退出,
   本地裸仓明明有 18763 条 commit 却什么都做不了。
   上游不可用不该阻止用已有内容重做快照。

4. 补充 LICENSES/LicenseRef-OpenWork-EE.txt 到 openwork 的 excludes
   详见上一提交,此处是让它真正生效后落库。

新增 scripts/validate.py:档案 schema 校验。
起因是我手写临时探针把 risk.claim_vs_reality 写成顶层字段,
得到「该字段 0 条」的错误结论——层级写错不报错,只会安静返回 0。
校验项含:核心字段完整性、claim_vs_reality 下限与 source 必填、
excludes 与 redistributable_after_excludes 的一致性、
以及自动抓「七个里」这类随样本增加即过时的计数表述。
当前 7 个项目全部通过。
This commit is contained in:
gitea-publish
2026-09-02 01:07:11 +08:00
parent 56e2c8a403
commit 8be2e8e611
3 changed files with 223 additions and 22 deletions
+47 -20
View File
@@ -24,6 +24,8 @@ SOURCE_ONLY_FORCE="no"
# private → public 的显式授权开关。默认 0:公开不可逆,绝不自动放宽。
SET_PUBLIC="0"
EXCLUDE_COUNT="0"
# 跳过上游更新(本地裸仓已完整,只为重做快照时用)
NO_FETCH="0"
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -33,6 +35,7 @@ while [[ $# -gt 0 ]]; do
--depth) DEPTH="$2"; shift 2;;
--no-source-only) SOURCE_ONLY="no"; shift;;
--set-public) SET_PUBLIC="1"; shift;;
--no-fetch) NO_FETCH="1"; shift;;
*) echo "未知参数: $1" >&2; exit 1;;
esac
done
@@ -146,27 +149,16 @@ if [[ "${VISIBILITY}" == "private" ]]; then
-H 'Content-Type: application/json' -d '{"private":true}' "${API}/repos/${ORG}/${REPO_NAME}" || true
fi
# ---- 放宽方向(private → public)必须显式授权 ----
# 公开是不可逆动作:一旦有人 fork/克隆,就再也收不回来。
# 所以这里**不自动翻**——只报告,要求显式加 --set-public。
# 2026-09-02 补:原先脚本只有"收紧"方向的修正,openwork 判定为 public 但仓库
# 停在 private,重跑多少次都不会翻过来,档案与事实不一致却看不出原因。
# ---- 放宽方向(private → public)推迟到推送成功之后做 ----
# 2026-09-02 的教训:这段原先放在同步之前,结果 openwork 翻成了 public
# 但推送失败(source-only 快照历史不连续被拒),
# 于是出现「仓库已公开 + 内容仍是旧快照」的窗口期——
# 虽然旧内容也不含 ee/(合法),但公开了不该公开的版本,正是最该避免的局面。
# 正确顺序:先推成功、内容对了,再翻可见性。任一步失败都停在 private,无害。
# 这里只做一次探测,真正的翻转在文件末尾 apply_visibility()。
if [[ "${VISIBILITY}" == "public" ]]; then
CUR_PRIVATE="$(curl -sS -u "${GITEA_USER}:${GITEA_TOKEN}" "${API}/repos/${ORG}/${REPO_NAME}" \
| /Users/figmarlite/.workbuddy/binaries/python/envs/default/bin/python -c 'import sys,json;print("true" if json.load(sys.stdin).get("private") else "false")' 2>/dev/null || echo unknown)"
if [[ "${CUR_PRIVATE}" == "true" ]]; then
if [[ "${SET_PUBLIC}" == "1" ]]; then
echo " ⚠ 按 --set-public 将 ${ORG}/${REPO_NAME} 从 private 翻为 public(不可逆)"
curl -sS -o /dev/null -u "${GITEA_USER}:${GITEA_TOKEN}" -X PATCH \
-H 'Content-Type: application/json' -d '{"private":false}' "${API}/repos/${ORG}/${REPO_NAME}" \
&& echo " 已翻为 public"
else
echo ""
echo " ⚠ ${ORG}/${REPO_NAME} 判定应为 public,但远端当前是 private。"
echo " 公开不可逆,脚本默认不自动翻。确认后重跑并加 --set-public。"
echo " 判定依据:许可证 ${LIC_LEVEL},排除 ${EXCLUDE_COUNT} 项后 redistributable=${VISIBILITY}"
fi
fi
fi
# ---- 同步 ----
@@ -202,7 +194,17 @@ if [[ -d "${MIRROR_DIR}" ]] && ! repo_ok; then
rm -rf "${MIRROR_DIR}"
fi
if repo_ok; then
if [[ "${NO_FETCH}" == "1" ]]; then
# 跳过上游更新,直接用本地裸仓生成快照。
# 2026-09-02 需要这个:本地裸仓已是完整的,只想重跑一次快照(改了排除项),
# 但 GitHub 恰好连不上("Empty reply from server"),脚本在 fetch 阶段就退出,
# 明明有数据却什么都做不了——上游不可用时,不该阻止我们用已有内容重做快照。
if repo_ok; then
echo " 跳过上游更新(--no-fetch),直接用本地裸仓生成快照"
else
echo "✗ --no-fetch 但本地裸仓不可用:${MIRROR_DIR}" >&2; exit 1
fi
elif repo_ok; then
if is_shallow && [[ -z "${DEPTH}" ]]; then
# 慢链路续传:分批 --deepen。每批成功即落盘,中断后重跑本脚本可继续,
# 不像 `git clone` 那样失败一次全部作废。
@@ -402,7 +404,32 @@ echo " 推送到 ${ORG}/${REPO_NAME} ..."
if [[ "${MIRROR_MODE}" == "full" ]]; then
git -C "${PUSH_DIR}" push --mirror "${PROTO}://${U_ENC}:${P_ENC}@${HOST}/${ORG}/${REPO_NAME}.git"
else
git -C "${PUSH_DIR}" push "${PROTO}://${U_ENC}:${P_ENC}@${HOST}/${ORG}/${REPO_NAME}.git" HEAD:refs/heads/main
# source-only 必须强推:每次快照都是「checkout → git init → 单次 commit」,
# 与远端上一次的快照 commit 毫无血缘关系,永远不可能 fast-forward。
# 2026-09-02 踩到:改了排除项后重跑,推送被拒
# "! [rejected] HEAD -> main (fetch first)"
# 但排除校验明明通过了——不是排除没生效,是历史不连续。
# 强推在这里语义正确:source-only 镜像保的是**当前源码状态**,不是历史链。
# 若哪天需要保留历史,该做的是增量快照而非回滚这个 force。
echo " (source-only 快照,强推覆盖:历史不连续是设计使然)"
git -C "${PUSH_DIR}" push --force "${PROTO}://${U_ENC}:${P_ENC}@${HOST}/${ORG}/${REPO_NAME}.git" HEAD:refs/heads/main
fi
# ---- 可见性放宽:走到这里说明内容已经推对了,才允许公开 ----
# 见上方 2026-09-02 的说明:翻转必须发生在成功推送之后。
# 收紧方向(private)在同步前就做了,因为锁起来永远安全、早做没代价。
if [[ "${VISIBILITY}" == "public" && "${CUR_PRIVATE}" == "true" ]]; then
if [[ "${SET_PUBLIC}" == "1" ]]; then
echo " ⚠ 内容已推送且排除校验通过 → 将 ${ORG}/${REPO_NAME} 翻为 public(不可逆)"
curl -sS -o /dev/null -u "${GITEA_USER}:${GITEA_TOKEN}" -X PATCH \
-H 'Content-Type: application/json' -d '{"private":false}' "${API}/repos/${ORG}/${REPO_NAME}" \
&& echo " 已翻为 public"
else
echo ""
echo " ⚠ ${ORG}/${REPO_NAME} 判定应为 public,但远端当前是 private。"
echo " 内容已推送且排除校验通过;公开不可逆,确认后重跑并加 --set-public。"
echo " 判定依据:许可证 ${LIC_LEVEL},排除 ${EXCLUDE_COUNT} 项后 redistributable=public"
fi
fi
# ---- 回写档案 ----