genotoxic

genotoxic

热门

基于代码图的变异测试结果分选工具。先通过 Trailmark 解析代码库,执行变异测试与 necessist,再结合存活变异体(survived mutants)、冗余测试语句及调用图数据,精准识别误报、测试覆盖缺失和 Fuzzing 目标。适用于对存活变异体进行分类排查、分析变异测试结果、定位测试盲区、基于弱测试寻找 Fuzzing 目标、运行变异框架(包含 circomvent 和 cairo-mutants)或使用 necessist 的场景。

6336Star
545Fork
更新于 2026/7/30
SKILL.md
只读
名称
genotoxic
描述

基于代码图的变异测试结果分选工具。先通过 Trailmark 解析代码库,执行变异测试与 necessist,再结合存活变异体(survived mutants)、冗余测试语句及调用图数据,精准识别误报、测试覆盖缺失和 Fuzzing 目标。适用于对存活变异体进行分类排查、分析变异测试结果、定位测试盲区、基于弱测试寻找 Fuzzing 目标、运行变异框架(包含 circomvent 和 cairo-mutants)或使用 necessist 的场景。

Genotoxic

将变异测试(Mutation testing)和 necessist(测试语句裁减)与代码图分析相结合,对发现的问题进行分类排查(Triage),将其归类为可落地的具体分类:误报(False positives)、缺失的单元测试以及 Fuzzing 目标。

适用场景

  • 变异测试跑出存活变异体(survived mutants),需要进一步分类排查时
  • 寻找编写单元测试收益最高的核心代码位置时
  • 寻找更适合写 Fuzz harness 而非普通单元测试的函数时
  • 利用数据流上下文评估并优化测试优先级时
  • 从变异结果中过滤无害变异体,筛选出真正需要处理的问题时
  • 查找测试中多余/无效的语句(necessist),定位弱断言测试时

不适用场景

  • 代码库完全没有现有测试套件(请先编写基础测试)
  • 纯文档修改或纯配置变更
  • 逻辑极其简单的单文件脚本

前置条件

  • 已安装 trailmark — 如果 uv run trailmark 运行失败,请执行:
    uv pip install trailmark
    
    切勿以“手动验证”或“手动分析”替代运行 trailmark。必须优先安装该工具;若安装失败,请直接报错反馈,严禁切到手动分析模式。
  • 目标语言对应的变异测试框架 — 若框架命令运行失败(如未找到或未安装),请按照 references/mutation-frameworks.md 中的指引进行安装。切勿退回到“手动变异分析”或直接跳过变异测试。必须先完成框架安装;若安装失败,请报出错误,而不是转入手动变异分析。
  • necessist(可选,推荐)— 如果目标语言受支持(Go、Rust、Solidity/Foundry、TypeScript/Hardhat、TypeScript/Vitest、Rust/Anchor),可以通过 cargo install necessist 安装。详见 references/mutation-frameworks.md
  • 一套可正常通过的现有测试套件
  • macOS 环境注意:在调用 mull-runner 之前,必须先运行 ulimit -n 1024。macOS Tahoe (26+) 默认会将文件描述符设为无限制(unlimited),这会导致 Mull 在创建子进程时崩溃。详见 references/mutation-frameworks.md

拒绝摆烂借口

错误借口 / 托词 错在哪 必须采取的行动
“所有存活的变异体都需要写测试” 很多变异体是无害的或等价变异(Equivalent mutant) 写测试前先进行分选(Triage)
“变异测试噪声太大了” 觉得噪声大说明你没有做分选 利用代码图数据进行过滤
“单元测试已经全覆盖了” 复杂的数据流需要 Fuzzing 检查入口点的可达性(Reachability)
“死代码里的变异体不用管” 死代码本身就应该清理掉 标记出来并进行清理
“复杂度低 = 风险低” 边界 Bug 往往藏在看似简单的代码里 检查变异体所在具体位置
“工具没装,我手动分析吧” 手工分析必然会漏掉自动化工具能捕获的问题 必须先安装工具
“Necessist 不是变异测试,跳过它” Necessist 能找出变异测试漏掉的问题:弱测试(Weak tests) 只要语言支持,就必须两者都运行

快速上手

# 1. 构建代码图
uv run trailmark analyze --language auto --summary {targetDir}

# 2. 运行变异测试(因语言而异)
# Python:
uv run mutmut run --paths-to-mutate {targetDir}/src
uv run mutmut results

# 2b. 运行 necessist(若语言支持)
necessist

# 3. 使用本 Skill 的工作流分析结果(阶段 3)

工作流概览

阶段 1: 图构建         → 使用 trailmark 解析代码库
      ↓
阶段 2: 变异测试运行    → 执行变异测试框架
阶段 2b: Necessist 运行 → 裁减测试语句(可选,可并行)
      ↓
阶段 3: 分选 (Triage)  → 结合图数据对结果分类
      ↓
输出:分类报告
  ├── 相互印证 (Corroborated) (两个工具标记同一函数 —— 价值最高)
  ├── 误报 (False Positives)  (无害,跳过)
  ├── 缺失测试 (Missing Tests)(编写单元测试)
  └── Fuzzing 目标           (搭建 Fuzz harness)

决策树

├─ 需要为某种语言配置变异测试?
│  └─ 请参阅:references/mutation-frameworks.md
│
├─ 需要配置 necessist 或查找弱测试语句?
│  └─ 请参阅:references/mutation-frameworks.md(Necessist 章节)
│
├─ 需要深入理解分选(Triage)的标准?
│  └─ 请参阅:references/triage-methodology.md
│
├─ 需要了解图数据如何辅助分选?
│  └─ 请参阅:references/graph-analysis.md
│
└─ 已经拿到结果 + 图数据?直接执行下文的阶段 3。

阶段 1:构建代码图并运行预分析

在执行变异测试之前,先使用 trailmark 解析目标代码库并运行预分析(Pre-analysis)。预分析会计算爆炸半径(Blast radius)、入口点(Entry points)、特权边界(Privilege boundaries)以及污染传播(Taint propagation),这些数据将在阶段 3 的分选排查中使用。

uv run trailmark analyze --language auto --summary {targetDir}

使用 QueryEngine API 构建图结构并运行预分析:

  1. QueryEngine.from_directory("{targetDir}", language="auto")
  2. 调用 engine.preanalysis() — 分选前必须执行
  3. 通过 engine.to_json() 导出数据,以便与变异测试结果进行交叉比对

如果自动识别的目标语言有误,可以传入明确的语言名称或逗号分隔列表重新运行(例如 python,rust)。

完整的 API 细节(包含节点映射、可达性查询、爆炸半径及预分析子图检索),请参阅 references/graph-analysis.md


阶段 2:运行变异测试

选择并运行合适的变异测试框架。针对具体语言的安装配置,请参阅 references/mutation-frameworks.md

收集存活的变异体(Survived mutants)。 不同框架的报告格式可能不同,但针对每个变异体,需提取以下字段:

字段 描述
File path(文件路径) 包含该变异体的源文件路径
Line number(行号) 应用变异的具体行号
Mutation type(变异类型) 被修改的内容(如运算符、数值等)
Status(状态) survived(存活)、killed(被杀)、timeout(超时)、error(错误)

仅筛选出**存活(survived)**的变异体,用于阶段 3 的分选。


阶段 2b:运行 Necessist(可选)

如果目标语言受支持(Go、Rust、Solidity/Foundry、TypeScript/Hardhat、TypeScript/Vitest、Rust/Anchor),运行 necessist 找出多余的测试语句。此步骤独立于阶段 2,可并行执行。

# 自动检测框架
necessist

# 或指定特定的测试文件
necessist tests/test_parser.rs

# 导出结果
necessist --dump

筛选出**删改后测试依然通过(passed after removal)**的结果。具体的框架配置及标准规范记录格式,请参阅 references/mutation-frameworks.md

利用 references/graph-analysis.md 中的算法,将每次删改映射到对应的生产函数(Production function)。


阶段 3:分选结果 (Triage Findings)

结合代码图数据,为每个存活变异体及 necessist 裁减项确定其归属的分选桶(Bucket)。 necessist 裁减项必须先映射到生产函数(详见 references/graph-analysis.md)。

快速分类规则(变异测试)

信号/特征 分选桶 判决依据
图结构中无调用方 误报 (False Positive) 死代码,变异体不可达
仅有测试代码调用 误报 (False Positive) 测试基础设施代码,非生产逻辑
日志/展示字符串变异 误报 (False Positive) 仅影响 UI/展示,不影响核心行为
等价变异体 (Equivalent mutant) 误报 (False Positive) 变异后实际运行行为未发生变化
简单函数、圈复杂度(CC)低、无入口点路径 缺失测试 (Missing Tests) 编写单元测试直截了当
错误处理路径 缺失测试 (Missing Tests) 应补充反向/异常测试用例
边界条件(如 off-by-one) 缺失测试 (Missing Tests) 适合采用属性测试(Property-based test)
纯函数、结果确定 缺失测试 (Missing Tests) 易于测试,收益高
高圈复杂度 CC (>10),且入口点可达 Fuzzing 目标 (Fuzzing Target) 复杂度高 + 暴露在外 = 极适合 Fuzzing
解析器/验证器/反序列化组件 Fuzzing 目标 (Fuzzing Target) 专门处理结构化输入
被大量调用 (>10) + 中等圈复杂度 CC Fuzzing 目标 (Fuzzing Target) 爆炸半径(Blast radius)大
二进制/网络协议处理逻辑 Fuzzing 目标 (Fuzzing Target) Fuzz 工具非常擅长测试这类格式

快速分类规则(Necessist)

信号/特征 分选桶 判决依据
冗余的初始化或调试调用 误报 (False Positive) 语句本身确实没有实质作用
无法映射到生产函数 误报 (False Positive) 缺乏图数据上下文,无法进一步分选
函数调用被删除,但没有断言对其效果做检验 缺失测试 (Missing Tests) 测试断言力度较弱
断言被删除,测试依然成功通过 缺失测试 (Missing Tests) 断言冗余或测试覆盖不足
映射到高 CC 且入口点可达的函数 Fuzzing 目标 (Fuzzing Target) 逻辑复杂 + 接口暴露 + 现有测试弱

当变异测试与 necessist 同时标记了同一个生产函数时,将其标记为相互印证(corroborated) —— 这是可信度最高的高价值发现。

详细判决标准,请参阅 references/triage-methodology.md

用于分选的图查询

针对每一个变异体,将其映射到对应的图节点,并使用阶段 1 生成的预分析子图数据(tainted、high_blast_radius、privilege_boundary)进行分类。分类逻辑的检查顺序为:无调用方 → 误报(false positive);特权边界 → Fuzzing 目标;高圈复杂度 CC + 被污染数据流 → Fuzzing 目标;大爆炸半径 → Fuzzing 目标;其他情况 → 缺失测试(missing tests)。

有关 batch_triage 的实现细节和节点映射函数,请参阅 references/graph-analysis.md


输出格式

生成 Markdown 格式的报告:

# Genotoxic 分选报告

## 概览
- 存活变异体总数:N
- Necessist 裁减语句总数:N
- 相互印证的发现数:N
- 误报数量:N (N%)
- 测试覆盖缺失数:N (N%)
- Fuzzing 目标数:N (N%)

## 相互印证的发现 (Corroborated Findings)
| 文件 | 行号 | 函数 | 变异测试信号 | Necessist 信号 | 建议操作 |
|------|------|----------|----------------|------------------|--------|

## 误报 (False Positives)
| 文件 | 行号 | 变异内容 | 判定原因 | 来源 |
|------|------|----------|--------|--------|

## 缺失测试覆盖 (Missing Test Coverage)
| 文件 | 行号 | 函数 | CC (圈复杂度) | 调用方数量 | 建议测试类型 | 来源 |
|------|------|----------|----|---------|----------------|--------|

## Fuzzing 目标 (Fuzzing Targets)
| 文件 | 行号 | 函数 | CC (圈复杂度) | 入口点路径 | 爆炸半径 | 来源 |
|------|------|----------|----|-----------------|--------------|--------|

来源 列填写 mutationnecessistcorroborated

将报告写入当前工作目录下的 GENOTOXIC_REPORT.md 文件中。


质量检查清单

交付前请确认:

  • [ ] 已针对目标语言构建 Trailmark 代码图
  • [ ] 变异测试框架已完整运行结束
  • [ ] 已运行 Necessist(若语言支持),或已注明不适用
  • [ ] 所有存活变异体均已完成分选(无未分类项)
  • [ ] 所有 Necessist 裁减项均已完成分选(若适用)
  • [ ] 已标出相互印证的发现(若两个工具均运行)
  • [ ] 所有误报项均有清晰合理的理由
  • [ ] 缺失测试项均给出了建议的测试类型
  • [ ] Fuzzing 目标包含具体的入口点路径及爆炸半径
  • [ ] 报告文件已写入 GENOTOXIC_REPORT.md
  • [ ] 已将汇总统计数据通知用户

与其他 Skill 的集成

trailmark skill:

  • 阶段 1:构建代码图,查询圈复杂度与入口点
  • 阶段 3:调用方分析、可达性分析、爆炸半径计算

property-based-testing skill:

  • 涉及边界条件的测试覆盖缺失项
  • 针对序列化变异体的往返/幂等性属性测试(Roundtrip/idempotence properties)

testing-handbook-skills (fuzzing):

  • Fuzzi

<!-- truncated for translation batch; full body continues in source -->