增加不可变源码检出、两阶段 finalize/activate、Runtime 同源对象读取与 iframe 安全边界,并用 fail-closed CI 门固定契约。Git 仅提交平台实现、契约、迁移和 SoT,不包含具体游戏源码、素材、bundle 或验收证据。
75 lines
4.8 KiB
Bash
Executable File
75 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 治理机器门 pre-commit(激活一次:git config core.hooksPath .githooks)
|
||
# 各门按暂存文件路径条件触发(判据没动的提交不跑对应门,省时间);
|
||
# 紧急绕过:git commit --no-verify(服务端 Gitea Actions 门仍会兜住)。
|
||
set -uo pipefail
|
||
|
||
STAGED="$(git diff --cached --name-only)"
|
||
ROOT="$(git rev-parse --show-toplevel)"
|
||
fail=0
|
||
|
||
# ── 门 1:文档治理七检 —— 触发 = 任一 .md 变更 ──
|
||
if printf '%s\n' "$STAGED" | grep -qE '\.md$'; then
|
||
bash "$ROOT/.agents/tools/docs-gate.sh" || { echo '✘ docs-gate 七检未过'; fail=1; }
|
||
fi
|
||
|
||
# ── 门 2:门金标判例库全量回归 —— 触发 = 触及任一验收门判据或判例库自身 ──
|
||
# 判据文件改动前必须先让本回归全绿(误杀/漏放判例不得回退),口径见 contracts/gate-fixtures/README.md。
|
||
if printf '%s\n' "$STAGED" | grep -qE '(play\.cdp\.cjs|amodel-gen/tools\.mjs|check-undef\.mjs|gate_judge\.py|cheap_gates\.py|^contracts/gate-fixtures/)'; then
|
||
node "$ROOT/contracts/gate-fixtures/run.mjs" || { echo '✘ 门金标判例库回归未过'; fail=1; }
|
||
fi
|
||
|
||
# ── 门 3:play-loop 契约校验(PlaySpec C5 / VerdictFeedback C6)—— 触发 = 触及 play-loop 契约 ──
|
||
if printf '%s\n' "$STAGED" | grep -qE '^contracts/play-loop/'; then
|
||
python3 "$ROOT/contracts/play-loop/validate.py" --suite || { echo '✘ play-loop 契约正负样本套件未过'; fail=1; }
|
||
fi
|
||
|
||
# ── 门 3b:游戏内容对象存储契约正负样本 —— 触发 = 三份清单/状态迁移/实现或判例变更 ──
|
||
if printf '%s\n' "$STAGED" | grep -qE '(contracts/(game-(package|artifact-manifest|source-archive)\.schema\.json|db-schemas/V3[45].*artifact)|game-cloud/huijing-server/src/main/resources/db/migration/V3[45].*artifact|tier2/gen-worker/(worker/game_(artifact|source_archive|artifact_storage)_store\.py|worker/game_content_repository\.py|scripts/game_content_repository\.py|tests/test_game_(artifact|source_archive|artifact_storage|content_repository)))'; then
|
||
# mise 的默认 Python 可能未装 pytest;仓内测试 venv 可用时复用,否则明确判红,绝不静默跳过。
|
||
PYTEST_PYTHON=python3
|
||
if ! "$PYTEST_PYTHON" -c 'import pytest' >/dev/null 2>&1; then
|
||
if [ -x "$ROOT/cheap-worker/.venv/bin/python" ] \
|
||
&& "$ROOT/cheap-worker/.venv/bin/python" -c 'import pytest' >/dev/null 2>&1; then
|
||
PYTEST_PYTHON="$ROOT/cheap-worker/.venv/bin/python"
|
||
else
|
||
echo '✘ 游戏内容对象存储门缺少 pytest(默认 Python 与 cheap-worker/.venv 均不可用)'
|
||
PYTEST_PYTHON=''
|
||
fail=1
|
||
fi
|
||
fi
|
||
if [ -n "$PYTEST_PYTHON" ]; then
|
||
PYTHONPATH="$ROOT/tier2/gen-worker" "$PYTEST_PYTHON" -m pytest -q \
|
||
"$ROOT/tier2/gen-worker/tests/test_game_artifact_store.py" \
|
||
"$ROOT/tier2/gen-worker/tests/test_game_source_archive.py" \
|
||
"$ROOT/tier2/gen-worker/tests/test_game_artifact_storage_store.py" \
|
||
"$ROOT/tier2/gen-worker/tests/test_game_artifact_storage_ddl.py" \
|
||
"$ROOT/tier2/gen-worker/tests/test_game_content_repository.py" \
|
||
|| { echo '✘ 游戏内容对象存储契约正负样本未过'; fail=1; }
|
||
fi
|
||
fi
|
||
|
||
# ── 门 4:品类 rubric fixture ↔ skill 双写对账 —— 触发 = 触及品类 rubric fixture 或品类 skill ──
|
||
if printf '%s\n' "$STAGED" | grep -qE '(cheap-worker/fixtures/genre-rubrics/|\.agents/skills/(trpg|heritage|puzzle|narrative|sim-business)-game-design\.md)'; then
|
||
python3 "$ROOT/.agents/tools/rubric-sync-gate.py" || { echo '✘ rubric 双写对账未过'; fail=1; }
|
||
fi
|
||
|
||
# ── 门 6:便宜档插件面三方一致性对账 —— 触发 = 触及插件目录/prompt 白名单/host-config 注入/PLUGIN_KEY_DIR ──
|
||
# 防漂移:白名单列了但没注入(运行时崩)、注入了但白名单没列(暗资产)、新增插件目录未裁定(悄悄成暗插件)。
|
||
if printf '%s\n' "$STAGED" | grep -qE '(game-runtime/src/plugins/|contracts/prompts/04-config/cheap-system\.md|game-runtime/games/_template/src/host-config\.js|amodel-gen/tools\.mjs)'; then
|
||
python3 "$ROOT/.agents/tools/plugin-surface-gate.py" || { echo '✘ 插件面三方对账未过'; fail=1; }
|
||
fi
|
||
|
||
# ── 门 5:Prompt 契约双闸 —— 触发 = 触及 prompts 契约(registry.yaml 或任一 prompt .md) ──
|
||
# 闸 a = 版本一致性(check_registry:registry.yaml↔.md frontmatter 的 version 必须相等);
|
||
# 闸 b = 四道闸·闸0 版本升号(check_version_bump:改了 prompt 正文相对 HEAD 必须升 version)。
|
||
if printf '%s\n' "$STAGED" | grep -qE '^contracts/prompts/'; then
|
||
python3 "$ROOT/contracts/prompts/check_registry.py" || { echo '✘ Prompt Registry 版本一致性未过'; fail=1; }
|
||
python3 "$ROOT/contracts/prompts/check_version_bump.py" || { echo '✘ Prompt 闸0 version 升号未过(改正文须升 version)'; fail=1; }
|
||
fi
|
||
|
||
if [ "$fail" -ne 0 ]; then
|
||
echo '提交被拦(明细见上;紧急绕过 git commit --no-verify,服务端门仍兜)'
|
||
exit 1
|
||
fi
|