ugiordan/code-claim-verifier

GitHub: ugiordan/code-claim-verifier

CodeClaimVerifier 通过确定性的代码检查手段(grep、文件读取、lockfile 解析)对 LLM 关于源代码的事实性声明进行自动化验证,以识别和拦截 LLM 幻觉,提升代码安全分类结果的可信度。

Stars: 0 | Forks: 0

# CodeClaimVerifier 对 LLM 关于源代码的声明进行确定性验证。验证过程无需任何 LLM 调用。 ## 问题所在 LLM 在推理代码时会做出事实性断言:“函数 X 没有调用者”、“包版本是 2.4.1”、“此文件是自动生成的”。这些断言驱动着真实的决策:分类裁定、审查批准、迁移计划。但 LLM 会产生幻觉,却没有人去检查它们关于代码的声明是否真的属实。 **如果没有 CCV**,LLM 可能会通过产生“无调用者”的幻觉,来忽略一个在被调用了三处的函数上真实存在的漏洞。或者它可能会声称使用了一个危险的函数(而实际上并没有),从而将一个非问题升级为风险。这两者都会浪费时间并带来风险。 **有了 CCV**,LLM 所做的每一个关于代码的事实性声明都会被提取、分类,并使用 grep、文件读取和 lockfile 解析与实际的代码库进行核对验证。grep 不会产生幻觉。 ## 实际作用 ``` LLM says: "torch.load() at model.py:42 has no callers. The vulnerability is dead code." CCV extracts 3 claims: FILE_EXISTS(path=model.py) -> VERIFIED (file exists) FUNCTION_CALLED(name=torch.load) -> VERIFIED (call sites found) HAS_CALLERS(name=torch.load, false) -> REFUTED (grep found 2 callers) Result: 67% verified, action=FLAG "The LLM claimed torch.load has no callers, but grep found 2 call sites. Re-triage this finding." ``` LLM 在关于调用者的判断上错了。如果没有 CCV,这个漏洞就会被当作死代码而忽略。有了 CCV,它就会被标记出来以供人工审查。 ## 应用场景 ### 捕捉漏报(遗漏的漏洞) 一个正在对 CVE 进行分类的 LLM 说:“有漏洞的函数 `yaml.load()` 没有在代码库的任何地方被导入。这个 CVE 不影响我们。” CCV 提取出 `IMPORT_EXISTS(module=yaml)`,对仓库进行 grep 搜索,在 `config/parser.py` 中找到了 `import yaml`。LLM 关于“未被导入”的声明被驳回(REFUTED)。CVE 保持打开状态,而不是被错误地关闭。 ### 捕捉误报(错误警报) 一个正在审查代码的 LLM 说:“函数 `process_input()` 在被调用时没有进行过滤清理。这是一个注入漏洞。” CCV 提取出 `FUNCTION_CALLED(name=process_input, expected=true)`。Grep 发现调用点为零(该函数在上个冲刺中已被移除)。LLM 的声明被驳回(REFUTED)。安全团队就不会浪费时间去调查一个不存在的调用路径。 ### 校准置信度 一个 LLM 生成了包含 5 个事实性声明的分类报告。CCV 验证了其中 4 个(80% 的验证率)。操作:提升(BOOST)。该分类结果是可靠的。 另一个 LLM 的分类报告有 3 个声明,1 个被验证,2 个被驳回(33% 的验证率)。操作:覆盖(OVERRIDE)。该 LLM 正在产生幻觉。不要相信这个分类结果,重新运行或升级给人工处理。 | 验证率 | 操作 | 含义 | |---|---|---| | 80-100% | 提升 (BOOST) | 声明经核实无误。信任 LLM 的结论。 | | 50-79% | 标记 (FLAG) | 部分声明核实失败。应由人工审查。 | | <50% | 覆盖 (OVERRIDE) | 大部分声明有误。不要相信此输出。 | ## 工作原理 ``` LLM Reasoning (text) | v [1. Extract Claims] -- 1 LLM call, structured output | "torch.load has no callers" -> HAS_CALLERS(name=torch.load, expected=false) v [2. Build Dependencies] -- 0 LLM calls | HAS_CALLERS depends on FUNCTION_EXISTS | synthesize missing prerequisites v [3. Verify Each Claim] -- 0 LLM calls | grep, os.path.exists, lockfile parse | language-aware patterns (Python, Go, TS, Java, C, Rust) v [4. Propagate Failures] -- 0 LLM calls | if FILE_EXISTS is REFUTED, flag all dependent claims as SUSPECT v [5. Calibrate] -- 0 LLM calls | weighted verification rate -> action (BOOST/FLAG/OVERRIDE) v VerificationReport ``` 提取过程仅需一次 LLM 调用。验证过程无需任何 LLM 调用。验证步骤使用的工具与开发人员检查时使用的相同:此文件存在吗?此函数是否已定义?此包是否处于此版本? ## 快速开始 ``` from code_claim_verifier import CodeClaimVerifier verifier = CodeClaimVerifier( llm_function=my_llm_call, # (system_prompt, user_prompt) -> str repo_path="/path/to/repo", ) report = verifier.verify( reasoning="torch.load() at model.py:42 has no callers in the codebase...", evidence={"call_chain": [], "mitigations_found": ["sanitizer at util.py:15"]}, finding_file="model.py", ) print(report.verification_rate) # 0.67 print(report.action) # "FLAG" print(report.hallucination_rate) # 0.33 # 检查单个 claim for claim in report.per_claim: print(f" {claim.claim.claim_type}: {claim.verdict} ({claim.evidence[:80]})") ``` ## 17 种声明类型 | 类别 | 类型 | 验证方式 | |---|---|---| | **文件/路径** | FILE_EXISTS, LINE_CONTENT, FILE_CLASSIFICATION, GENERATED_OR_VENDORED | `os.path.isfile()`、文件读取、路径正则匹配、头部标记 | | **函数** | FUNCTION_EXISTS, FUNCTION_CALLED, HAS_CALLERS | 针对定义和调用点进行具有语言感知能力的 grep 搜索 | | **依赖项** | IMPORT_EXISTS, PACKAGE_VERSION, DEPENDENCY_TYPE, CVE_AFFECTS_VERSION | 导入 grep、lockfile 解析、使用 [OSV API](https://osv.dev/) 进行 CVE 检查 | | **代码** | ABSENCE, MITIGATION_EXISTS, ENTRY_POINT | 限定范围的 grep(取反)、文件读取、框架模式 grep | | **Auth Chain** | CALL_CHAIN, DEFAULT_VALUE, CONFIG_FLAG | 多跳调用路径 grep、默认值/nil 检查、配置标志 grep | 每种类型都有记录在案的置信度水平(对于缺失声明为 0.60,对于文件存在为 0.99),反映了验证方法的精确度。 ## 声明链 LLM 的声明具有隐含的依赖关系。如果文件不存在,“第 42 行包含 `torch.load()`”就毫无意义。 CCV 会自动推断这些依赖关系: - LINE_CONTENT 依赖于 FILE_EXISTS(同一路径) - FUNCTION_CALLED 依赖于 FUNCTION_EXISTS(同一名称) - CALL_CHAIN 依赖于 FUNCTION_EXISTS(链中的每个函数) - IMPORT_EXISTS 依赖于 FILE_EXISTS(同一文件) 如果文件不存在,所有关于其内容的声明都会被标记为可疑(SUSPECT),并降低置信度。如果函数不存在,关于它被调用的声明就会被标记。 这可以捕捉连锁幻觉:LLM 虚构了一个文件,然后对其内容做出详细的声明。CCV 会驳回文件存在的声明,并标记其下游的所有内容。 ## CPG 集成 为了在函数声明上获得更高的准确性,CCV 可以使用来自 [architecture-analyzer](https://github.com/ugiordan/architecture-analyzer) 的代码属性图(CPG)。这将用精确的 AST 级别查询来取代 grep,适用于: - **FUNCTION_EXISTS**:精确节点查找,取代正则匹配 - **FUNCTION_CALLED / HAS_CALLERS**:调用边遍历,取代 grep 启发式方法 - **CALL_CHAIN**:通过实际调用图进行多跳路径查询 - **ENTRY_POINT**:来自 CPG 的 HTTP endpoint 节点 首先,在你的代码库上运行 architecture-analyzer 以生成 CPG: ``` arch-analyzer scan --repo /path/to/repo --output /path/to/output/ ``` 然后将其加载到 CCV 中: ``` verifier = CodeClaimVerifier(llm_function=my_llm, repo_path="/path/to/repo") verifier.load_cpg("/path/to/output/code-graph.json") # CPG 自动加载。Function claim 使用 AST 查询。 ``` ## 批量验证 通过共享缓存和自适应批处理验证多项发现: ``` reports = verifier.verify_batch( items=[ {"reasoning": "...", "evidence": {}, "finding_file": "model.py"}, {"reasoning": "...", "evidence": {}, "finding_file": "util.go"}, ], domain_context="security triage", ) ``` 多项批处理共享一个 grep 缓存(相同的模式只需搜索一次),并使用较少的 LLM 调用进行提取。依赖图是针对每个发现的(不会发生交叉污染)。 ## 自定义声明类型 为 CCV 开箱即用未覆盖的声明注册特定领域的验证器: ``` from code_claim_verifier.types import TypedClaim, VerifiedClaim def verify_has_decorator(claim: TypedClaim, repo_path: str, language: str) -> VerifiedClaim: from code_claim_verifier.grep import grep pattern = f"@{claim.parameters['decorator']}\\s*\\ndef\\s+{claim.parameters['function']}" matches = grep(pattern, repo_path) return VerifiedClaim( claim=claim, verdict="VERIFIED" if matches else "REFUTED", method_confidence=0.85, evidence=matches[0][:200] if matches else "no match", method="grep_decorator", ) verifier.register( claim_type="HAS_DECORATOR", verifier_fn=verify_has_decorator, extraction_hint="HAS_DECORATOR: {function: str, decorator: str} - checks if a function has a specific decorator", depends_on=[("FILE_EXISTS", "file", "path")], ) ``` 自定义类型可获得与内置类型相同的缓存、链接和校准功能。 ## CLI ``` # 验证单个 finding python -m code_claim_verifier verify \ --repo /path/to/repo \ --reasoning "torch.load() is called at model.py:42" \ --llm-provider anthropic # 从 JSON 进行批量验证 python -m code_claim_verifier verify-batch \ --repo /path/to/repo \ --input findings.json # 列出所有 claim 类型及其参数 schema python -m code_claim_verifier list-types # 针对 fixture repo 运行评估 python -m code_claim_verifier eval \ --dataset eval/dataset.jsonl \ --fixtures eval/fixtures/ ``` ## 用于 Agent 集成的 Tool Schema 将 CCV 作为工具暴露给任何 LLM Agent 框架: ``` tools = verifier.as_tools() # includes custom types tools = CodeClaimVerifier.default_tools() # built-in types only ``` 以标准的工具使用格式返回 `extract_claims`、`verify_claim`、`verify_all`、`list_claim_types`。 ## 评估框架 内置评估功能,用于衡量验证质量: ``` python -m code_claim_verifier eval \ --dataset eval/dataset.jsonl \ --fixtures eval/fixtures/ \ --output report.json ``` 三个阶段: 1. **提取质量**:声明提取相对于真实情况的精确率/召回率 2. **验证准确性**:按声明类型划分的正确判定、混淆矩阵、错误驳回/验证率 3. **校准分析**:基于类型的预测置信度与实际准确率对比、ECE 得分 ## 安装 ``` pip install code-claim-verifier ``` 安装用于 CLI 的 LLM provider: ``` pip install code-claim-verifier[anthropic] pip install code-claim-verifier[openai] ``` 从源码安装: ``` git clone https://github.com/ugiordan/code-claim-verifier cd code-claim-verifier pip install -e ".[test]" ``` ## 核心设计原则 - **验证过程无需任何 LLM 调用。** grep 不会产生幻觉。`os.path.exists()` 不会产生幻觉。 - **语言感知。** 支持 Python、Go、TypeScript、Java、C/C++、Rust 的函数/导入模式。 - **将缺失(Absence)视为一等公民。** “不存在调用者”是安全分类中最重要的声明,而 CCV 会对其进行验证。 - **声明链。** 通过依赖传播捕捉连锁幻觉。 - **线程安全。** 基于 contextvars 的缓存,可安全用于 Agent 框架中的并发使用。 - **零依赖。** 核心库仅使用标准库。CLI 为可选的 provider。 - **领域无关。** 安全分类、代码审查、重构、迁移、文档记录、架构评估。 ## 文档 完整文档:[ugiordan.github.io/code-claim-verifier](https://ugiordan.github.io/code-claim-verifier/) - [快速入门](https://ugiordan.github.io/code-claim-verifier/getting-started/installation/) - [17 种声明类型](https://ugiordan.github.io/code-claim-verifier/guides/claim-types/) - [API 参考](https://ugiordan.github.io/code-claim-verifier/reference/api/) - [架构](https://ugiordan.github.io/code-claim-verifier/architecture/overview/) ## 背景 受 [Claimify](https://arxiv.org/abs/2502.10855) (ACL 2025) 启发,通过确定性验证将其扩展到代码领域: - Claimify 仅支持提取。CCV 添加了确定性验证。 - Claimify 会过滤掉缺失声明。CCV 将其视为一等公民。 - Claimify 针对文本进行验证。CCV 针对源代码进行验证。 - Claimify 使用 LLM 作为评判标准。CCV 在验证时无需任何 LLM 调用。 ## 许可证 Apache 2.0 ## 版权 版权所有 (c) Red Hat, Inc.
标签:DLL 劫持, 事实核查, 代码审查, 大语言模型, 安全分诊, 自动化验证, 逆向工具, 错误基检测, 静态代码分析