Skip to content

Commit e8145e7

Browse files
authored
Merge pull request #41 from full-stack-plugins/fix/guard-banner-first-line
fix(guard): 版本横幅不再前置——stderr 首行必须是综述
2 parents bff90b3 + 3d5e3e0 commit e8145e7

3 files changed

Lines changed: 34 additions & 1 deletion

File tree

‎hooks/gate_lib.py‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
from scope import FULL_SCAN_EXCLUDES, changed_files, scope_cmd
4343

4444
# === git 提交内容安全检查:绝不该进版本库的文件 ===
45+
CODEGUARD_VERSION = "0.12.0"
46+
4547
# 目录 = 构建产物/依赖快照**单一事实源**(scope.FULL_SCAN_EXCLUDES)+ IDE 目录。
4648
# 从单一来源派生:清单只在 scope.py 改一处,"入库面"与"扫描面"永不漂移
4749
# (此前两份手抄清单已经漂移:扫描面缺 out/.next/coverage 等 14 个目录,
@@ -140,7 +142,7 @@ def _gate_cache_path(project_root: Path) -> Path:
140142
return Path(tempfile.gettempdir()) / f"codeguard-gate-{os.getuid()}-{key}.json"
141143

142144

143-
def _worktree_fingerprint(project_root: Path) -> str:
145+
def _worktree_fingerprint(project_root: Path, *, max_files: int = 500) -> str:
144146
"""工作区指纹:三路改动的**名字 + stat** 指纹(不再哈希全文内容)。
145147
146148
只用 index mtime 会漏掉"文件已修但未 git add"——键不变 → 60 秒内继续
@@ -459,6 +461,24 @@ def check(lang: str):
459461
if not ok:
460462
return (lang, None, f"{lang} 工具链不可用未验证:{reason}(安装: {hint})")
461463

464+
# Java 门禁接入 java_project 分析:mvnw 感知 + 工具链失配归跳过。
465+
if lang == "java":
466+
try:
467+
from java_project import analyze as _jp_analyze
468+
_jp = _jp_analyze(str(project_root))
469+
if _jp.get("status") == "UNVERIFIED":
470+
return (lang, None,
471+
(f"{lang} 项目分析 UNVERIFIED({_jp.get('build_system', '?')}),"
472+
f"原因: {'; '.join(_jp.get('reasons', []))},本次未验证"))
473+
exe = _jp.get("executable")
474+
if exe and base_cmd and base_cmd[0] in ("mvn", "gradle"):
475+
base_cmd = [exe] + base_cmd[1:]
476+
except Exception as exc: # noqa: BLE001 — 分析失败不阻塞门禁,走原路径
477+
print(f"[codeguard] java_project 分析失败(走原路径): {exc!r}",
478+
file=sys.stderr)
479+
record_gate_decision(project_root, lang, base_cmd, -1,
480+
"UNVERIFIED", f"java_project 分析失败: {exc!r}")
481+
462482
outputs: list[tuple[int, str, str]] = []
463483
stale_notes: list[str] = []
464484
# 项目级命令(mvn/gradle 等,无 {file} 占位符)不追加文件路径——
@@ -877,11 +897,16 @@ def gate_directive(failures: list) -> str:
877897
"""
878898
header = [
879899
summarize_failures(failures),
900+
f"codeguard v{CODEGUARD_VERSION}",
880901
"─" * 60,
881902
"**给 AI 的强制指令**:提交门禁未通过,禁止执行 git commit / git push。\n"
882903
+ "**⚠️ 整个工具调用没有执行**:被拦截的是一次包含 git commit/push 的完整 Bash "
883904
"调用——其中非 git 的前序步骤(写文件、跑脚本)也全部未运行。请把「修复」与"
884905
"「提交」拆成两次独立的工具调用,修完再单独执行提交。\n"
906+
+ "**⚠️ 如果报错涉及 target/、dist/、build/ 下的构建产物**:请先单独"
907+
"运行清理命令(如 `rm -rf target/reports`,不含 git commit/push),"
908+
"清理完成后再重试提交——本门禁在命令执行前拦截,此前命令链中的清理"
909+
"步骤不会被执行。\n"
885910
+ "请立即处理:1) 按下面「怎么修」逐项修复(能自动修复的先跑自动修复命令);"
886911
"2) 纯 lint 类修复可直接继续、不必逐项追问;但凡涉及付费、发布、删除、"
887912
"密钥、或跨出本仓的操作,必须先征得用户同意再执行;"

‎hooks/pre_tool_git_guard.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,8 @@ def main() -> int:
650650
exact=True, pending_commit=pending_commit,
651651
)
652652
if failures:
653+
# 版本自标识由 gate_directive 首行综述之后的第二行承担——
654+
# 此处不再前置横幅:stderr 首行必须是综述(三个契约测试锁定)。
653655
reports.append(gate_directive(failures))
654656
unknown = [s for s in _skipped if "本次改动未涉及" not in s and " SKIPPED:" not in s
655657
and "markdown 风格告警" not in s]

‎tests/test_hardening_fixes.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ def test_directive_mentions_whole_call(self) -> None:
9090
self.assertIn("拆成两次独立的工具调用", text)
9191
# 首行契约保持:综述在最前
9292
self.assertTrue(text.splitlines()[0].startswith("codeguard ❌ 提交门禁未通过:"))
93+
# 版本自标识
94+
self.assertIn("codeguard v", text)
95+
# 构建产物清理自救指令
96+
self.assertIn("rm -rf target/reports", text)
97+
self.assertIn("不含 git commit/push", text)
98+
self.assertIn("命令执行前拦截", text)
9399

94100

95101
class CacheKeyTests(unittest.TestCase):

0 commit comments

Comments
 (0)