Skip to content

Commit ea6138b

Browse files
committed
merge: tmp-tp 测试可移植性与迁移债收口汇入 main
2 parents 31d475c + 03ebb24 commit ea6138b

16 files changed

Lines changed: 150 additions & 10 deletions

‎.github/workflows/skills-check.yml‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,22 @@ on:
88
jobs:
99
vendor-check:
1010
runs-on: ubuntu-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
python-version: ["3.11", "3.12", "3.13"]
15+
name: vendor-check (py${{ matrix.python-version }})
1116
steps:
1217
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
1318
with:
1419
fetch-depth: 0
1520
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
1621
with:
17-
python-version: "3.12"
22+
python-version: ${{ matrix.python-version }}
1823
- name: Install requirements (mcp SDK so MCP server tests run, not skip)
1924
run: python3 -m pip install --disable-pip-version-check -r requirements.txt
20-
- name: Install test checker (deterministic real-process fixtures)
21-
run: python3 -m pip install --disable-pip-version-check ruff==0.16.8
25+
- name: Install dev baseline (ruff as python checker + test precondition)
26+
run: python3 -m pip install --disable-pip-version-check -r requirements-dev.txt
2227
- name: Check executable code quality
2328
run: ruff check hooks scripts tests
2429
- name: Verify core dependency boundaries and import cycles

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ CLI exit priority: FAIL → 2; otherwise UNVERIFIED/PLANNED → 1; verified succ
3838

3939
## Java project awareness
4040

41+
The legacy import facades under `scripts/` (`verdict.py`, `user_config.py`, `run_per_language.py`) are Deprecated compatibility shims: new code must import from the `codeguard` package. They are scheduled for removal in the next major version.
42+
4143
### Read-only planning
4244

4345
```bash

‎README.zh-CN.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ CLI 优先级:FAIL → 2;否则有 UNVERIFIED/PLANNED → 1;验证成功
3838

3939
## Java 项目感知
4040

41+
`scripts/` 下的旧导入门面(`verdict.py`、`user_config.py`、`run_per_language.py`)为 Deprecated 兼容 shim:新代码必须从 `codeguard` 包导入,计划在下一个 major 版本移除。
42+
4143
### 只读规划
4244

4345
```bash

‎bin/codeguard‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ case "$cmd" in
4747
3. 从 linters/pre-commit/.pre-commit-config.template.yaml 拷贝并裁剪
4848
4. pip install pre-commit && pre-commit install
4949
或直接对 AI 说 /init,由 AI 按步骤完成。
50+
以上仅为引导清单,本命令不执行任何变更。
5051
EOF
51-
exit 1
52+
exit 0
5253
;;
5354
*)
5455
echo "codeguard: 未知子命令 '$cmd'" >&2

‎requirements-dev.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# 开发/测试可复现基线(CI 同源安装)。
2+
# ruff 同时是 python 适配器的真实检查器与若干回归用例的前置依赖
3+
#(用例在 ruff 缺失时 skipIf 跳过,判定基线钉在 CI 版本防漂移)。
4+
ruff==0.16.8

‎scripts/bump-plugin.mjs‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,23 @@ function resolvePluginsRoot() {
4949
}
5050
while (dir !== path.parse(dir).root) {
5151
if (fs.existsSync(path.join(dir, "plugins", "catalog.json"))) return path.join(dir, "plugins");
52+
const candidates = [];
5253
try {
5354
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
5455
if (entry.isDirectory() && /-plugins$/.test(entry.name)
5556
&& fs.existsSync(path.join(dir, entry.name, "catalog.json"))) {
56-
return path.join(dir, entry.name);
57+
candidates.push(path.join(dir, entry.name));
5758
}
5859
}
5960
} catch { /* 不可读目录跳过 */ }
61+
if (candidates.length === 1) return candidates[0];
62+
if (candidates.length > 1) {
63+
// 歧义目录(如工作区根同时含多个 *-plugins 市场仓)拒绝 first-match:
64+
// 静默选错市场会把版本写进错误的 catalog。
65+
throw new Error(
66+
`发现多个插件市场仓候选,拒绝猜测,请设 PARTME_PLUGINS_ROOT 指定:\n ${candidates.join("\n ")}`,
67+
);
68+
}
6069
dir = path.dirname(dir);
6170
}
6271
throw new Error("找不到插件市场仓。可设 PARTME_PLUGINS_ROOT 指定。");

‎scripts/check_architecture.py‎

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""静态架构门禁:内核依赖白名单与第一方 Python 导入环。
1+
"""静态架构门禁:内核依赖白名单、顶层脚本角色与第一方 Python 导入环。
22
33
只解析 AST,不导入被检查代码。函数内、条件分支中的静态 import 同样检查;
44
运行时拼接的动态加载不在静态保证范围内,本工具不是安全沙箱或 CodeGraph 替代。
@@ -11,6 +11,34 @@
1111
from pathlib import Path
1212

1313
# 明确的层依赖;stdlib 也受约束,纯模型不能悄悄导入 subprocess/宿主。
14+
# 顶层 scripts/*.py 的显式角色登记:新脚本必须归类,不许"就是多了一个脚本"。
15+
# entry=命令入口 / compat-shim=旧导入面兼容外观(docstring 必须含 Deprecated)/
16+
# adapter=物化适配层 / support=共享工具层。内核包 codeguard.* 走 CORE_DEPENDENCIES,
17+
# 本表只管包外顶层脚本;两者共同构成可检查的分层边界。
18+
SCRIPT_ROLES = {
19+
"check_architecture.py": "entry",
20+
"cve_check.py": "entry",
21+
"detect_lang.py": "entry",
22+
"dockerfile_security.py": "entry",
23+
"fix.py": "entry",
24+
"gen_language_docs.py": "entry",
25+
"java_project.py": "entry",
26+
"run_check.py": "entry",
27+
"validate_languages_json.py": "entry",
28+
"verdict.py": "compat-shim",
29+
"user_config.py": "compat-shim",
30+
"run_per_language.py": "compat-shim",
31+
"scope.py": "adapter",
32+
"git_snapshot.py": "adapter",
33+
"paths.py": "support",
34+
}
35+
36+
# 适配层白名单:包外实现模块的用途声明(谁在依赖它由 CORE_DEPENDENCIES 约束)。
37+
ADAPTER_LAYERS = {
38+
"scope.py": "linter 命令作用域物化 + git 改动集(delta 门禁共享层)",
39+
"git_snapshot.py": "只读 index/HEAD 物化一次性检查目录",
40+
}
41+
1442
CORE_DEPENDENCIES = {
1543
"codeguard.cve_policy": {"__future__", "dataclasses"},
1644
"codeguard.cve_reports": {"__future__", "json", "math", "codeguard.cve_policy"},
@@ -192,9 +220,42 @@ def check(root: Path) -> list[str]:
192220
graph[name].add(local)
193221
if allowed is not None and target not in allowed and target.split(".")[0] not in allowed:
194222
errors.append(f"{relative}:{line}: forbidden dependency: {name} -> {target}")
223+
errors.extend(_script_roles(root, modules))
195224
return errors + _cycles(graph)
196225

197226

227+
def _script_roles(root: Path, modules: dict) -> list[str]:
228+
"""顶层 scripts/*.py 必须显式归类;compat-shim 必须带 Deprecated 通告;
229+
adapter 必须在 ADAPTER_LAYERS 声明用途。"""
230+
errors: list[str] = []
231+
top_level = {
232+
path.name
233+
for path in (root / "scripts").glob("*.py")
234+
}
235+
for name in sorted(top_level - set(SCRIPT_ROLES)):
236+
errors.append(f"scripts/{name}:1: unclassified top-level script (add to SCRIPT_ROLES)")
237+
# 完备性校验只对真实插件仓布局生效:架构用例会在合成临时树上跑本检查,
238+
# 临时树不需要携带全部顶层脚本,不应误报 missing。
239+
is_full_repo = (root / "scripts" / "check_architecture.py").is_file()
240+
if is_full_repo:
241+
for name in sorted(set(SCRIPT_ROLES) - top_level):
242+
errors.append(f"scripts/{name}:1: declared in SCRIPT_ROLES but missing on disk")
243+
for name, role in sorted(SCRIPT_ROLES.items()):
244+
path = root / "scripts" / name
245+
if not path.is_file():
246+
continue
247+
if is_full_repo and role == "compat-shim":
248+
head = path.read_text(encoding="utf-8")[:400]
249+
if "Deprecated" not in head:
250+
errors.append(f"scripts/{name}:1: compat-shim must carry a Deprecated notice in its docstring")
251+
if role == "adapter" and is_full_repo and name not in ADAPTER_LAYERS:
252+
errors.append(f"scripts/{name}:1: adapter must declare its purpose in ADAPTER_LAYERS")
253+
if is_full_repo:
254+
for name in sorted(set(ADAPTER_LAYERS) - top_level):
255+
errors.append(f"scripts/{name}:1: declared in ADAPTER_LAYERS but missing on disk")
256+
return errors
257+
258+
198259
def main() -> int:
199260
parser = argparse.ArgumentParser(description=__doc__)
200261
parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parents[1])

‎scripts/run_per_language.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""旧脚本导入兼容入口;按语言检查的唯一实现位于 codeguard.language_check。"""
1+
"""旧脚本导入兼容入口;按语言检查的唯一实现位于 codeguard.language_check。
2+
3+
Deprecated:此模块是旧导入面的兼容外观,新代码必须从 `codeguard.language_check` 导入;
4+
计划在下一个 major 版本移除。
5+
"""
26
from __future__ import annotations
37

48
from codeguard.language_check import LANG_COMMANDS, _run, run_check, run_fix

‎scripts/user_config.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""用户配置旧导入面的兼容导出;实现仅在 codeguard.config。"""
1+
"""用户配置旧导入面的兼容导出;实现仅在 codeguard.config。
2+
3+
Deprecated:此模块是旧导入面的兼容外观,新代码必须从 `codeguard.config` 导入;
4+
计划在下一个 major 版本移除。
5+
"""
26
from codeguard.config import (
37
ConfigurationError,
48
get_overrides,

‎scripts/verdict.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""旧导入路径的兼容层;判定实现仅存在于 codeguard.verdict。"""
1+
"""旧导入路径的兼容层;判定实现仅存在于 codeguard.verdict。
2+
3+
Deprecated:此模块是旧导入面的兼容外观,新代码必须从 `codeguard.verdict` 导入;
4+
计划在下一个 major 版本移除。
5+
"""
26
from codeguard.verdict import (
37
FAIL,
48
PASS,

0 commit comments

Comments
 (0)