Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@
"source": {
"source": "url",
"url": "https://github.com/partme-ai/partme-codeguard-plugin.git",
"ref": "v0.14.5"
"ref": "v0.14.6"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_USE"
},
"category": "Developer Tools",
"version": "0.14.5",
"version": "0.14.6",
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.5/assets/official-logo.png",
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.6/assets/official-logo.png",
"interface": {
"displayName": "代码规范守卫",
"shortDescription": "Trustworthy code checks and Java impact analysis",
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.5/assets/official-logo.png"
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.6/assets/official-logo.png"
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codeguard",
"version": "0.14.5+codex.20260923",
"version": "0.14.6+codex.20260923",
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
"author": {
"name": "Full Stack Skills / PartMe.AI",
Expand Down
2 changes: 1 addition & 1 deletion .zcode-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"en": "CodeGuard",
"zh-CN": "代码规范检查"
},
"version": "0.14.5",
"version": "0.14.6",
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
"description_i18n": {
"en": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Root codeguard.json may set gate_scope to delta or repo and customize extension/
The registry contains **54 Stable adapters and 3 Planned entries**. “Stable” does not certify every toolchain or project. Markdown/YAML require project configuration; missing configuration is UNVERIFIED. Markdown findings are advisory. Generated and dependency directories are excluded from ordinary lint scope, not automatically accepted for commit. Python checks honor the project's own ruff configuration (ruff.toml / .ruff.toml / [tool.ruff]); when none exists, codeguard injects a default rule set pinned to the CI baseline (ruff==0.16.8) so verdicts do not drift with whichever ruff version a machine happens to have. Full command inventory: [languages](docs/LANGUAGES.md).

The explicit escape hatch git config codeguard.skipGate true bypasses the hook gate and is recorded in session summaries. Shared hook state lives under CODEGUARD_HOME (default ~/.codeguard).
The Git gate statically inspects one readable shell-wrapper layer, including bare assignment, env, command and sudo prefixes; the same prefix rules apply to skipGate changes and one-shot bypasses. It does not execute or fully interpret shell scripts.

## External skills

Expand Down
1 change: 1 addition & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ python3 scripts/run_check.py --mcp /path/to/project
注册表含 **54 个 Stable 适配器和 3 个 Planned 项**。“Stable” 不证明全部工具链或项目已验证。Markdown/YAML 需要项目配置,缺配置为 UNVERIFIED;Markdown 违规只告警。生成物和依赖目录从普通 lint 范围排除,不等于允许入库。Python 检查优先使用项目自有 ruff 配置(ruff.toml / .ruff.toml / [tool.ruff]);项目无自有配置时注入钉扎在 CI 基线(ruff==0.16.8)的默认规则集,判定不随机器上 ruff 版本漂移。完整命令见[语言清单](docs/LANGUAGES.md)。

显式逃生门 git config codeguard.skipGate true 会绕过钩子门禁,并在会话总结中记录。共享状态位于 CODEGUARD_HOME(默认 ~/.codeguard)。
Git 门禁静态读取一层 Shell 包装命令,支持可解析的裸环境赋值、env、command 和 sudo 前缀;同一前缀规则也用于 skipGate 状态变更和单次豁免。它不执行或完整解释脚本。

## 外部技能

Expand Down
1 change: 1 addition & 0 deletions docs/current-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ flowchart TD
Git 命令的仓库定位与拟暂存解析共用入口传入的 cwd;显式 `cd`/`git -C` 无法绑定 Git 工作树时,硬门禁给出目标未验证并阻断,不退回到调用者仓或无关子仓。未给出显式目标且调用目录非仓时仍保留 workspace 子仓兜底。静态命令解析不等于完整 Shell 执行模拟。
一条命令链中的 Git 副作用先绑定为仓库与操作的有序对,再按仓库聚合检查面:纯 push 不读取该仓未提交的 index,同仓 commit→push 则保留已有 HEAD 与拟提交内容的并集。仓库级、内联及链式 `skipGate` 均按目标仓与操作顺序生效;已存在的仓库配置也可被同链先行 `git config --unset` 取消。链式设置跨 `||`、`;` 或换行时无法证明生效,门禁要求拆分命令;写入其它文件的 config 设置也不构成本仓豁免。语法、仓库归属、间接脚本与拟暂存分析共用引号/转义感知切分;参数文本中的控制符不能合成豁免。解析能力仍限于受支持的静态 Shell 形态。
一层 `bash`/`sh`/`zsh` 的 `-c`(含组合短选项)及可读脚本现在携带调用目录与正文进入同一 Git 操作计划;脚本内的 `git add` 可进入拟暂存范围,外层和内层 Git 操作按仓分别检查。识别到无法建模的间接 Git 操作、脚本内 `skipGate` 配置变更或跨解释器的暂存/提交关系时,明确以 Git 意图 UNVERIFIED 阻断,不借用调用者仓的检查结果。动态脚本、任意控制流及 Python/Node 中构造的 subprocess 仍未建模。
直接 Git 命令、解释器入口及 `skipGate` 状态/内联豁免解析共用裸前缀归一化;可解析的环境赋值、`env FOO=1`、`command` 和无参数 `sudo` 不会遮蔽后面的 Shell 提交或豁免取消。带值 wrapper 参数和运行时生成命令仍不在静态保证范围内。

## 模块所有权

Expand Down
2 changes: 1 addition & 1 deletion kimi.plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codeguard",
"version": "0.14.5",
"version": "0.14.6",
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
"author": {
"name": "Full Stack Skills / PartMe.AI"
Expand Down
3 changes: 3 additions & 0 deletions openspec/changes/refactor-codeguard-architecture/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ flowchart TD
源码误当 Shell 执行计划:它们若被保守静态扫描命中但无法证明行为,返回明确的 Git
意图未验证,不能用外层仓库检查结果代替。仍只支持一层、静态可读的脚本,不推断任意
控制流、动态脚本生成或解释器在运行时调用的 subprocess。
`git_syntax` 的命令前缀归一化同时供直接 Git 命令、解释器入口与仓库级/内联豁免解析使用:裸 `env`、环境赋值、
`command`、无参数 `sudo` 不再遮蔽后面的静态 Shell 正文或 skipGate 状态变化。带值 wrapper 选项仍属明确边界,
不能把它们当成已完全求值的 Shell。

参考:pre-commit 的 [Language Protocol 与通用执行](https://github.com/pre-commit/pre-commit/blob/main/pre_commit/lang_base.py)、[Python 适配器](https://github.com/pre-commit/pre-commit/blob/main/pre_commit/languages/python.py)。只借鉴边界设计,不复制安装环境逻辑或新增插件生态协议。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ index 或工作树;不支持的动态/交互式形态必须明确未验证,
拟暂存分析 MUST 使用脚本的实际调用目录和同一份内层命令;外层直接 Git 操作与内层操作
不得互相覆盖。若已识别间接 Git 副作用但不能可靠建立仓库或暂存计划,MUST 报告 Git
意图 UNVERIFIED 并阻断,不得回退扫描无关子仓或以错误仓库的 PASS 放行。
静态可解析的环境赋值、`env`、`command` 与无参数 `sudo` 等裸命令前缀 MUST 在 Shell
解释器检测、直接 Git 检测及 `skipGate` 设置/取消/内联豁免中共享同一归一化语义,
不能让同一个 `bash -c` 的提交因前缀而逃过门禁,也不能漏掉前缀后的豁免状态变更而
错误继承持久豁免;带参数且无法静态解析的 wrapper 不在此保证范围内。

#### Scenario: Two repositories have different staging commands
- **WHEN** 一条命令链对 A 执行 add -A、对 B 只提交已暂存内容
Expand Down Expand Up @@ -247,6 +251,14 @@ index 或工作树;不支持的动态/交互式形态必须明确未验证,
- **WHEN** 从 Git 仓执行 `bash -c 'git commit'` 或相对路径脚本,脚本内存在待提交内容
- **THEN** 将内层 commit 绑定到脚本调用目录的 Git 仓,而非报无仓或扫描其子仓

#### Scenario: A bare prefix does not hide a shell commit
- **WHEN** 可读的 `bash -c` 或脚本前有环境赋值、`env FOO=1`、`command` 或无参数 `sudo` 前缀,内层提交包含敏感暂存内容
- **THEN** 检测、仓库归属和拟暂存分析仍使用同一内层命令,按目标仓阻断;前缀本身不构成豁免

#### Scenario: A bare prefix does not hide a bypass change
- **WHEN** 仓库原有 `skipGate=true`,同链先执行 `env FOO=1 git config codeguard.skipGate false` 再提交敏感文件
- **THEN** 后续提交不继承原持久豁免,仍运行门禁并阻断;带前缀的 `git -c` 单次豁免仍仅作用于其自身操作

#### Scenario: Script arguments are not interpreter options
- **WHEN** 一个无 Git 副作用的脚本接收名为 `-c` 的普通参数及包含 `git commit` 的文本
- **THEN** 解析器不得把脚本参数当成解释器 `-c` 代码并虚构 Git 副作用
Expand Down
4 changes: 2 additions & 2 deletions openspec/changes/refactor-codeguard-architecture/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@
- [x] 5.1 增加自动架构依赖/循环检查并接入 CI,临时源码树注入反向依赖/函数内导入/相对导入环后确实拒绝;本地已验证,远端 CI 待发布阶段。不以文件行数当合格标准。
- [x] 5.2 四个历史 skipped 已全部恢复;Dockerfile CLI 接入统一报告解析与扫描应用,14 项真实进程边界测试通过;基线比较按诊断内容和次数核验并要求基线实际 FAIL,三项误豁免用例先红后绿。完整 433 项单测零跳过、142 项回归零失败。
- [x] 5.3 新增当前架构 Mermaid 与扩展指南;报告版本读取插件 manifest,双语 README 指向当前证据,旧设计标明历史范围;双语标题/链接/版本及本地链接存在性测试通过。发布版本仍需在 5.5 检查。
- [x] 5.4 全量单测/真实 hook 回归/ruff/语言 schema/vendor 离线与在线/本 change strict 和逐条规格追溯通过;第十九批 495 项单测、143 项真实 Hook 回归、57 项/11 规则,证据见 verification.md。仅证明本地契约,不等同三宿主现场验收。
- [ ] 5.5 按仓规升级版本、生成市场元数据、授权的 PR/CI/不可变 tag/Release 闭环;v0.14.4 阶段版本已完成插件/市场双仓合并、PR/main CI、tag/Release,但第十九批新改动仍需独立发布。宿主安装运行独立记录,未授权不得改宿主。
- [x] 5.4 全量单测/真实 hook 回归/ruff/语言 schema/vendor 离线与在线/本 change strict 和逐条规格追溯通过;第二十批 500 项单测、143 项真实 Hook 回归、57 项/11 规则,证据见 verification.md。仅证明本地契约,不等同三宿主现场验收。
- [ ] 5.5 按仓规升级版本、生成市场元数据、授权的 PR/CI/不可变 tag/Release 闭环;第十九批已发布 v0.14.5(插件 PR #51、市场 PR #8、PR/main CI、注释 tag/正式 Release 均核对)。第二十批已准备 v0.14.6 元数据与本地验证,远端 PR/CI/tag/Release/市场主线仍待核对。宿主安装运行独立记录,未授权不得改宿主。
- [ ] 5.6 完成全目标审计,代码/规格/证据一致后同步并归档 change,才可将整体优化标记完成。
10 changes: 10 additions & 0 deletions openspec/changes/refactor-codeguard-architecture/verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,13 @@
- 一层 bash/sh/zsh `-c`(含 `-lc`)或可读脚本现在按解释器实际参数位置、调用目录解析;内层 Git 操作携带来源正文与 cwd,和外层操作按仓聚合。拟暂存分析合并外层与内层来源,真实 Hook 子进程证明未实际执行 `git add` 就拦截 `.env` 且 index 字节不变。纯 push 不纳入未提交 index;外层 skipGate 设置只传递给所属仓的内层操作。
- 不能可靠建模的 Python/Node 间接命中、脚本内 skipGate 配置变化、交互暂存与后续提交跨解释器边界时,明确返回 Git 意图 UNVERIFIED 并阻断;仅在纯 push 之后的独立暂存不误扩该 push 面。脚本的普通 `-c` 参数不再被误认成解释器代码。动态脚本与任意 subprocess 构造仍是未覆盖边界。
- RED→GREEN 的目标用例及最终完整单测 **495/495、0 skipped**;真实 Hook 回归 **143/0/0**。Ruff、架构门禁、语言 schema **57 项/11 规则**、vendor 离线与在线、本 change strict、diff whitespace 均通过。受管技能及 lock 未改;这些是本地契约证据,不是三宿主安装、在线漏洞库、Windows 或第十九批发布证据。本批已准备 v0.14.5 元数据;远端发布须另行核对 PR、CI、tag、Release 与市场主线。

- 第十九批随后发布为 v0.14.5:源码 PR #51 合并为 `3f1266d8b57625e282989a51b20c528d578a01e1`,市场 PR #8 合并为 `a910cde2f6bfd5ebc6ca88d11fbb834687fb9084`;PR/main `skills-check` 成功,远端注释 tag 解引用到源码 main 合并提交,GitHub Release 为非 draft、非 prerelease,市场 Codex/ZCode/Kimi 及双语导航为 0.14.5。此证据不覆盖以下新工作树。

## 第二十批实际验证:裸前缀不遮蔽 Shell Git 副作用

- 将最新 v0.14.5 `main` 同步至已有临时 CodeGraph 索引(136 文件;源码仓未初始化索引),追踪 `git_syntax._analyze_segment`、`git_context._indirect_body`、`_guarded_mode`、`resolve_git_operations` 与 `staging_intent`。真实临时 Git 仓和纯函数探测先 RED:裸 `bash -c 'git commit'` 进入门禁,而 `FOO=1`、`env FOO=1`、`command`、`sudo` 前缀令同一 Shell 正文完全不命中;带敏感 `.env` 的暂存内容可被错误放行。
- 直接 Git 与解释器入口现共用 `git_syntax` 的裸前缀归一化;一层脚本仍由同一个调用目录与正文进入仓库归属和拟暂存分析。RED→GREEN 用例覆盖五类前缀、内层 add/index 不变、`cd` 后相对脚本、真实 PreToolUse 子进程;带值 wrapper 参数、动态命令及任意控制流仍不在静态保证范围内。
- `/opt/anaconda3/bin/python3` 3.13.5 完整执行 **498 unittest、0 skipped**;真实 Hook 回归 **143/0/0**。Ruff、架构门禁、语言 schema **57 项/11 规则**、vendor 离线与在线、本 change strict、diff whitespace 均通过。CodeGraph 的 `affected` 对本次核心文件返回空,但真实目标测试存在且已运行,故不把空图谱结果当无影响证明。受管技能和 lock 未改;本批尚未版本升级、提交或发布,三宿主现场/Windows/在线漏洞库仍未验收。
- 同步最新 CodeGraph 后继续追踪 `git_syntax` 发现:`inline_skip_gate` 和 `skip_gate_config_change` 仍用原始空白分词,与已共用的直接 Git/解释器前缀语义分叉。真实仓库 RED 证明已有持久 `skipGate=true` 时,`env FOO=1 git config codeguard.skipGate false && git commit` 被错误放行;带前缀的 `git -c` 单次豁免则被错误阻断且失去审计。二者现复用同一 `_segment_tokens`,目标测试转绿;此证据补充前述批内回归,不将早先 498 项计数当最终全量结果。
- 最终本地完整回归:`/opt/anaconda3/bin/python3` 3.13.5 执行 **500 unittest、0 skipped**,真实 Hook **143/0/0**;Ruff、架构门禁、语言 schema **57 项/11 规则**、vendor 离线与在线、本 change strict、diff whitespace 均通过。两项新 RED 场景及既有豁免/引号边界均转绿。本批已准备 v0.14.6 元数据;在 PR/CI/tag/Release/市场主线核对前,不能用 v0.14.5 的证据证明新改动已发布。
5 changes: 3 additions & 2 deletions scripts/codeguard/git_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
_git_c_path,
_git_side_effect_sub,
_segment_is_git_side_effect,
_strip_command_prefix,
inline_skip_gate,
skip_gate_config_change,
split_shell_segments,
Expand Down Expand Up @@ -188,7 +189,7 @@ def _fallback_roots(cwd: Path) -> list[Path]:
def _indirect_body(segment: str, invocation_dir: Path) -> tuple[str, bool] | None:
"""取得一段解释器实际收到的 -c 文本或脚本正文;不执行脚本。"""
try:
tokens = shlex.split(segment)
tokens = _strip_command_prefix(shlex.split(segment))
except ValueError:
return None
if not tokens:
Expand Down Expand Up @@ -260,7 +261,7 @@ def _guarded_mode(command: str, cwd: Path | None = None) -> str | None:
"""门禁命中时返回兜底门禁面:commit 或 push(同一仓两面并存时推送面
携带 pending_commit 可覆盖两面);未命中返回 None。

直接命令段先判定;未命中再走一层解释器间接(脚本/-c 内联)。
同时汇总直接命令段与一层解释器间接正文(脚本/-c 内联)。
is_guarded 即本函数的存在性判断——面判定与命中判定共用同一套扫描,
避免"命中了却选错面"的分叉。可直接解析的命令由 GitOperation 按仓
分别选择门禁面,不能把这里的整链模式传播到其它仓。
Expand Down
Loading
Loading