跳到主要内容

03 · CodeShield 静态分析引擎内部

本章深入 CodeShield 的核心 insecure_code_detector.analyze——LlamaFirewall 的 CodeShieldScanner 只是它的薄壳。代码在 CodeShield/insecure_code_detector/insecure_code_detector.py(与 LlamaFirewall 同仓,PyPI 上是独立包 codeshield)。

1. 为什么要两级引擎

静态分析有个经典权衡:

手段优点缺点
正则(regex)极快、无外部进程只能匹配文本模式,易漏易误
semgrep(语法感知)懂代码结构、更准要起子进程、慢

CodeShield 的策略:先用 regex 快扫;对 CODESHIELD 这个「实时」用例,一旦 regex 命中就立即返回, 根本不跑 semgrep(省延迟);只有在 regex 没命中、但「预扫」提示这段代码值得深看时,才动用 semgrep。

每种语言配哪些分析器,见 LANGUAGE_ANALYZER_MAP(insecure_code_detector.py:36):C/C++/C#/Java/JS/ Kotlin/Python 同时挂 REGEX+SEMGREP;PHP/Ruby/Rust/Swift/Objective-C/Hack/XML 只有 REGEX。

2. 主流程 analyze

怎么读这张图:从上往下是一次 analyze 调用;菱形是 CODESHIELD 用例特有的两处「早退」。

analyze(language, generated_code, usecase=CODESHIELD)

├─▶ ① regex 分析(_regex_analyze)
│ │
│ ▼
│ CODESHIELD 且已有命中? ──是──▶ 立即返回这些 issue(不跑 semgrep)
│ │否
│ ▼
├─▶ ② 该语言支持 semgrep?
│ │是
│ ▼
│ CODESHIELD 且「预扫正则」没提示值得深看? ──是──▶ 直接返回(跳过 semgrep)
│ │否
│ ▼
│ ③ 跑 semgrep 子进程(_semgrep_analyze)
│ ▼
└─▶ 汇总 regex + semgrep 的 issue,清理临时文件,返回

对应源码 insecure_code_detector.py:84-155。两处早退分别在 :126(regex 命中即返回)和 :135 (预扫不推荐则不跑 semgrep)。注释里直接写着 fast mode is greedy(:127)。

3. regex 分析的两个细节

并行跑所有规则

_run_regex(insecure_code_detector.py:195)用 ThreadPoolExecutor 把每条 InsecurePattern 并行 re.search,再把命中拍平成 Issue 列表。规则库按「语言 + 用例」从 YAML 加载 (rules/regex/*.yaml,如 python.yamllanguage_agnostic.yaml)。

跳过注释里的匹配(降误报)

_search_pattern(insecure_code_detector.py:169)命中后,会看命中行是不是注释/预处理指令 (以 # // /* 开头或 */ 结尾),是的话丢弃(_is_comment_or_directive,:158)—— 避免把注释里出现的敏感字样当成真漏洞。命中会带上 description / cwe_id / severity / line

4. semgrep 这一级

预扫「值不值得跑」

_is_semgrep_scan_recommended(insecure_code_detector.py:295)先跑一组轻量预扫正则 (load_prescan_regexes);没有预扫规则就默认跑,有预扫规则但一条不中就不跑 semgrep。 这是又一层「省掉昂贵 semgrep」的闸门。

跑子进程 + 解析

_semgrep_analyze(insecure_code_detector.py:309)把待查代码写进临时文件,拼出 semgrep 命令 (优先用预生成的规则 JSON),_run_command 起异步子进程跑,再 _parse_semgrep_issues (:261)从 JSON 输出里抽出 issue(带 CWE、行列号、规则 id)。

只保留「生成代码」范围内的问题

分析时可能带上下文(code_before / code_after)。_filter_issues_in_generated_code (insecure_code_detector.py:240)按行号把 issue 过滤到新生成那段代码的行范围内,避免把上下文里 本就存在的问题算到模型头上。

5. 开关与可移植性

analyze 里的两个总开关来自 oss 模块:oss.ENABLE_REGEX_ANALYZERoss.ENABLE_SEMGREP (insecure_code_detector.py:121,132)。这让 CodeShield 在没装 semgrep 的环境也能退化成纯 regex 跑。 临时文件在分析后会尽量删除(:149-153)。

6. 小结

  • CodeShield = 「regex 快扫 + 命中即停 + 需要时才 semgrep」的两级流水线,为实时场景压延迟。
  • 三处降本/降误报闸门:CODESHIELD 命中即返回、semgrep 预扫、注释行过滤。
  • LlamaFirewall 侧只是把它包成一个「任一 issue → BLOCK」的扫描器,并对所有支持语言并行试扫