sergiparpal/semantic-diff-weaver
GitHub: sergiparpal/semantic-diff-weaver
一个只读的 Python 语义 diff 静态分析工具,通过 AST 比较推断代码变更的行为影响并生成风险评级和测试义务,支持 CLI、GitHub Action 和 Hermes 插件三种运行方式。
Stars: 0 | Forks: 0
# Semantic Diff Weaver
Semantic Diff Weaver 是一个建议性、只读的审查工具,用于分析两个已提交版本之间有限的 Git diff。它静态提取 Python 结构性变更,推断有证据支持的行为变更,将风险与置信度分开评级,并产出具体的测试义务以及未经验证的候选现有测试。您可以从命令行、在 pull request 上作为 GitHub Action 运行它,或作为 Hermes Agent 插件运行。
它绝不导入、执行、构建、安装、测试或修改被分析的仓库。它不运行您的测试或自行测量覆盖率——它可以*获取*您自己的 CI 已经生成的覆盖率报告,并报告该报告针对已更改行的说明。仓库内容被视为不受信任的数据,当没有可用的模型时,分析会降级为确定性的结构性发现。
## 要求
- Python 3.11 或更高版本。
- `PATH` 中可用的 Git。
- Pydantic 2 和 PyYAML 6(随包安装)。
- 仅 0.14.0 或更高版本的 Hermes Agent 用于插件路径。该包故意不在元数据中强制安装 Hermes 或限制其版本。
## 独立 CLI
```
pipx run --spec . semantic-diff-weaver --repo . --base main --head HEAD
```
如果安装到当前环境中,同样的运行为:
```
python -m pip install . && semantic-diff-weaver --repo . --base main --head HEAD
```
`python -m semantic_diff_weaver` 与控制台脚本等效。
| 标志 | 含义 |
| --- | --- |
| `--repo PATH` | 要分析的仓库;默认为 `.` |
| `--base REF` | 基础版本;**必填** |
| `--head REF` | 目标版本;默认为 `HEAD` |
| `--include GLOB` | 可重复的包含模式 |
| `--exclude GLOB` | 可重复的排除模式 |
| `--risk-profile PATH` | 额外的有限 YAML 配置文件 |
| `--coverage PATH` | 作为覆盖率基准的 coverage.py JSON 或 lcov `.info` 报告 |
| `--model ID` | 推理模型;覆盖 `SEMANTIC_DIFF_WEAVER_MODEL` |
| `--no-llm` | 跳过推理;仅输出确定性结构性发现 |
| `--format {json,markdown,both}` | 默认为 `markdown` |
| `--allow-root PATH` | 可重复的额外授权根目录 |
| `--fail-on {none,low,medium,high,critical}` | 默认为 `none` |
`markdown` 打印适用于 PR 的简报,`json` 打印标准的 schema 版本化分析,`both` 打印包含分析和简报的信封。退出代码为:
| 代码 | 含义 |
| --- | --- |
| `0` | 成功,且总体风险低于 `--fail-on` |
| `1` | 分析错误;稳定的错误代码、消息和补救措施会输出到 stderr |
| `2` | 参数错误 |
| `3` | 成功,但总体风险达到 `--fail-on` |
退出代码 `3` 仍然会打印完整的报告——阈值是一个信号,而不是扣留分析结果的理由。
**在没有模型提供商的情况下,CLI 以确定性模式运行。** 它报告结构性发现、其分类法类别、风险和义务,全部仅源自 AST 比较。它没有添加的是推理层:发现被标记为 `deterministic_fallback` 而不是 `llm_supported`,描述是从内置的按类别模板中提取的,而不是针对特定 diff 编写的,并且除了确定性规则产生的问题外,不会提出任何审查问题。请参阅 [提供商部分](#model-provider) 以启用推理。
### 基准覆盖率
将该工具指向您的 CI 已经生成的覆盖率报告,它将报告测试套件实际执行了哪些已更改的行:
```
semantic-diff-weaver --repo . --base main --coverage coverage.json
```
接受 coverage.py JSON 和 lcov `.info` 格式,并根据内容进行识别。如果已更改的文件不在报告中,则会报告为**未知,从未发现未覆盖**,因此路径前缀不匹配会显示为警告,而不是虚假的覆盖率缺口。请参阅 [配置](docs/configuration.md#coverage-grounding)。
### 模型提供商
推理是可选的,且从不是必需的。安装扩展并导出密钥以启用它:
```
python -m pip install '.[anthropic]' && export ANTHROPIC_API_KEY=...
```
然后,CLI 将基于证据的推理层添加到确定性发现中。模型默认为 `claude-opus-5`,可以使用 `--model ID` 或 `SEMANTIC_DIFF_WEAVER_MODEL` 覆盖。
`--no-llm` 完全跳过提供商解析。
适配器将每个请求塑造为指定模型系列接受的形式——对于移除了采样参数的系列,会丢弃这些参数;对于思考始终开启而不是作为禁用发送的系列,会完全省略 `thinking` 参数。如果某个系列拒绝某个参数,会导致*所有*调用失败,然后运行会降级为确定性发现,仅显示一个通用的批次警告。因此,在 CI 中设置覆盖之前,请针对 `semantic_diff_weaver/providers/anthropic_client.py` 中的前缀列表进行检查;其原因详见 [docs/decisions.md](docs/decisions.md)。
当缺少包或密钥时,CLI 会向 stderr 打印一行通知,并以确定性模式继续——**缺少凭据绝不是硬性失败**,提供商报错、超时或返回 schema 拒绝的输出也同样不是。所有这些情况都会降级为相同的确定性结构发现,这是 Hermes 路径已经具备的行为。
密钥仅从环境中读取。它从不被记录,从不包含在错误路径中,也从不写入输出;`tests/security/test_provider_secrets.py` 断言,即使提供商将其嵌入到异常消息中,它也无法到达渲染的简报或 `WeaverError` 负载中。
### CLI 授权
调用者选择的本地路径独立于仓库包含关系进行授权,并且 CLI 解析该授权的方式与插件**故意**不同。在 Hermes 下,*模型*选择 `repo_path`,因此默认的授权根目录是进程工作目录,仅此而已。在命令行上,由*人*输入路径,这就是授权。
因此,当 `SEMANTIC_DIFF_WEAVER_ALLOWED_ROOTS` **未设置**时,CLI 会为分析将其设置为解析后的 `--repo` 以及任何 `--allow-root` 值,然后恢复环境。当操作员**已经设置**了该变量时,CLI 从不扩大它:`--allow-root` 会被拒绝并返回退出代码 `2`,而操作员边界之外的 `--repo` 会像在 Hermes 下一样失败。无论是哪个路径,文件系统根目录都不会被接受为授权根目录。
外部的 `--risk-profile` 必须解析到授权根目录之下,因此当它位于仓库之外时,请使用 `--allow-root` 传递其目录。
## GitHub Action
将简报作为单个 pull-request 评论发布。该 Action 封装了 CLI,本身不包含任何分析逻辑。
```
name: pr-review
on: [pull_request]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0 # required: the analyzer reads committed objects and never fetches
- uses: your-org/semantic-diff-weaver@v0
with:
fail-on: none
```
重新运行会**编辑**现有评论,而不是追加新评论,这是通过隐藏的标记进行匹配的。第三方 Action 被固定到完整的 commit SHA,因为移动的标签是可变的,且此作业持有 `pull-requests: write`。输入、fork 的 pull-request 注意事项以及如何传递先前作业的覆盖率报告详见 [docs/github-action.md](docs/github-action.md)。
## 安装并启用 Hermes 插件
作为用户目录插件进行开发时,请将此仓库目录复制到:
```
~/.hermes/plugins/semantic-diff-weaver/
```
对于项目插件,请将其复制到 `.hermes/plugins/semantic-diff-weaver/` 并显式信任项目插件发现:
```
HERMES_ENABLE_PROJECT_PLUGINS=true
```
对于包安装:
```
python -m pip install .
hermes plugins enable semantic-diff-weaver
hermes plugins list
```
插件是可选的。如果发现或注册失败,请设置 `HERMES_PLUGINS_DEBUG=1` 并检查 Hermes 插件日志。该包公开了 `hermes_agent.plugins` 入口点,并且该目录同时包含 `plugin.yaml` 和根 `__init__.py`。
## 工具输入
Hermes 仅注册一个工具 `analyze_semantic_diff`:
```
{
"repo_path": "/path/to/local/repository",
"base_ref": "main",
"head_ref": "HEAD",
"include": ["src/**/*.py"],
"exclude": ["**/generated/**"],
"output_format": "both"
}
```
`repo_path` 和 `base_ref` 是必需的。`head_ref` 默认为 `HEAD`;`output_format` 可以为 `json`、`markdown` 或 `both`。可选的 `risk_profile` 可以显式指定一个有限的 YAML 文件,可选的 `coverage_report` 可以指定一个 coverage.py JSON 或 lcov `.info` 报告作为覆盖率基准。未知参数将被拒绝。
调用者选择的本地路径独立于仓库包含关系进行授权。默认情况下,该工具只能访问 Hermes 进程工作目录下的路径。受信任的主机操作员可以使用由平台路径分隔符分隔的 `SEMANTIC_DIFF_WEAVER_ALLOWED_ROOTS` 环境变量来授权额外的有限根目录。例如,在 Linux/macOS 上:
```
SEMANTIC_DIFF_WEAVER_ALLOWED_ROOTS=/work/project:/work/shared-profiles
```
`repo_path`、外部的 `risk_profile` 和外部的 `coverage_report` 都必须解析到这些根目录之一下。文件系统根目录永远不会被接受为授权根目录。
处理程序始终返回 JSON 编码的字符串。JSON 模式返回标准的 schema 版本化分析。Markdown 模式返回包含适用于 PR 的简报的 JSON 信封。Both 模式返回标准的分析和匹配的 Markdown。
## 配置
所有配置都是可选的。优先级依次为工具参数、显式风险配置文件、`.hermes/semantic-diff-weaver.yaml`、`.semantic-diff-weaver.yaml` 以及内置的保守默认值。有关完整的 schema 和限制,请参阅 [配置](docs/configuration.md)。
最小示例:
```
version: 1
paths:
include: ["src/**/*.py"]
test_roots: ["tests"]
critical_paths:
- pattern: "src/auth/**"
weight: 90
rules:
minimum_report_confidence: 0.45
deterministic_fallback: true
```
强制性的密钥和控制目录排除无法禁用。配置无法启用网络访问、代码执行或仓库边界之外的路径。
## 开发门控
```
python -m pytest
python -m pytest tests/unit tests/contract
python -m pytest tests/integration
python -m pytest tests/security
python -m pytest tests/evaluation
python -m pytest tests/performance
python -m pytest --cov=semantic_diff_weaver --cov-branch --cov-report=json:coverage.json
python scripts/check_coverage.py coverage.json
python -m ruff check .
python -m ruff format --check .
python -m mypy
python -m build
python scripts/verify_wheel.py dist
python scripts/verify_hermes.py # with Hermes >=0.14.0 and the wheel installed
```
测试使用临时 Git 仓库和伪造的 Hermes 上下文/模型。它们不会更改真实的 Hermes 主目录,也不需要付费或实时的 LLM。
## 限制
- 仅支持 Python 源代码和常见的 pytest/unittest 布局。
- 仅支持已提交的基础/目标内容;暂存和工作树更改不在 MVP 范围内。
- 静态候选测试不是已验证的覆盖率:它们是名称和导入匹配,绝不是测试断言了已更改行为的声明。即使提供了覆盖率报告,这一点也成立——获取的报告说明测试套件执行了已更改的*行*,这是一个不同且较弱的声明。
- 该工具获取覆盖率报告而从不生成报告;报告中缺失的已更改文件会被报告为未知,而不会报告为未覆盖。
- 动态元编程和外部契约可能会产生审查问题或未知的语义更改。
- 没有网络引用查找、测试执行或测试生成。GitHub Action 通过 `gh` CLI 使用工作流自身的 token 发布评论;分析器本身不发出任何网络请求,也不读取任何 pull-request API。
- 多语言支持不在范围内:`ast_diff/` 是基于 Python 自己的 `ast` 构建的。
## 许可证
根据 [MIT License](LICENSE) 授权。
标签:Git差异分析, SOC Prime, 代码审查, 开发工具, 恶意代码分类, 网络安全研究, 逆向工具, 错误基检测, 静态代码分析, 风险量化评估