Files
Agent-System-Dev/scripts/check_pin_regression.sh
T
weichen ba1d3b2b81 Add the pin-regression gate to pins checks and the PR gate
Why: PR #682 merged a stale branch that reset five component pins to
pre-batch values, silently dropping the batch-1 composition on main.
Evidence: materialized byte-exact from the reviewed transport
(gatemat-run.json); regression/forward/same/skip/missing-object cases
(verify-pingate.json); make test-governance and test-pins re-run below.
Impact: new check script wired into check-pins and task-pr-check;
PIN_REGRESSION_SKIP=1 documents deliberate downgrades.
Refs: feature/audit-followups-pin-gate-m5
2026-10-22 06:16:13 +00:00

101 lines
3.6 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
# 组合指针不倒退:HEAD 中每个 gitlink(deps/*、modules/*)相对 origin/main
# 只能前进——新 pin 必须以 origin/main 的旧 pin 为祖先。事故原型:PR #682
# 合入了过期分支,其树把五个组件 pin 重置回批次前的值,静默丢掉了 main 上
# batch-1 的组合。
#
# ┌─ 逃生口(须 owner Review)──────────────────────────────────────────────┐
# │ PIN_REGRESSION_SKIP=1 声明这是一次有意的降级:失败改为醒目的 warn 并 │
# │ 退出 0。只用于经组件 owner 审阅的刻意回退,PR │
# │ 描述须写明原因;不得用来绕过过期分支。 │
# └─────────────────────────────────────────────────────────────────────────┘
#
# 其他开关:
# PIN_REGRESSION_NO_FETCH=1 旧 pin 在子仓本地缺失时不尝试 fetch(测试/离线用)。
#
# 在当前工作目录所属仓库的顶层运行。origin/main 本地不可解析(浅检出)时只告警、退出 0。
set -euo pipefail
root=$(git rev-parse --show-toplevel)
cd "$root"
base=origin/main
skip=${PIN_REGRESSION_SKIP:-0}
if ! git rev-parse --verify -q "$base^{commit}" >/dev/null; then
echo "warn: $base is not resolvable locally; pin regression check skipped" >&2
exit 0
fi
fail=0
declare -A main_pins=()
while read -r mode _typ sha path; do
[ "$mode" = "160000" ] || continue
main_pins["$path"]=$sha
done < <(git ls-tree -r "$base")
# 子仓须是独立检出的仓库;未初始化时 git -C 会落到 Dev 自身。
own_repo() {
local path="$1" top
top=$(git -C "$path" rev-parse --show-toplevel 2>/dev/null) || return 1
[ "$top" = "$root/$path" ]
}
has_commit() {
git -C "$1" cat-file -e "$2^{commit}" 2>/dev/null
}
ensure_commit() {
local path="$1" sha="$2"
has_commit "$path" "$sha" && return 0
[ "${PIN_REGRESSION_NO_FETCH:-0}" = "1" ] && return 1
git -C "$path" fetch -q origin "$sha" >/dev/null 2>&1 || true
has_commit "$path" "$sha"
}
regress() {
if [ "$skip" = "1" ]; then
echo "warn: PIN_REGRESSION_SKIP=1 — $* (deliberate downgrade; requires owner review)" >&2
else
echo "pin: $*" >&2
fail=1
fi
}
while read -r mode _typ new path; do
[ "$mode" = "160000" ] || continue
old=${main_pins["$path"]:-}
if [ -z "$old" ]; then
echo "ok $path (new, not on $base)"
continue
fi
if [ "$old" = "$new" ]; then
echo "ok $path"
continue
fi
if ! own_repo "$path"; then
regress "$path is not checked out; cannot verify ${new:0:12} descends from $base ${old:0:12}"
continue
fi
if ! ensure_commit "$path" "$old"; then
regress "$path $base pin $old is missing locally and could not be fetched; cannot verify no regression"
continue
fi
if ! ensure_commit "$path" "$new"; then
regress "$path HEAD pin $new is missing locally and could not be fetched; cannot verify no regression"
continue
fi
if git -C "$path" merge-base --is-ancestor "$old" "$new"; then
echo "ok $path (forward ${old:0:12}..${new:0:12})"
continue
fi
regress "$path moves BACKWARD: $base is ${old:0:12}, HEAD is ${new:0:12} (not a descendant)." \
"This is the PR #682 pattern (a stale branch resetting pins over main): merge $base and re-pin," \
"or set PIN_REGRESSION_SKIP=1 for an owner-reviewed deliberate downgrade"
done < <(git ls-tree -r HEAD)
if [ "$fail" -ne 0 ]; then
exit 1
fi
echo "pin regression ok"