# 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 四项核查)、错误处理矩阵等完整设计。