graph-evolution

graph-evolution

热门

比较两个源代码快照(Git提交、标签或目录)的Trailmark代码图,揭示与安全相关的结构变化。能够检测文本差异无法发现的新攻击路径、复杂度变化、影响范围增长、污点传播变化和权限边界修改。适用于比较提交或标签之间的代码、分析结构演变、检测攻击面增长、审查审计快照之间的变化,或发现文本差异遗漏的安全相关变化。

6336Star
545Fork
更新于 2026/7/30
SKILL.md
readonly只读
name
graph-evolution
description

比较两个源代码快照(Git提交、标签或目录)的Trailmark代码图,揭示与安全相关的结构变化。 能够检测文本差异无法发现的新攻击路径、复杂度变化、影响范围增长、污点传播变化和权限边界修改。 适用于比较提交或标签之间的代码、分析结构演变、检测攻击面增长、审查审计快照之间的变化, 或发现文本差异遗漏的安全相关变化。

图演化

在两个源代码快照上构建Trailmark代码图,并计算结构差异。揭示文本级差异无法发现的安全相关变化:新攻击路径、复杂度变化、影响范围增长、污点传播变化和权限边界修改。

使用场景

  • 比较两个Git引用以理解结构上的变化
  • 审计一系列提交的安全相关演化
  • 检测代码变更产生的新攻击路径
  • 发现影响范围或复杂度悄然增长的函数
  • 识别重构中的污点传播变化
  • 发布前的结构比较(标签到标签或分支到分支)

不适用场景

  • 行级代码审查(使用differential-review进行文本差异分析)
  • 单快照分析(直接使用trailmark技能)
  • 从单个快照生成图表(使用diagramming-code技能)
  • 变异测试分类(使用genotoxic技能)

应拒绝的理由

理由 错误原因 正确操作
"我们只需要结构差异,跳过预分析" 没有预分析,会遗漏污点变化、影响范围增长和权限边界偏移 在两个快照上运行engine.preanalysis()
"文本差异已经覆盖了变化" 文本差异会遗漏新攻击路径、传递性复杂度变化和子图成员变化 使用结构差异补充文本差异
"只有新增节点重要" 删除的安全函数和偏移的权限边界同样危险 审查删除和修改,而不仅仅是新增
"低严重性的结构变化可以忽略" INFO级别的变化(如死代码删除)可能掩盖删除的安全检查 分类每个变化,审查删除是否被替换
"单个快照的图足以比较" 单快照分析无法检测演化——需要前后两个快照 始终构建并导出两个图
"工具未安装,我手动比较" 手动比较会遗漏图分析能捕捉的内容 先安装trailmark

前提条件

必须安装trailmark。如果uv run trailmark失败,运行:

uv pip install trailmark

不要退而求其次使用“手动比较”或读取源文件来替代运行trailmark。必须安装并程序化使用该工具。如果安装失败,报告错误。


快速开始

# 比较两个Git引用(例如标签、分支、提交)
# 1. 在每个快照上构建图
# 2. 对两者运行预分析
# 3. 计算结构差异
# 4. 生成报告

# 逐步操作:见下方工作流

决策树

├─ 需要理解每个指标的含义?
│  └─ 阅读:references/evolution-metrics.md
│
├─ 需要报告输出格式?
│  └─ 阅读:references/report-format.md
│
├─ 已有两个图JSON导出?
│  └─ 跳转到阶段3(运行原生diff + graph_diff.py)
│
└─ 从两个Git引用开始?
   └─ 从阶段1开始

工作流

图演化进度:
- [ ] 阶段1:创建快照(git worktrees)
- [ ] 阶段2:在两个快照上构建图 + 预分析
- [ ] 阶段3:计算结构差异
- [ ] 阶段4:解释差异并生成报告
- [ ] 阶段5:清理worktrees

阶段1:创建快照

使用git worktrees获取每个引用的干净副本,而不干扰工作树。

# 为worktrees创建临时目录
BEFORE_DIR=$(mktemp -d)
AFTER_DIR=$(mktemp -d)

# 创建worktrees(在仓库根目录运行)
git worktree add "$BEFORE_DIR" {before_ref}
git worktree add "$AFTER_DIR" {after_ref}

如果比较两个目录而不是Git引用,跳过此阶段,直接在阶段2中使用目录路径。

阶段2:构建图并运行预分析

为两个快照构建Trailmark图,并对每个运行预分析。预分析计算影响范围、污点传播、权限边界和入口点枚举。

from trailmark.query.api import QueryEngine

def build_and_export(target_dir, output_path, language="auto"):
    """构建图,运行预分析,导出JSON。"""
    engine = QueryEngine.from_directory(target_dir, language=language)
    engine.preanalysis()
    json_str = engine.to_json()
    with open(output_path, "w") as f:
        f.write(json_str)
    return engine.summary()

import tempfile, os
work_dir = tempfile.mkdtemp(prefix="trailmark_evolution_")
before_json = os.path.join(work_dir, "before_graph.json")
after_json = os.path.join(work_dir, "after_graph.json")

before_summary = build_and_export(
    "{before_dir}", before_json
)
after_summary = build_and_export(
    "{after_dir}", after_json
)

通过检查摘要输出验证两个图是否成功构建。如果任一失败,使用显式语言或逗号分隔的语言列表重新运行,而不是auto

阶段3:计算结构差异

运行两者

  1. Trailmark的原生结构差异(节点、边和入口点)
  2. 插件的graph_diff.py辅助工具(子图成员变化)

使用阶段2中的同一个work_dir

trailmark diff --json "{before_dir}" "{after_dir}" > "{work_dir}/trailmark_diff.json" || \
  uv run trailmark diff --json "{before_dir}" "{after_dir}" > "{work_dir}/trailmark_diff.json"

uv run {baseDir}/scripts/graph_diff.py \
    --before "{before_json}" \
    --after "{after_json}" > "{work_dir}/subgraph_diff.json"

如果任一diff命令失败或写入空的JSON文件,停止并报告错误,而不是继续到阶段4。

原生Trailmark差异包含:

内容
summary_delta 节点/边/入口点数量的变化
nodes.added 新增的函数、类、方法
nodes.removed 删除的函数、类、方法
nodes.modified CC、参数、行跨度发生变化的函数
edges.added 新的调用/继承/导入关系
edges.removed 删除的关系
entrypoints 新增、删除和修改的入口点

子图差异包含:

内容
subgraphs 每个子图的成员变化(tainted、high_blast_radius等)

阶段4:解释差异并生成报告

读取两个差异JSON文件,生成以安全为重点的Markdown报告。
参见references/report-format.md获取完整模板。

解释优先级(从高到低):

  1. 新的污点路径 — 进入tainted子图的节点,尤其是同时出现在指向敏感函数的新增边中
  2. 权限边界变化 — 来自原生入口点/边差异和子图差异的新增或删除的信任转换
  3. 攻击面增长 — 新的入口点,特别是来自trailmark_diff.jsonuntrusted_external
  4. 影响范围增加 — 进入high_blast_radius的节点
  5. 复杂度激增 — 污点或入口点可达节点上CC增加超过3
  6. 结构新增 — 新的节点和边(需要审查)
  7. 结构删除 — 验证删除的安全函数已被替换

将结构变化与git diff {before_ref}..{after_ref}交叉引用,为发现添加源代码级上下文。

严重性分类:

严重性 结构信号
CRITICAL 新的到敏感函数的污点路径,删除的身份验证边界
HIGH 新入口点 + 高影响范围,污点节点上CC大幅增加
MEDIUM 新的跨信任边界边,CC适度增加
LOW 新增节点但不可从入口点到达
INFO 死代码删除,复杂度降低

有关详细指标定义,请参见references/evolution-metrics.md

阶段5:清理

报告写入后删除git worktrees:

git worktree remove "{before_dir}"
git worktree remove "{after_dir}"

差异参考

trailmark diff --json BEFORE AFTER
uv run {baseDir}/scripts/graph_diff.py [OPTIONS]

使用trailmark diff用于:

  • 节点/边变化
  • 新增/删除/修改的入口点
  • 人类可读的结构差异报告

使用graph_diff.py用于:

  • engine.preanalysis()派生的子图成员变化
  • taintedhigh_blast_radiusprivilege_boundary及相关集合
参数 默认值 描述
--before 必需 “之前”图JSON的路径
--after 必需 “之后”图JSON的路径
--indent 2 JSON输出缩进

graph_diff.py输入格式:来自engine.to_json()的Trailmark JSON导出。
graph_diff.py输出:节点、边和子图的JSON结构差异。


质量检查清单

在交付报告之前:

  • [ ] 两个图均成功构建(检查摘要)
  • [ ] 在两个快照上运行了预分析
  • [ ] 原生Trailmark差异已计算且非空(trailmark_diff.json
  • [ ] 子图差异已计算且非空(subgraph_diff.json
  • [ ] 所有子图变化已解释(污点、影响范围等)
  • [ ] 关键发现包含证据(节点ID、边差异)
  • [ ] 所有发现已分配严重性级别
  • [ ] 通过git diff交叉引用添加了源代码级上下文
  • [ ] Worktrees已清理(或临时目录已删除)
  • [ ] 报告已写入GRAPH_EVOLUTION_*.md

集成

trailmark技能:
阶段2使用trailmark API进行图构建和预分析。所有trailmark查询模式均可用于任一快照的引擎。

differential-review技能:
使用graph-evolution进行结构分析,使用differential-review进行行级代码审查。两者互补——graph-evolution发现文本差异遗漏的攻击路径,而differential-review提供git blame上下文和微观对抗分析。

trailmark-review-gate技能:
在graph-evolution之后使用trailmark-review-gate,当分支、拉取请求、修复提交或发布差异需要PASS/WARN/FAIL/UNKNOWN结构审查包时。该门控对graph-evolution输出应用确定性审查规则;它不取代人工审查。

genotoxic技能:
如果graph-evolution揭示新的高CC污点节点,将其输入genotoxic进行变异测试分类。

diagramming-code技能:
生成前后图表以可视化结构变化。使用聚焦于变化节点的call-graphdata-flow图表。


支持文档