# rpm_code_check
**Repository Path**: costinchen/rpm_code_check
## Basic Information
- **Project Name**: rpm_code_check
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-11
- **Last Updated**: 2026-09-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# rpm_code_check
RPM 软件包 PR 代码检查工具:对 PR 前后的 `rpmbuild -bp` 源码树快照做**代码安全 + 代码质量**检查,只回答「本次 PR 引入了什么风险」,产出 JSON + HTML 中文报告。
> 输入:PR 前后两个源码树(含 spec)|输出:`rpm_code_check.json` + `rpm_code_check.html`
## 特性
- **diff 增量扫描**:每条 finding 锚定变更行(含被编译开关「激活」的代码),未变更代码不扫描
- **规则 + AI 双引擎**:三层确定性规则(regex / semgrep / cppcheck + metrics)兜底召回;AI subagent(scanner)做语义发现,独立会话 verifier 逐条核查去偏
- **RPM 特有分析**:spec 条件编译/编译选项翻转 → 激活行分析;spec scriptlet 特权操作审计;纯升级 PR 自动跳过
- **成本受控**:单模型、四档规模预算(真实扫描数据标定)、LLM 对话硬上限、外部墙感知、批量装箱、工具白名单
- **诚实报告**:任何情况(成功 / 0 finding / 部分失败 / 失败)都产出 JSON + HTML,未核查项不进报告
- **无人值守**:全流程脚本化编排,容器内跑通,适配 CI 流水线
## 架构总览
六阶段流水线:
```mermaid
flowchart TD
S0["S0 预处理\ndiff · 激活行 · spec · 审计单元 · 包知识库"]
S0 -->|无变更 / 纯升级 PR| EMPTY["S5 空报告(带 reason)"]
S0 --> S1["S1 规则扫描\nregex · semgrep · cppcheck · metrics\n内置 spec/diff 规则"]
S1 -->|无代码可扫| EMPTY
S1 --> S2["S2 AI 发现\nscanner 并行批次\n追加式 unit 产出"]
S2 --> PF["候选前过滤 prefilter\nschema · 确定性误报 · 锚定 · 限量\n质量降采样"]
PF -->|纯确定性规则\nscanner 未覆盖| S4["S4 合并收敛\n去重 · 置信度公式\nseverity 基线 · PoC 封顶"]
PF -->|AI 候选 / 规则+AI 双源 / 质量| S3["S3 AI 核查\nverifier 独立会话(candidateId 回填)\n质量按文件聚类 ≤12 条/组"]
S3 --> S4
S4 --> S5["S5 报告\nJSON + 单文件 HTML"]
```
- **S0 预处理**:输入形态判定(`.git` 仓库 diff 模式 / `--full` 全量模式)、diff 解析、语言识别、spec 解析、编译选项→激活行分析、审计单元构建(函数边界扩展 + 批次打包)、包知识库检索(胶囊护照 + CVE 先验,版本漂移分级)
- **S1 规则扫描**:regex + semgrep + cppcheck + metrics(lizard)+ 内置 spec/diff 规则,产出归一化规则命中与线索摘要
- **S2 AI 发现**:scanner subagent 按批次审计变更单元(C 六问、失败路径、删除行审计、条件语义真值表、激活区审计),**追加式逐单元产出**(写一个单元文件即一份产出,超时防护天然成立)
- **S3 AI 核查**:安全类 AI 候选(含规则+AI 同时命中)经独立 verifier 核查(candidateId 稳定匹配),未完成核查的候选不进报告(记 `unverifiedCandidates` 供人工复核);质量项按文件聚类拆会话(≤12 条/组,总上限 30 条:按 severity/置信度降序截断,critical/high 豁免,中低危溢出不进报告);仅纯确定性规则直接进报告
- **S4 合并收敛**:去重、taxonomy 归一化、severity 基线收敛 + PoC 封顶、置信度公式确定性计算
- **S5 报告**:JSON + 单文件 HTML(内联 CSS/JS,双 Tab 安全/质量;过程类通知集中在诊断信息节)
### 规模分档与预算
| 档 | 判定 | 并发 | LLM 对话上限 | wall 预算 | 质量采样 |
|----|------|------|-------------|-----------|---------|
| tiny | ≤1 文件 且 ≤50 行 | ≤2 | 3 | 600s | full |
| small | ≤5 文件 且 ≤500 行 | ≤4 | 6 | 1200s | full |
| medium | ≤15 文件 且 ≤2000 行 | ≤6 | 10 | 1800s | high-value |
| large | 更大 | ≤8 | 16 | 2400s | high-value |
(档位预算由真实扫描数据标定;外部硬墙感知:`RPM_CODE_CHECK_WALL_LIMIT` 注入 CI 平台上限后取 min ×0.92,被硬杀前必收尾。)
### 置信度
`confidence = clamp(0, 100, L + E + C + V)`
置信度表示「这条是真阳性的把握」,不是危害大小。
| 项 | 含义 |
|----|------|
| L 基础分 | 仅 AI 且未核查:自评 × 0.8。规则+AI 双源或已 uphold:`max(自评, 引擎先验)`,不打折。纯规则用引擎默认值 |
| E 证据完备度 (0~+12) | 代码行一致 / diff 锚定通过 / 攻击链完整,均为脚本可核验事实 |
| C 多源印证 (0/+8) | 同一 finding 被 ≥2 个独立来源命中(如 rule + scanner) |
| V 核查修正 (-20/0/+15) | verifier uphold +15;未核查 0;核查未确证 -20 |
## 安装
```bash
# 基础依赖
pip install -e .
# AI 功能(可选)
pip install -e ".[ai]"
# 质量度量(可选)
pip install -e ".[metrics]"
```
依赖:Python ≥ 3.10;AI 模式需要 `codebuddy-agent-sdk` 与 `CODEBUDDY_API_KEY`。
## 用法
```bash
# 形态 A:含 .git 的仓库(标准 PR 检查,diff 模式)
rpm_code_check scan --input
--commit HEAD~1..HEAD
# 形态 B:单源码树全量扫描(兜底)
rpm_code_check scan --input --full
# 常用选项
rpm_code_check scan --input \
--model deepseek-v4-flash-ioa \ # LLM 模型 ID
--output ./rpm_code_check_out \ # 输出目录
--mode all \ # all | security | quality
--time-budget 30m \ # wall-clock 预算
--concurrency 6 # AI 会话并发上限
```
- 无 `.git` 的目录自动进入全量模式(无需 `--full`)
- 无变更 / 纯升级 PR / 无代码变更 → 输出空报告(带 `reason` 说明)
## 配置
默认使用项目根目录 `config.yaml`,命令行显式参数覆盖它。
```yaml
# config.yaml(示例即默认值)
model: "deepseek-v4-flash-ioa" # LLM 模型 ID
fallback_models: [] # 备用模型列表:主模型限流(429)/不可用时按序降级
time_budget: "30m" # wall-clock 预算
mode: "all" # all | security | quality
concurrency: 6 # AI 会话并发上限
output: "./rpm_code_check_out" # 输出目录
```
**参数优先级**:CLI 参数 > 环境变量(`RPM_CODE_CHECK_*`)> config 文件 > 代码默认值
| 环境变量 | 说明 |
|---------|------|
| `RPM_CODE_CHECK_CONFIG` | 指定 config 文件路径(默认项目根目录 config.yaml) |
| `RPM_CODE_CHECK_MODEL` | 覆盖 model |
| `RPM_CODE_CHECK_FALLBACK_MODELS` | 覆盖备用模型列表(逗号分隔,主模型限流时按序降级) |
| `RPM_CODE_CHECK_TIME_BUDGET` | 覆盖 time_budget(如 `25m`/`900s`) |
| `RPM_CODE_CHECK_MODE` | 覆盖 mode(all / security / quality) |
| `RPM_CODE_CHECK_CONCURRENCY` | 覆盖 concurrency |
| `RPM_CODE_CHECK_DISABLE_AI=1` | 强制纯规则模式(CI / 测试) |
| `RPM_CODE_CHECK_WALL_LIMIT` | 外部硬墙(秒,CI 平台任务上限);wall = min(档位默认, 该值×0.92),被硬杀前必收尾 |
| `RPM_CODE_CHECK_INTEL_ROOT` | 包知识库位置(pkg-intel.sqlite 合并库或老式 intel 目录) |
| `CODEBUDDY_API_KEY` | LLM 认证(AI 模式必需) |
| `CODEBUDDY_INTERNET_ENVIRONMENT` | LLM 网络环境(中国版填 `internal`/`ioa`) |
## 输出产物
工具本身写入 `{output}/{batchId}/`;CI 脚本会把报告提升到输出顶层:
```
{output}/
├── rpm_code_check.json # CI 顶层:完整 JSON 报告(findings 全量数据)
├── rpm_code_check.html # CI 顶层:单文件 HTML 报告(零外部依赖)
├── rpm_code_check_rpmbuild.log
├── rpm_code_check_no_change.marker # base/head 无差异时出现
└── artifacts/{batchId}/ # CI 归档的中间产物
├── rpm_code_check.json / .html
├── summary.json
├── merged-verified.json
├── scan-context.json
├── rule-findings.json
├── agents/ / hunks/
└── ...
```
本地直接调用 CLI 时,报告仍在 `{output}/{batchId}/`。
退出码:`0` = 扫描完成(无论 finding 数);`2` = 工具失败(报告仍产出)。
## Docker 部署与 CI 集成
镜像基于 `opencloudosstream/opencloudos-stream-minimal`,预置全部依赖(semgrep / cppcheck / lizard / rpm 工具链 / codebuddy-agent-sdk),**无 ENTRYPOINT**。
```bash
# 构建(依赖不变就极少重建)
docker build -t rpm_code_check .
# 日常运行(挂载最新代码 + 待扫描仓库)
docker run --rm \
-v $PWD:/opt/rpm_code_check:ro \
-v /path/repo:/in/repo:ro -v /path/out:/out \
-e CODEBUDDY_API_KEY=*** \
rpm_code_check python3 -m rpm_code_check.cli scan \
--input /in/repo --output /out --time-budget 25m
# 注意:镜像不含代码(无 COPY),必须挂载工具代码目录,否则 CLI 不可用
# (历史文档误称「内置 .dist 快照」,该层实际从未存在)
```
**CI 流水线**(`ci/check_code_by_rpm_code_check.sh`,由 ocs_ci_api `check_pr_code.py` 挂载执行):
1. 挂载 base/head 仓库(`/work/repo_{base,head}/$OCS_REPO`)与最新工具代码(`/opt/rpm_code_check`)
2. 两侧分别 `rpmbuild -bp --nodeps` 解出真实源码树(失败则 `dnf builddep` 后重试)
3. 二次判断两侧源码无差异 → 写 `rpm_code_check_no_change.marker` 并跳过
4. 构造 `/work/src` 双 commit git 仓库 → 跑 `rpm_code_check scan --commit base..head`(不传 `--model`,走 `config.yaml`)
5. 产物收集:从 `{batchId}/` 提升 `rpm_code_check.{json,html}` 到顶层,整批中间产物归档到 `artifacts/{batchId}/`
CI 环境变量:`OCS_REPO`(包名)、`CODEBUDDY_API_KEY`、`CODEBUDDY_INTERNET_ENVIRONMENT`、`RPM_CODE_CHECK_OUT`(缺省 `/work/output`)、`HOST_UID`/`HOST_GID`(产物 chown 回宿主)。脚本会为挂载代码设置 `PYTHONPATH` / `RPM_CODE_CHECK_CONFIG`。
更新流程:改代码/规则 → push 工具仓库 → 流水线下一次 clone 即生效,无需重建镜像。
## 项目结构
```
rpm_code_check/
├── config.yaml # 默认配置(项目根目录)
├── Dockerfile
├── ci/check_code_by_rpm_code_check.sh # 容器内 CI 驱动脚本
├── rpm_code_check/
│ ├── cli.py # 命令行入口(参数解析/优先级)
│ ├── orchestrator.py # 六阶段编排 + 条件跳过 + 失败兜底出报告
│ ├── sdk_client.py # CodeBuddy SDK 封装(工具白名单/预算/认证)
│ ├── budget.py # 规模分档 / wall-clock 预算 / 截断
│ ├── agents/
│ │ ├── definitions.py # scanner / verifier AgentDefinition
│ │ └── prompts/{scanner,verifier}.md
│ ├── intelligence/ # 包知识库(扫描侧只读)
│ │ ├── paths.py # 定位:环境变量/参数 → 仓内合并库
│ │ ├── store.py # 统一查询(合并库/老式胶囊双后端)
│ │ └── cli.py # rpm-intel query(--cve/--query)
│ └── core/
│ ├── input_resolver.py # 输入形态判定(diff / full)
│ ├── diff_engine.py # diff / changedLines / 文件分类
│ ├── lang_detect.py # 语言识别
│ ├── archetype.py # 攻击面原型 / auditDepth / fast_lane 守卫
│ ├── pkg_profile.py # 包档案注册加载与覆盖
│ ├── spec_analyzer.py # spec 解析 / 纯升级 PR 判定
│ ├── activation.py # 编译选项→宏翻转→激活行
│ ├── hunk_builder.py # 函数边界扩展审计单元 + 批次打包
│ ├── knowledge_brief.py # 判定知识确定性内联(按批次上下文选片段)
│ ├── retriever.py # 包知识库检索(版本漂移分级/CVE 先验)
│ ├── clue_digest.py # 规则命中 → 线索摘要(prompt 注入)
│ ├── rule_engine.py # regex / semgrep / cppcheck / metrics 引擎
│ ├── builtin_spec_rules.py
│ ├── builtin_diff_rules.py# 条件反转等 diff 配对检测
│ ├── normalize.py # 规则命中归一化
│ ├── prefilter.py # 候选前过滤(schema/确定性误报/锚定/限量/降采样)
│ ├── merge_findings.py # 合并收敛 / 置信度公式 / severity 基线收敛
│ ├── taxonomy.py # 风险类型分类表
│ └── report.py # JSON / HTML 报告
├── resource/ # 规则与知识库(YAML 热加载)
│ ├── risk-taxonomy.yaml # 风险类型分类(安全+质量)
│ ├── attack-surface-archetypes.yaml
│ ├── macro-conventions.yaml # 编译选项→宏映射约定
│ ├── lang-map.yaml
│ ├── rules/{security,quality,packaging}/*.yaml
│ ├── semgrep/
│ ├── knowledge/ # C 内存安全 / rpm-spec / 各语言知识
│ ├── intel/pkg-intel.sqlite # 包知识库合并库(随仓分发,2.3MB)
│ └── pkg-profiles/ # 可选包档案(按需追加)
└── tests/
```
## 检查范围与边界
| 检查 | 不检查 |
|------|--------|
| PR 引入的代码安全风险(内存安全、注入、条件反转、特权 scriptlet…) | 上游代码自身已知漏洞(CVE 平台负责) |
| PR 引入的代码质量问题(复杂度、长函数、复制粘贴…) | spec 语法与构建可用性(构建流水线负责) |
| 被编译开关「激活」的既有代码 | 纯升级 PR(无源码补丁变化) |
| spec 的 scriptlet / 加固选项变化 | `.patch`/`.diff` 文件本身(已由 %prep 应用进源码树) |
## 设计文档
详见 [DESIGN.md](DESIGN.md):统一数据契约(finding schema)、置信度机制、激活行分析、AI 纪律(scanner 六问/verifier 四项核查)、错误处理矩阵等完整设计。