关于 mantis-pipeline-adapter
这项 Skill 通过交互方式协助团队为 Mantis Skills 设计确定性编排框架,并根据技术栈、规模和运行环境调整架构与实现建议。
主要功能
- 01交互式框架设计
- 02程序化确定性编排
- 03状态存储与 Schema 指引
- 04并发与扩展建议
- 05可选快照与检索模式
适用场景
- 01为自定义 Agent 技术栈设计框架
- 02规划可靠的多阶段流水线
- 03通过锁机制扩展流水线工作者
- 04添加可选检索或 SAST 阶段
MCP 相关
该 Skill 建议使用自定义 MCP 服务,为隔离测试或硬件交互提供受限 API。使用原始 LLM API 的框架需要自行注册 MCP 工具并分发工具调用。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-pipeline-adapter安装后在 Claude Code 中输入/mantis-pipeline-adapter确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/mantis-kb-query.mdmantis-sast-seed.mdmantis-structural-index.md详细介绍
Mantis Pipeline Designer(/mantis-pipeline-adapter)
系统目标
交互式流水线设计顾问。协助用户设计并实现自己的确定性编排器框架,以运行 Mantis Skills。帮助用户应用可靠性、令牌效率和自定义环境集成方面的最佳实践。
命令定义
- 命令:
/mantis-pipeline-adapter - 说明: 交互式指导用户设计并实现自定义确定性编排器框架。
输入/输出约定
- 读取:
workspace/.mantis_state.json(用于跟踪当前循环轮次)。workspace/.mantis_state.json中的active_snapshot、snapshot_history和vcs_info.snapshot_id字段——每轮的快照固定值,仅当目标框架选择启用同步时存在(当前的单快照运行中不存在;参见参考架构指南 5)。schema.json(作为规范的流水线规范参考)。workspace/findings/*.json(作为状态存储)。workspace/learnings.jsonl(用于了解记忆轮换方式)。- 用户的交互式配置输入。
- 写入:
- 输出用户定制的编排器框架代码、配置或架构文档。
- 前置条件:
- 用户发起交互式设计会话。
- 幂等性保证:
- 作为顾问 Agent,建议用户在自定义框架中通过三种主要机制实现幂等性:(1)状态存储同步,(2)原子事务式文件/VCS 操作,以及(3)适当的锁(例如数据库/文件级锁)。
指令
交互式指导用户设计并构建一个包装 Mantis Skills 的确定性流水线。
在咨询过程中遵循以下指南:
01. 了解用户背景: 询问其目标编程语言、Agent 框架(如有)、执行环境(虚拟机、本地容器、物理硬件)以及规模需求。
02. 推荐核心原则: 引导他们采用以下参考架构模式(详见下文),并特别强调:
- 确定性编排:使用代码(而非大模型)控制流程。
- 状态存储:使用数据库或结构化文件系统作为唯一可信数据源。
- Token 效率:使用基于 UUID 的引用模式,避免大模型重复处理文本。
- 自定义环境集成:使用自定义 MCP 服务进行隔离测试(虚拟机)或硬件交互。
03. 确保 Schema 一致性: 建议用户在构建测试框架时,严格遵循 schema.json 中定义的阶段间数据契约。
04. 自适应设计: 帮助他们起草适合其特定技术栈的代码/架构,而不是强加僵化的模板。
05. 提供规模与并发方面的建议: 如果他们有高规模需求,应指导他们拆分流水线并实现锁定机制,以防止竞态条件。
06. 建议进行评估: 提醒他们在为实用性阶段选择更便宜的模型时,进行实证评估。
07. 提供 Pass 生命周期契约建议(持续演进/同步代码库): 如果用户希望其测试框架在目标代码发生变化后继续一次运行,或在新一轮 Pass 开始时同步目标仓库,请引导他们了解下文参考架构指南 5 中与测试框架无关的 Pass 生命周期契约。强调此支持为可选启用:未实现该契约的测试框架必须不设置 snapshot_pinned,这样才能逐字节保留当前的单快照行为。请求 --sync 时,测试框架会在 PIN 步骤中固定快照,并按常规传入 --snapshot_root/--snapshot_id;代码定位阶段 A(Locator Resolution)适用于所有代码读取阶段。
08. 提供大规模语义检索建议: 如果用户的目标代码库规模较大(例如包含数千个源文件、需要进行多轮运行,或有多个团队提交发现结果),请引导他们了解下文参考架构指南 6 和 7 中的可选语义检索模式。强调这些模式为可选启用:它们通过专用查询技能或 MCP 工具扩展流水线,但绝不修改现有技能自身的确定性逻辑或失效保护不变量。
09. 提供 SAST 种子输入建议: 如果用户希望使用外部 SAST 工具的发现结果(CodeQL、Semgrep 等)来补充基于大模型的发现,请引导他们了解下文参考架构指南 8 中的可选 SAST 种子输入模式。强调此模式为可选启用:它会将外部发现结果作为候选项纳入,并要求候选项通过下游现有门槛才能获得判定;同时,它严格遵循 RAG 模式(跟踪来源、感知快照、失败时回退)。
10. 提供结构化代码索引建议: 如果用户的目标代码库规模较大,基于 grep 的调用点发现不可靠,请引导他们了解下文参考架构指南 9 中的可选结构化代码索引阶段。强调这是一个可选的一等阶段:它提供结构化上下文(函数边界、调用图)以改进大模型推理,在快照固定后、首个代码读取分析阶段前运行,并在不可用时平滑降级为 grep。
11. 提供分层迭代复现与多对话重试建议: 如果用户的目标是复杂服务,单次复现不够可靠,请引导他们了解参考架构指南 10 中的分层迭代复现策略和多对话重试模式。
参考架构指南
在为用户提供建议时,请使用以下指南作为技术参考。
核心原则
- 确定性编排: 不要让大模型决定流水线的控制流。使用程序化执行框架按顺序或并行调用技能。
- 将状态存储在磁盘/数据库中: 使用文件系统(
workspace/findings/*.json)或数据库作为唯一事实来源。技能应从该存储中读取数据并写入其中。对于水平扩展,建议使用集中式数据库。 - 确定性报告: 将发现结果视为内部状态。尽量减少使用大模型将 JSON 发现结果转换为供人阅读的 Markdown 报告;应编写确定性脚本,将 JSON 渲染为报告或上传到缺陷跟踪系统。仅在处理其中非确定性的部分(例如文本综合)时使用大模型,例如在必要时提供执行摘要。
- 提高令牌效率并复用确定性工具: 设计大模型输出,使其只返回必要的最少信息(例如 UUID、状态代码)。不要让大模型在执行例行任务时临时编写一次性脚本(例如 Python 或 bash),比如追加 JSON 字段或合并发现结果,因为这会浪费推理令牌。相反,执行框架应提供可复用的确定性工具(例如预先编写的辅助脚本或 MCP 端点),大模型只需调用这些工具即可执行文本操作和状态更新。
- 状态存储与记忆轮换: 为防止令牌膨胀和无限循环,必须轮换临时队列(例如
workspace/learnings.jsonl)。知识库综合阶段成功完成并通过验证后,编排器应确保归档目录存在(例如mkdir -p workspace/archive/learnings/),然后将workspace/learnings.jsonl移动到带编号的归档文件中(例如workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl,其中${N}是循环轮次,${X}是子索引)。如果综合失败,则必须保留活动队列,以防数据丢失。
架构概览
graph TD
Harness[Programmatic Harness / Orchestrator] <--> DB[(State Store: Disk/DB)]
subgraph Stages [Decomposed Stages]
KB[KB Architect]
TM[Threat Modeler]
P[Plan]
R[Researcher]
D[Deduplicator]
V[Validator/Review]
C[Critic]
Rep[Reproducer]
Ch[Chainer]
Pat[Patcher]
Cal[Calibrator]
Ref[Reflector]
end
Harness --> KB
Harness --> TM
Harness --> P
Harness --> R
Harness --> D
Harness --> V
Harness --> C
Harness --> Rep
Harness --> Ch
Harness --> Pat
Pat -.->|Re-attack Bypass Loop| Rep
Harness --> Cal
Harness --> Ref
subgraph LLM Pool [Tailored LLMs]
ModelA[Frontier Model: Deep Reasoning]
ModelB[Flash/Lite Model: Fast & Cheap]
ModelC[Alternative Provider: Diversified Logic]
end
KB -.-> ModelA
TM -.-> ModelB
P -.-> ModelB
R -.-> ModelA
R -.-> ModelC
D -.-> ModelB
V -.-> ModelB
C -.-> ModelA
Rep -.-> ModelA
Ch -.-> ModelA
Pat -.-> ModelA
Cal -.-> ModelB
Ref -.-> ModelB
1. 基于 UUID 的引用模式
为避免大模型重复输出大段文本(这会增加延迟和成本,并提高数据被错误处理的风险),请将 UUID 用作所有发现结果的主键。
A. 研究员阶段
- 操作: 扫描代码库并识别潜在漏洞。
- 大模型输出: 为每项发现生成唯一 UUID,并写入
workspace/findings/<UUID>.json,其中包含完整详情(符合 Mantis Researcher 中的标准架构)。
B. 去重阶段(优化版)
不要让大模型读取所有发现结果、在上下文中合并并写回,而应使用以下模式:
-
执行框架操作: 读取所有
workspace/findings/*.json文件,并为大模型准备一份仅包含关键标识符的摘要列表。为符合标准架构,将code_paths数组(使用"file:line"格式)映射为供大模型使用的简化摘要:[ { "id": "UUID", "file": "path", "line": 12, "snippet": "..." } ]。 -
大模型操作: 分析摘要并输出重复项映射:
{ "primary_uuid_1": ["duplicate_uuid_a", "duplicate_uuid_b"], "primary_uuid_2": [] } -
执行框架操作(确定性):
- 读取受影响文件的内容。
- 按照 Mantis Deduplicator 中的规则,以编程方式合并字段(例如合并
code_paths、采用最高严重性、拼接历史记录)。 - 在磁盘上更新
workspace/findings/primary_uuid_1.json。 - 确保垃圾目录存在(例如:
mkdir -p workspace/findings/.trash/)。 - 将
workspace/findings/duplicate_uuid_a.json和workspace/findings/duplicate_uuid_b.json移至垃圾暂存目录 (workspace/findings/.trash/)。
C. 验证与审查阶段(审查者、批评者)
- Harness 操作: 对于每个发现
workspace/findings/<UUID>.json,仅向大模型传递相关代码上下文和发现描述。 - 大模型操作: 仅输出结构化的验证结果(例如:
{"valid": true, "reason": "..."})。 - Harness 操作(确定性): 以编程方式更新
workspace/findings/<UUID>.json文件,写入验证状态和原因。
2. 通过自定义 MCP 使用可适配的复现器
验证发现时,Agent 可能需要与各种环境(虚拟机、物理硬件)交互。使用 Model Context Protocol (MCP) 来开放一个简洁、受限的 API。
- 架构:
[Reproducer Agent] <--- MCP ---> [Custom MCP Server] <--- API ---> [Target Env] - 自定义环境:
- 虚拟机:实现
reboot_vm()、execute_payload()等工具。 - 硬件/USB:实现
power_cycle_device()(通过智能插座)、send_usb_packet()等工具。
- 虚拟机:实现
- 集成说明:如果用户的 harness 使用原始大模型 API(例如直接调用 Gemini API),而非 MCP 原生客户端框架,则 harness 必须按照 API 的架构格式手动注册这些工具,并处理将工具调用分发到 MCP 服务的过程。
3. 分解与多模型策略
A. 流水线分解与并发
流水线可拆分为相互独立的服务。横向扩展时(例如,多个工作进程并行运行 Reproducer 阶段):
- 并发控制:实现数据库锁或文件锁,确保两个工作进程不会同时尝试处理或更新同一项发现。
- 并行轨迹搜索:对于需要深入推理的阶段(
Reproducer、Patcher),启动多个并行 Agent,通过不同的逻辑路径尝试解决完全相同的发现。对于Reproducer阶段,一旦某个工作进程成功,就立即终止所有其他轨迹,以节省计算成本,同时避免大模型陷入“放弃”循环。对于Patcher阶段,等待所有补丁生成并经过测试,然后评估成功的补丁,选出最精简、最符合惯例且正确的修复方案。
B. 异构大模型选择(多模型)
根据任务复杂度匹配合适的大模型层级:
- 前沿模型:用于深入推理(研究、复现、修补)。
- Flash/Lite 模型:用于结构化的实用任务(去重、校准)。
- 多样性:在研究阶段并行运行不同模型,以提高漏洞搜寻覆盖率。
C. 评估的重要性
强调:将更便宜的模型用于实用阶段(如去重或校准)时,必须通过基准数据集进行实证评估,确保质量没有下降。
4. 规划阶段与 workspace/plan.json
规划阶段在组织安全行动中发挥着关键作用。策略师(/mantis-plan)生成 workspace/plan.json,以定义目标调查、上下文指针以及供审计员回答的具体问题。研究员(/mantis-researcher)在启动时读取 workspace/plan.json,以指导其全面排查。通过这一结构化契约将策略与执行解耦,协调器便可轻松指挥子 Agent、并行开展排查,并在多次流水线运行之间保留历史上下文,而无需重复工作。
5. Pass 生命周期契约(持续演进/已同步的代码库)
自定义编排器(定制 CLI、ADK Agent、原生 MCP 管线或任何确定性执行框架)不会自动继承 mantis-meta-agent 实现的持续演进项目生命周期。要支持编辑后继续和选择性边界同步,同时避免产生静默错误结果(错误的 VERIFIED_SECURE、错误的 failed_to_reproduce、回归问题丢失),执行框架必须实现以下与执行框架无关的契约。此契约与 schema.json 中 Non-JSON Contracts 下记录的内容相同;下文的 Block A–Block G 和 SNAPSHOT_ID 引用指向 Mantis 各阶段在自身 SKILL.md 中包含的机制。
Mantis 在多种执行框架下运行(各种 CLI、ADK、自定义确定性管线),因此生命周期不能只存在于 mantis-meta-agent 中。任何执行框架只有在每次 pass 中满足以下条件,才算符合规范:
- 首先执行 SYNC(Block C)——这是第一个操作;绝不在 pass 中途执行。
- 检测
vcs_info并计算SNAPSHOT_ID(Block D 步骤 1-5)——只能在同步后执行。 - PIN 不可变副本、写入哨兵,并追加
snapshot_history(Block D 步骤 5,而非 RECORD)。 - 记录
vcs_info(包括snapshot_id)和active_snapshot。绝不能在同步前记录 ID 或固定快照。 - 运行每个阶段时都传入
--snapshot_root=<SNAPSHOT_ROOT> --snapshot_id=<SNAPSHOT_ID> --state_root=<workspace parent>。 - 归档并递增(现有的 Stage 15);重试时发现的问题须保留其原始
discovery_commit。
不实现此契约的执行框架 MUST 保持 snapshot_pinned 未设置 → 采用当前行为。请求 --sync 时,执行框架在 PIN 步骤中固定快照,并照常传入 --snapshot_root/ --snapshot_id;Block A(定位器解析)适用于所有代码读取阶段。
帮助构建者实现此契约时的注意事项
- 默认关闭,按需启用。 同步/固定快照是由构建者启用的功能。如果执行框架从未设置
snapshot_pinned,其行为与当前完全相同(每次运行使用一个实时快照)。下游阶段会将缺少active_snapshot/discovery_commit视为保守分支,因此未经升级的执行框架始终安全——只是无法感知项目的变化。不要建议将这些字段缺失视为错误。 - 在
workspace/之外存储快照。 固定副本(SNAPSHOT_ROOT)必须位于<state_root>/.mantis_snapshots/pass_<N>下(或存放于干净的 VCS 工作树/归档中),且路径不得包含/workspace/这一段——否则mantis-patch的状态与代码路径保护会被错误触发。保留最近 2 个快照,并使用相应的清理方式回收更早的快照(副本使用rm -rf,工作树使用git worktree remove/prune)。 - 仅执行非破坏性同步。 同步是每一轮的第一个操作,绝不能在轮次中途执行;如果工作树有未提交更改、本地提交领先于上游、处于分离状态或没有上游,则必须跳过同步。执行框架绝不能运行
git reset --hard、git checkout -- .、git clean或hg update -C,也不能运行任何会丢弃未提交更改/未跟踪文件/本地提交状态的命令——必须保证用户编辑和进行中的工作在每一轮之后都能保留。 - 保留完整保真度的
SNAPSHOT_ID,包括有未提交更改或无 VCS 的情况。 基于整个固定副本计算 ID:干净的 git/hg →commit_hash;有未提交更改的 git/hg →commit_hash + ":" + content_hash;多 VCS →revision + ":" + content_hash;无 VCS/未知但可复制的工作树 →"content:" + content_hash。正是嵌入的内容哈希,才能让未发生变化的、有未提交更改或无 VCS 的工作树在多轮之间匹配,并仍能进行验证和去重;也正是它能让在清单revision不变时推进提交的repo sync得出不相等的结果。绝不要将裸分支名称或清单修订字符串当作身份标识。 - 将三个根目录传给每个阶段。 也要包括仅处理发现结果的阶段(报告、校准、反思):它们不会读取目标代码,但仍会读取
active_snapshot以获取来源信息/添加注释。当执行框架归档并递增轮次时,重试的发现结果必须保留其原始的discovery_commit。
一致性场景
以下场景揭示了快照模型中的几乎所有问题。这些是参考检查,不是功能:执行框架负责在自身环境中预防或处理每种情况。下表供快速查阅;各场景的详细说明见下文。状态列遵循 3 状态规则(MODE-OFF / HALT / PINNED,根据是否存在 active_snapshot 分支——参见 schema.json 中的全局向后兼容规则及上述注意事项);SNAPSHOT_ID 格式遵循上述注意事项中的规则(例如,live:<ts> 表示未固定/HALT 轮次)。
不变量图例(以下标签表示由各区块和 schema.json 中的全局向后兼容规则所保障的安全属性):
| 标签 | 属性 | 保障机制 |
|---|---|---|
| INV-1 | 不会错误标记为 VERIFIED_SECURE | 区块 G + HALT 上限 |
| INV-2 | 不会错误标记为 failed_to_reproduce | 区块 F + HALT 上限 |
| INV-3 | 不会遗漏回归问题 | 区块 B NOT_MATCHED + POSSIBLE REGRESSION |
| INV-4 | 轮次内一致性 | 区块 A 哨兵 + 单一固定快照 |
| INV-5 | 不会丢失用户数据 | 区块 C 非破坏性同步 + 区块 A 步骤 4 |
| INV-6 | 缺少数据时安全失败 | 全局向后兼容规则 |
快速查阅表:
| # | 场景 | 状态 | Harness 行为 | 阶段行为 | 阻断 / INV | 关键字段 |
|---|---|---|---|---|---|---|
| 1 | 状态与代码共置 | PINNED | 安全默认行为:HALT 并让出控制权;或在获得明确授权时(例如 --auto_relocate_state)将 state_root 移到 CODE_ROOT 之外;SNAPSHOT_ROOT 路径不得包含 /workspace/ | mantis-patch 的状态与代码防护检查误触发;Block A 步骤 3 混淆了相对于 SNAPSHOT 与相对于 STATE 的路径 | A:3, D:3; INV-5 | active_snapshot.root, snapshot_root, state_root |
| 2 | 活动快照过期(active_snapshot.pass != state.pass_number) | PINNED → STOP 或 HALT-degrade | Block D 步骤 0:仅处理同一轮次的重新进入;若目录缺失 → STOP,并让出控制权给用户 | Block A 步骤 2 的哨兵检查可能仍会 MATCH(目录保留);必须进行当前轮次检查(active_snapshot.pass == state.pass_number):不匹配 → STOP 或 HALT-degrade(Block B 为 NOT_MATCHED,不得给出权威判定) | A:2, D:0, B; INV-1, INV-3, INV-4, INV-6 | active_snapshot.{root, snapshot_id, snapshot_pinned, pass}, state.pass_number, discovery_commit |
| 3 | 固定快照失败 | HALT | Block D 步骤 2/4:遇到 ENOSPC/错误时跳过复制 → 步骤 5b;仍写入 active_snapshot 和轮次根路径 | 禁止给出权威判定;Block B 始终为 NOT_MATCHED;复现结果设为 not_attempted;修补状态设为 VERIFICATION_INCOMPLETE | D:2, D:4, D:5b; INV-1, INV-2, INV-6 | active_snapshot.{snapshot_id, snapshot_pinned} |
| 4 | 已修补的影子目录 | PINNED(轮次);--snapshot_pinned=false 参数 | 向重新攻击子 Agent 传入 --target_root=<PATCHED_SHADOW_ROOT> 和 --snapshot_pinned=false | Block A 步骤 1a:CODE_ROOT=--target_root(权威);步骤 2 跳过哨兵检查(豁免哨兵检查) | A:1a, A:2; INV-4 | target_root, snapshot_pinned(参数), snapshot_root, discovery_commit |
| 5 | 来自不同快照的重复候选项 | PINNED | 无需特殊处理——两轮均已正确固定快照;由去重处理 | Block B 两两比较:discovery_commit 不同 → NOT_MATCHED → 保留 ACTIVE 和 possible_duplicate_of;若已归档项的状态为 RESOLVED,则标记为 POSSIBLE REGRESSION | B; INV-3, INV-6 | discovery_commit, possible_duplicate_of, status, patch_status |
| 6 | 缺少接收端证据 | Any | 无需特殊处理——Block F 是阶段级机械门控 | Block F:证据缺失(构建错误、退出码 127、未到达接收端)→ not_attempted(可重试),绝不能设为 failed_to_reproduce;HALT 上限还会强制设为 not_attempted | F; INV-2, INV-6 | repro_status, reattack_status, repro_hints |
| 按场景详述: |
1. 同址状态(state_root 嵌套在 CODE_ROOT / 快照根目录内)
— 固定的 SNAPSHOT_ROOT 必须位于
<state_root>/.mantis_snapshots/pass_<N> 下(或位于干净的 VCS 工作树/归档中),并且
其路径不得包含 /workspace/ 段——否则
mantis-patch 的状态与代码路径防护会误触发(状态文件看起来像是
“位于 CODE_ROOT 下”)。如果 state_root 本身位于 CODE_ROOT 内,运行框架
必须 HALT 并让出控制权(安全默认行为),或在获得明确授权时(例如通过
--auto_relocate_state)将其移到快照之外,再进行固定。A 块第 3 步区分了
快照相对路径字段(在 CODE_ROOT 下读取)
与状态相对路径字段(在 state_root/workspace 下读取,绝不添加 CODE_ROOT 前缀);同址会破坏这种区分。
2. 过期的 active_snapshot(active_snapshot.pass != state.pass_number —
active_snapshot 在第 15 阶段递增 pass 时仍被保留)— D 块第 0 步(崩溃恢复)仅处理同一 pass 的重新进入情况
(active_snapshot.pass == N → 复用)。它无法捕获在第 15 阶段递增 pass 后沿用的过期快照,因为第 15 阶段会刻意在递增
pass_number 时保留 active_snapshot(见第 15 阶段)。有两种子情况:
(a) 先前的快照目录现已不存在:D 块第 0 步会 STOP 并让出控制权给
用户(绝不重新固定可能已发生漂移的实时树)。(b) 先前的快照
目录仍然存在(默认保留 2 份),且其哨兵值与保留的
active_snapshot.snapshot_id 匹配:A 块第 2 步的哨兵检查会 SUCCEED
(它只比较哨兵文件与 SNAPSHOT_ID,不与当前 pass 比较)。
B 块的成对 discovery_commit 检查会将沿用的发现与带有相同过期 SNAPSHOT_ID 的新发现判定为 MATCH,
并静默丢弃为 DUPLICATE——这是一个错误的权威判定。
为防止 (b),在任何使用者阶段读取 active_snapshot 之前,
HARNESS MUST 保证 active_snapshot.pass == state.pass_number。
参考运行框架(mantis-meta-agent)通过每个 pass 都重新固定来满足这一要求(D 块第 0 步发现 active_snapshot.pass != N → 重新固定 → 在任何阶段运行前刷新
active_snapshot.pass),因此不会触发子情况 (b)。如果自定义运行框架在第 15 阶段递增 pass 后保留 active_snapshot,却不重新固定,则 MUST (a) 每个 pass 都重新固定(参考行为),或 (b) 在调用阶段前注入等效的阶段前门控,以刷新 active_snapshot.pass 或彻底清除 active_snapshot。阶段 CANNOT 通过 B 块自行检测此过期状态(B 块只检查 snapshot_id,不检查 pass):即使快照已过期,沿用的发现与带有相同过期 SNAPSHOT_ID 的新发现仍会在 B 块中判定为 MATCH。active_snapshot.pass 字段在 schema.json #/$defs/state/active_snapshot/pass 中定义,正是用于此检查。运行框架的 D 块第 0 步复用检查不能替代此项保证:它只会在同一 pass 重新进入时触发。(读取 active_snapshot 的阶段 MAY 额外自行进行防御性检查——见各阶段第 0 步的哨兵检查——但此项约束保证由运行框架负责。)
3. 固定失败(快照副本失败——磁盘已满、权限不足或目录树过大)——Block D 步骤 2(可用空间预检):比较实时目录树的 du -s 与 state_root 中 df 显示的可用空间;如果空间不足 → 跳过复制 → 转至步骤 5b。Block D 步骤 4(容错验证):检查复制退出状态,并进行合理性检查(文件数量/大小约为预期的 90%);失败时 → 转至步骤 5b(未固定/HALT)。步骤 5b:SNAPSHOT_ROOT=<live root>,snapshot_pinned=false,SNAPSHOT_ID="live:"+ISO8601。运行框架仍会写入 active_snapshot,并仍会向各阶段传递 --snapshot_root/--snapshot_id,以便它们收到 HALT 信号。随后,每个阶段都会采取保守处理:禁止给出权威判定(VERIFIED_SECURE、failed_to_reproduce、DUPLICATE、FALSE_POSITIVE、NON_VIABLE);Block B 始终返回 NOT_MATCHED;复现记录 not_attempted;补丁阶段能达到的最佳状态为 VERIFICATION_INCOMPLETE。
4. 已打补丁的影子目录(--target_root 指向预先修改过的目录树;Block A 中豁免哨兵检查的路径 1a)——mantis-patch 会向复现子 Agent 传递 --target_root=<PATCHED_SHADOW_ROOT> 和 --snapshot_pinned=false,以重新攻击验证。Block A 步骤 1a:CODE_ROOT = --target_root(权威覆盖项,会覆盖 --snapshot_root 和状态回退值)。Block A 步骤 2:跳过哨兵检查(--target_root 目录树经过刻意修改,豁免哨兵检查)。参数 --snapshot_pinned=false 表示豁免哨兵检查,不是 HALT 信号——应通过读取 STATE 来检测 HALT(active_snapshot.snapshot_id 以 live: 开头,等同于状态中的 active_snapshot.snapshot_pinned 为 false),切勿根据本次调用传入的参数来判断。发现项的 discovery_commit 不受影响——它会保留发现时所在轮次的 SNAPSHOT_ID;只有 --snapshot_pinned=false 参数仅适用于本次重新攻击调用。
5. 不同快照中的重复候选项(跨轮次去重,discovery_commit 不同——即 Block B 成对检查的 NOT_MATCHED 路径)——两轮都已正确固定快照;这些发现项只是来自不同的快照。mantis-dedupe 的 Block B 成对检查会将当前发现项的 discovery_commit 与已归档发现项的 discovery_commit 进行比较(而非与全局 SNAPSHOT_ID 比较)。如果两者不同 → NOT_MATCHED。NOT_MATCHED 会使当前发现项保持 ACTIVE,并设置 possible_duplicate_of(一种非终结性的软提示——不会过滤或丢弃该发现项)。如果已归档发现项已 RESOLVED(patch_status 为 {VERIFIED_SECURE、MITIGATION_PROPOSED},或 status==FALSE_POSITIVE,或 production_viability==NON_VIABLE),且这对发现项的结果为 NOT_MATCHED → 可能回归:保持 ACTIVE,添加历史记录,绝不进行过滤(在新代码中重新发现的已回退修复绝不能被丢弃)。
6. 缺少 sink 证据(Block F — PoC 编译成功,但没有产生已到达 sink 的证据;not_attempted 与 failed_to_reproduce 的区别)— mantis-reproduce Block F:如果 EVIDENCE 缺失(任何编译器/构建非零退出、退出码 127 表示找不到命令、退出码 2 表示“没有这样的文件”,或从未到达 sink)→ repro_status = not_attempted(可重试),停止。绝不能使用 failed_to_reproduce。在 --reattack 模式下:保持 reattack_status 未设置,并添加历史记录说明“setup_failed”——绝不能使用 failed_to_bypass。failed_to_reproduce 仅适用于能够确证测试框架已到达存在漏洞的入口点的情况——即有已到达 sink 的证据,而非环境设置证据——但漏洞未触发。已到达 sink 的证据必须来自被调用路径内部,或来自目标生成的跟踪/回溯:(a)PoC 脚本/源代码测试框架在 sink 调用之前,且在其自身执行流程中,将 MANTIS_REACHED_ENTRYPOINT 写入 sidecar 文件(标记写入是被调用路径的一部分,并非启动前步骤);或(b)对于二进制/固件/原始负载目标,捕获到的崩溃回溯或消毒器跟踪(ASan/UBSan/MSan/TSan)明确指出目标 sink 函数(目标生成的跟踪)。外部包装器在调用目标之前写入的标记仅属于环境设置证据(只能证明“已尝试启动”,不能证明“已到达 sink”),单凭它不足以使用 failed_to_reproduce——在判定门控中应将其视为 EVIDENCE 缺失。证据记录在 repro_hints 中。在 HALT 模式下,HALT 上限还会强制使用 not_attempted(不得使用 failed_to_reproduce),因为无法信任未固定代码树上的负面结果具有权威性。
6. 大型代码库的语义检索(RAG)
对于小型代码库,规划器可以手动扫描 workspace/kb/index.md,研究人员可以通过 grep 搜索调用点。随着规模增大(数千个文件、深层目录树、多轮活动),这些方法会遗漏相关上下文,并浪费 token 阅读无关文件。语义检索层使规划器和研究人员能够查询相关 KB 条目和代码位置,而无需阅读所有内容。
支持两种实现,它们共享相同的数据契约:
- 选项 A(默认 — 基于 Skill): 使用专用 skill 对
chunks.jsonl运行 BM25/TF-IDF 辅助脚本。零外部依赖——可在隔离网络环境中运行,无需向量嵌入或向量存储。若可用,也可选择支持向量嵌入。 - 选项 B(最大规模 — 基于 MCP): 测试框架使用向量嵌入维护持久化向量索引,并提供持久化的
semantic_search_kb/semantic_search_codeMCP 工具。更适合规模极大的代码库,因为逐次调用运行 BM25 过慢。
两种方式都需要选择启用。现有 skills 不作修改;规划器和研究人员会收到运行时指令,使用可用的检索机制。如果两者都不可用,则回退到当前的手动操作方式。检索结果仅作为覆盖范围提示——用于决定排序和优先级,绝不能决定审计集合的成员资格。检索未命中绝不能导致跳过或删除文件、调用点或调查项。
A. 共享数据契约:chunks.jsonl
Stage 2(/mantis-architecture)完成后,分块内容会提取到
workspace/kb/chunks.jsonl(每行一个 JSON 对象)。Harness 可以事后读取
workspace/kb/*.md 来完成此操作,也可以指示架构技能在综合时将其写入,作为纯文本副作用。生成两种分块:
-
知识库分块,来自现有的
workspace/kb/*.md文件:{"id": "auth_module:0", "source_file": "workspace/kb/entities/auth_module.md", "entity_type": "entity", "chunk_text": "The auth module handles..."} -
代码分块,来自
CODE_ROOT(固定快照)。每个分块都包含文件路径和行范围,以便研究员从快照中请求特定文件:{"id": "src/parser.c:0", "source_file": "src/parser.c", "start_line": 1, "end_line": 80, "chunk_text": "int parse_input(..."}
chunks.jsonl 的第一行是来源标头,记录这些分块基于哪个 SNAPSHOT_ID 构建:
{"_provenance": true, "snapshot_id": "abc123", "kb_snapshot_id": "abc123"}
提供查询服务前,请将来源标头中的 snapshot_id 与当前的
SNAPSHOT_ID 对照;如果两者不同,则重新构建。在 MODE-OFF(没有
active_snapshot)模式下,永远不会设置 kb_snapshot_id — 跳过整个索引,让技能回退到手动扫描。绝不要从实时目录树构建代码分块 — 分块必须反映技能正在读取的固定副本。
B. 选项 A:基于技能的检索(默认 — 无需基础设施)
专用技能读取 chunks.jsonl,并编写和运行辅助脚本(例如
workspace/helpers/search_chunks.py),执行 BM25/TF-IDF 相似度搜索。该脚本由 Agent 在运行时生成 — 技能不附带任何代码(与
mantis-dedupe 的 merge_findings.py 采用相同模式)。这不需要任何外部依赖 — 无需嵌入模型、向量存储或 MCP 服务。它适用于气隙环境和 VPC-SC 环境。
此技能的完整参考蓝图见
references/mantis-kb-query.md。构建者可以
根据自己的环境进行调整。蓝图包含 Block A(定位器解析)、分块来源检查、带版本号的辅助脚本契约
(MANTIS_HELPER_VERSION = 1)以及 JSON 输出架构。
- **调用:**规划器或研究员将技能作为子 Agent 启动,并传入查询字符串。技能会在辅助脚本尚不存在时创建该脚本,运行脚本,并以 JSON 格式返回排名前 K 的匹配分块。
- **可选嵌入:**如果有向量嵌入可用,可以指示 Agent 使用余弦相似度而非 BM25。这是运行时配置开关,而非不同的技能。
- **快照安全:**技能通过 Block A 从状态中读取
active_snapshot(与其他所有技能相同),并在提供服务前检查分块来源。
C. 选项 B:基于 MCP 的检索(适用于最大规模场景)
对于每次调用时执行 BM25 速度过慢的超大型代码库,Harness 可以使用向量嵌入维护持久化向量索引,并提供两个 MCP 工具 (遵循指南 2 中为虚拟机/硬件定制 MCP 的相同模式):
-
semantic_search_kb(query: string) → [{id, source_file, entity_type, chunk_text, score}]— 搜索知识库分块。返回相关的实体/漏洞 Markdown 上下文。 -
semantic_search_code(query: string) → [{file, start_line, end_line, snippet, score}]— 搜索来自固定快照的代码分块。返回相关代码位置。
Harness 负责管理向量索引的生命周期:从 chunks.jsonl(或直接从
CODE_ROOT)构建索引,在 SNAPSHOT_ID 变化时重新构建,并处理新鲜度检查。在 HALT 模式下,提供带有 STALE 标志的结果,或拒绝提供。在 MODE-OFF 模式下,完全跳过。
D. 各技能的增强指导
当有检索机制(技能或 MCP)可用时,请指示以下技能使用它。这些是运行时指令,由 harness 或 meta-agent 在调用技能时传递——不会修改技能文件本身:
-
mantis-architecture: 无需更改。架构师完成 Stage 2 后,harness 会对现有的
workspace/kb/*.md文件进行分块。如果构建者倾向于这样做,也可以指示架构师在综合阶段(Step 3)同时写入workspace/kb/chunks.jsonl,作为纯文本的附带操作——但这不是必需的,因为 harness 可以事后提取分块。 -
mantis-plan: 如果检索机制可用,请指示规划者使用它为每项调查查找
kb_references,而不是只手动扫描workspace/kb/index.md。对于每项调查,使用调查标题和目标文件名进行查询,然后将排名靠前的 K 个匹配 KB 实体/漏洞文件添加到kb_references数组中。如果没有可用的检索机制,则仍以手动扫描index.md作为后备方案。 -
mantis-researcher: 如果检索机制可用,请指示 Wave 1 子 Agent 使用它来优先查找相关调用点和流入接收点的跨模块数据流(例如,“解析器模块中,不可信输入在哪里到达
memcpy”)。语义搜索仅作为排序提示来补充 grep——它只决定顺序,绝不决定审计集的成员。它绝不能替代穷举式 Step-3 调用点扫描;完整 grep 能找到的每个调用点或数据流,无论是否排入前 K 名,都必须经过审计。对 grep 结果与语义搜索结果的并集进行审计。研究者现有的 Wave 1/Wave 2 结构保持不变。
E. 快照安全
无论由技能还是 harness 提供检索索引,它都是固定快照的缓存,绝不是实时视图:
- 从
CODE_ROOT(固定快照)构建代码分块,而不是从实时代码树构建。 - 当
SNAPSHOT_ID变化时(新一轮、新固定快照),重新构建。 - 在 HALT 模式(
snapshot_pinned=false)下,提供带有STALE标记的结果,或拒绝提供结果——采用与其他阶段相同的保守降级方式。 - 在 MODE-OFF 下,完全跳过索引。
7. 基于 Embedding 的去重预筛选
当流水线在大型代码库上运行多轮时,去重器(/mantis-dedupe)必须将每个当前发现与所有已归档发现进行比较——由大模型读取摘要执行 O(n×m) 比较。大规模情况下(多轮中积累数百条发现),这会消耗大量 token,且速度缓慢。
在调用 /mantis-dedupe 之前,harness 可以使用 Embedding 作为快速预筛选,缩小候选范围。技能现有的确定性匹配规则(code_paths + title + discovery_commit)仍是硬性去重判断的唯一依据。
这完全在 harness 侧进行,且为可选功能。 不会修改 /mantis-dedupe。
A. 工作原理
-
**Harness Action:**读取所有
workspace/findings/*.json(当前)和workspace/archive/findings_pass_*/*.json(已归档)。针对每条发现, 根据标准化的文本表示计算嵌入向量(例如,title + description + first code_paths entry with line stripped)。 -
**Harness Action:**计算当前发现与已归档发现之间的成对余弦相似度。筛选出高于可配置阈值 (例如,0.85)的候选对。
-
**Harness Action:**写入候选对清单(例如,
workspace/helpers/dedup_candidates.json),其中包含 UUID 对和相似度分数。 -
**mantis-dedupe 调用:**Harness 按照常规方式调用
/mantis-dedupe。 如果候选清单存在,则指示该技能读取清单,并优先将其中的候选对交由大模型进行成对比较,而不是 将每条发现与每条已归档发现逐一比较。所有现有的确定性匹配规则均保持不变——清单只会缩小 搜索范围。
B. 安全防护措施
-
**仅用于预筛选,绝不用于判定。**嵌入向量相似度分数绝不能导致判定为
DUPLICATE、移入垃圾箱,或 设置possible_duplicate_of。只有该技能现有的code_paths、title和discovery_commit检查才能做出这些判定。预筛选漏掉候选只会导致重复项被过度保留(安全——大模型会看到它并跳过);绝不会 导致保留不足(不会漏掉真实的重复项)。 -
**不产生假阴性。**阈值应设置得足够低(例如,0.75),以避免漏掉真正的重复项。 宁可筛选出过多候选,也不要漏掉真正的重复项——大模型和确定性匹配会过滤掉误报。
-
**失败时回退。**如果无法计算嵌入向量、候选清单不存在,或发生任何错误,
/mantis-dedupe都会回退到 现有的 O(n×m) 比较方式。如果清单缺失,该技能不得停止或报错。 -
**感知快照差异。**对于
discovery_commit值不同的发现,Harness 不应在未标记为跨快照候选的情况下计算嵌入向量——该技能的 B 块成对检查会负责做出最终的 MATCHED/NOT_MATCHED 判定。
C. 共享基础设施
如果构建者也实现了指导原则 6(语义检索),请复用相同的向量嵌入基础设施来计算发现的嵌入向量。发现的嵌入内容 不同(发现 JSON,而非知识库块),但同一嵌入能力可以同时服务于两者。
D. 企业级向量架构与云可扩展性
对于需要在分布式代码库和多租户审计流水线中跟踪数十万项漏洞的企业部署,可以将 SQLite 向量存储替换为托管云向量引擎:
- Cloud Spanner Vector Search:
- *最适合:*需要全球 ACID 一致性、99.999% 可用性以及同步发现项溯源跟踪的关键任务型企业流水线。
- *架构:*在 Spanner 中存储发现项和
lineage_vectors,并使用ARRAY<FLOAT32>向量列。在并行扫描过程中,利用COSINE_DISTANCE和 KNN 搜索索引实时去重发现项。
- Cloud SQL for PostgreSQL(
pgvector):- *最适合:*需要符合 ACID 要求且运维复杂度较低的标准企业关系型后端。
- *架构:*启用
vector扩展。在vector(768)或vector(256)列中存储发现项嵌入,并使用 HNSW(vector_cosine_ops)或 IVFFlat 索引执行亚毫秒级相似性查询。
- AlloyDB for PostgreSQL:
- *最适合:*运行并发研究轮次的高吞吐量多 Agent 审计集群。
- *架构:*利用 AlloyDB 的列式向量引擎和基于 ScaNN 的近似最近邻索引,相较于标准 PostgreSQL,向量查询速度最高可提升 10 倍。
- BigQuery Vector Search:
- *最适合:*批量分析处理、组织范围的威胁情报聚类以及跨活动漏洞溯源分析。
- *架构:*将发现项嵌入导入 BigQuery,并使用
COSINE距离执行VECTOR_SEARCH(TABLE findings, 'embedding', ...),以实现无服务器批量去重和历史回归分析。
8. SAST 种子导入(外部工具接入)
Mantis 的发现引擎完全由 LLM 生成(grep 集群 + 推理)。能力较弱的 LLM 可能无法从结构上充分检测整程序范围的污点类别(注入、路径遍历、反序列化、UAF、格式字符串),而成熟的 SAST 工具(CodeQL、Semgrep-taint)会将其编码为跨过程查询。SAST 种子导入适配器会将外部工具的发现结果导入为 PROVISIONALLY_VALID / NEEDS_RESEARCH 候选项,这些候选项必须通过原有的下游关卡才能获得最终判定。这一机制纯粹是增量式的(强化 INV-2)——它扩大检测范围,但不会削弱任何验证关卡。
这完全遵循指南 6 中的 RAG 模式:选择启用、默认关闭、追踪来源、感知快照、失败时回退。
与平台无关的 IR(非 SARIF): 适配器不会绑定到 SARIF(这是一种复杂且依赖特定工具的格式),而是使用精简的 JSONL 中间表示(IR)。任何 SAST 工具的输出(SARIF、Semgrep JSON、Bandit JSON 等)都可以通过轻量包装器转换为此 IR。这最大限度地提高了平台无关性——任何能生成简单 JSONL 格式的工具都可以与该适配器配合使用。
支持两种实现,它们共用相同的数据契约:
- 选项 A(默认 — 基于技能): 专用技能(
/mantis-sast-seed)读取 IR,并利用 LLM 推理将发现结果规范化为 mantis 发现 JSON。在 CODE_ROOT 下,LLM 会读取报告中每个位置的实际源代码以验证发现结果,并通过根因分析丰富描述。无需外部依赖——可在气隙环境中运行。 - 选项 B(最大控制 — 基于 Harness): Harness 使用确定性代码(例如 SARIF 到发现结果的转换脚本)将 SAST 输出直接规范化为发现 JSON,从而绕过 LLM 完成规范化步骤。Harness 会在调用
/mantis-dedupe前,将发现 JSON 写入workspace/findings/。
两种方式都需要选择启用。现有技能不会被修改。导入的发现结果会与研究人员的发现结果一同进入 workspace/findings/,并经过原有的下游关卡(去重 -> 审查 -> 评论审查 -> 复现 -> 修复 -> 校准)。
完整的参考蓝图见 references/mantis-sast-seed.md。
A. 共享数据契约:sast_findings.jsonl
IR 是位于 workspace/sast_findings.jsonl 的 JSONL 文件(相对于 STATE)。它遵循与 chunks.jsonl(指南 6A)相同的来源标头模式。
第 1 行 — 来源标头:
{"_provenance": true, "scan_snapshot_id": "abc123def456", "tool": "codeql", "tool_version": "2.15.0", "scan_timestamp": "2026-07-22T10:00:00Z"}
scan_snapshot_id:运行扫描所针对的 SNAPSHOT_ID。这是主要来源锚点——逐字节与当前轮次的SNAPSHOT_ID比较(与区块 B 中的比较相同)。如果执行框架针对固定的 CODE_ROOT 运行 SAST 工具,则会将此字段设为SNAPSHOT_ID。tool:工具名称(例如codeql、semgrep、bandit)。仅供参考。tool_version:工具版本。仅供参考。scan_timestamp:ISO 8601 格式。仅供参考。
第 2 行及之后 — 每行一条发现:
{"rule_id": "cpp/sql-injection", "rule_name": "SQL injection", "cwe": "CWE-89", "severity": "HIGH", "code_paths": ["src/db/query.c:42"], "message": "User input flows into SQL query without sanitization"}
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
rule_id | string | 是 | 工具特定的规则标识符 |
severity | string | 是 | CRITICAL、HIGH、MEDIUM、LOW(Mantis 级别) |
code_paths | array | 是 | "file:line" 字符串数组(相对于 SNAPSHOT) |
message | string | 是 | 原始 SAST 发现消息 |
rule_name | string | 否 | 易于理解的规则名称 |
cwe | string | 否 | CWE 标识符(例如 CWE-89) |
IR 转换(执行框架负责): 执行框架会在调用适配器之前,将 SAST 工具的输出转换为此 IR。转换示例:
- SARIF:提取
ruleId,将level映射为严重级别(error->HIGH、warning->MEDIUM、note->LOW),将locations提取为code_paths,复制message.text。 - Semgrep JSON:提取
check_id作为rule_id,将extra.severity映射为 Mantis 严重级别,将path:start.line提取为code_paths,复制extra.message。
B. 选项 A:基于技能的摄取(默认 — 无需基础设施)
专用技能读取 sast_findings.jsonl、应用允许列表、验证来源、计算 signature/lineage_id/discovery_commit,并写入发现 JSON。LLM 会读取 CODE_ROOT 下每个报告位置的实际源代码,以验证发现并补充描述。
- 调用: 执行框架在第 6 阶段(研究)之后、第 7 阶段(去重)之前,使用
--snapshot_root/--snapshot_id/--state_root调用/mantis-sast-seed。种子发现会在/mantis-dedupe运行之前写入workspace/findings/。 - 接线前不生效: 如果缺少
sast_findings.jsonl,技能不会输出任何内容,并会通知调用方。它绝不会失败——只会返回空结果。 - 防止幻觉: LLM 在写入发现 JSON 前,必须读取每个报告位置的实际代码。它不得编造 SAST 输出中不存在的发现。
sast_provenance.line_verified字段记录验证是否成功。 - 快照安全: 技能通过区块 A 从状态中读取
active_snapshot,并且仅当快照已固定且发现的位置已在 CODE_ROOT 下验证时,才写入discovery_commit。
C. 选项 B:基于执行框架的摄取(用于确定性摄取)
为实现最高确定性,执行框架可以使用确定性代码将 SAST 输出规范化为发现 JSON。此方式在规范化步骤中绕过 LLM:
- 执行框架操作: 读取 SAST 工具输出,以确定性方式解析,并将发现 JSON 写入
workspace/findings/。 - 执行框架操作: 仅当能够证明扫描针对固定的 CODE_ROOT 运行时,才写入
discovery_commit。 - 执行框架操作: 应用允许列表筛选器。
- 调用 mantis-dedupe: 按常规流程继续——种子发现与研究人员发现无法区分。
D. 来源验证
仅当能够证明扫描针对与固定 CODE_ROOT 行内容完全一致的目录运行时,适配器才会写入 discovery_commit:
- 从
workspace/.mantis_state.json读取active_snapshot(通过 Block A)。如果不存在,则为 MODE-OFF,跳至步骤 5。 - 如果
snapshot_pinned为 false,则为 HALT,跳至步骤 6。 - 读取 IR 来源标头中的
scan_snapshot_id。 - VERIFIED:
scan_snapshot_id存在且与SNAPSHOT_ID完全一致。写入discovery_commit = SNAPSHOT_ID。状态 =PROVISIONALLY_VALID。 - MODE-OFF:
active_snapshot不存在。省略discovery_commit。状态 =PROVISIONALLY_VALID(MODE-OFF 允许所有判定结果)。 - HALT:
snapshot_pinned为 false。省略discovery_commit。状态 =NEEDS_RESEARCH。 - DRIFT:
scan_snapshot_id存在但与之不同。完全省略discovery_commit。状态 =NEEDS_RESEARCH。 - UNVERIFIED:
scan_snapshot_id不存在。省略discovery_commit。状态 =NEEDS_RESEARCH。
行存在性验证(当状态为 VERIFIED 或 DRIFT 且 CODE_ROOT 已解析时执行的额外检查):对每个发现,验证每个 code_paths 条目:去掉末尾的 :line,检查 CODE_ROOT 下是否存在该文件,并检查行号是否在文件行数范围内。如果文件缺失或行号超出范围,则降级为 DRIFT(省略 discovery_commit,状态 = NEEDS_RESEARCH)。
这与 discovery_commit(schema.json)以及 signature/lineage_id 使用的“UNTRUSTED-IF-ABSENT”模式完全相同。
E. 允许列表与噪声控制
workspace/sast_allowlist.json(可选配置文件,相对于 STATE):
{
"enabled": true,
"severity_filter": ["CRITICAL", "HIGH"],
"cwe_allowlist": {
"enabled": true,
"cwes": ["CWE-89", "CWE-78", "CWE-79", "CWE-22", "CWE-787", "CWE-416", "CWE-502"]
},
"rule_allowlist": {
"enabled": false,
"rules": []
},
"per_rule_cap": 5,
"total_cap": 50
}
如果配置文件不存在,则采用默认值:仅 CRITICAL+HIGH,per_rule_cap=5,total_cap=50。
**允许列表如何保护重试上限:**重现阶段(/mantis-reproduce)对每个发现最多允许 6 次尝试(绝对上限,永不重置)。如果未经筛选就加入 1000 条 SAST 发现,重现阶段最多需要尝试 6000 次,耗尽重试预算。允许列表筛选链(严重性筛选 -> CWE/规则筛选 -> 每条规则上限 -> 总数上限)确保只有数量受限且信号强的候选项进入流水线。审查阶段(13 条规则的负向筛选)和评审阶段(生产可行性)会在重现阶段运行前进一步筛选。
F. 各技能的增强指南
当 SAST 种子技能可用时,指示执行框架在第 6 阶段(研究)和第 7 阶段(去重)之间调用它。这些是由执行框架传递的运行时指令,不会修改技能文件本身:
- **mantis-meta-agent:**在
/mantis-researcher完成后、/mantis-dedupe之前,调用/mantis-sast-seed,并传入--snapshot_root/--snapshot_id/--state_root。 - **mantis-dedupe:**无需更改。种子发现与研究者发现一同位于
workspace/findings/中。去重会以相同方式处理它们(基于签名的匹配、Block B 两两检查)。 - **mantis-review:**无需更改。13 条规则的负向筛选同样适用于种子发现。
- **mantis-report:**无需更改。
sast_provenance字段仅供参考,可在报告中展示。
G. 快照安全性
SAST 种子适配器严格遵循代码读取类技能所用的 Block A(定位符解析):
- 从
--snapshot_root/ 状态中的active_snapshot解析 CODE_ROOT。 - 遵循哨兵检查(Block A 步骤 2)。
- 在 CODE_ROOT 下读取源文件(相对于快照),以验证行是否存在。
- 将发现结果写入
state_root/workspace/findings/(相对于状态)。 - 固定快照时,绝不写入 CODE_ROOT。
- 在 MODE-OFF 中:无需
discovery_commit即可继续。允许所有判定结果。 - 在 HALT 中:省略
discovery_commit。种子发现结果标记为NEEDS_RESEARCH。 - 在 PINNED 中:验证每项发现结果的位置是否位于 CODE_ROOT 下;若验证通过,则将
discovery_commit设为SNAPSHOT_ID。
SAST 工具的输出本身不具备快照感知能力——它可能是针对不同代码树生成的。适配器的来源验证负责弥合这一差距:它会在写入 discovery_commit 前,针对固定的 CODE_ROOT 重新核验每项发现结果。
H. 安全防护措施
- 仅作增补。 种子发现结果是
PROVISIONALLY_VALID/NEEDS_RESEARCH候选项。它们必须通过未经改动的下游关卡:去重(Block B)、审查(13 条规则筛选)、批判审查(可行性)、复现(Block F 的到达汇点证据 + HALT 上限)、补丁(Block G 重新攻击)、校准(合理性上限)。任何关卡都不会放宽。 - 不会错误标记为
VERIFIED_SECURE。 种子发现结果初始状态为PROVISIONALLY_VALID——未经完整的补丁 + 重新攻击流程,绝不可能达到VERIFIED_SECURE。 - 不会错误标记为
failed_to_reproduce。 进入复现阶段的种子发现结果仍须满足相同的 Block F 证据关卡和 HALT 上限。 - 不会丢弃回归问题。 如果 SAST 种子发现结果与
discovery_commit不同的已归档发现结果匹配,Block B 会返回 NOT_MATCHED ->possible_duplicate_of-> 该发现结果保持有效。 - 缺少数据时采取故障安全措施。 如果不存在
sast_findings.jsonl,则不会写入任何发现结果。如果某项发现结果无法验证,则标记为NEEDS_RESEARCH。 - 不修改现有技能。 适配器会在运行
/mantis-dedupe前,将发现结果写入workspace/findings/。 sast_provenance仅供参考。 它不会影响任何安全关键不变量、关卡或判定结果。决定 Block B 快照匹配的是发现结果的discovery_commit字段。
9. 结构化代码索引(AST 级上下文)
对于小型代码仓库,研究人员可以通过 grep 查找调用点,规划器可以推断依赖关系。对于大型代码仓库,基于 grep 的调用点发现并不可靠(会漏掉间接调用,无法区分调用与注释或字符串,也无法识别函数边界)。结构化代码索引可提供 AST 级上下文(函数边界、调用图、符号表),提升发现阶段大模型推理的质量。
这遵循指南 6 中的 RAG 模式:可选、追踪来源、感知快照,并在失败时回退。结构化索引仅为覆盖率提示——用于决定顺序和优先级,绝不决定审计集合的成员。漏检绝不能导致跳过或丢弃文件、调用点或调查项。
完整规范——包括清单架构、SQLite 服务存储、基于能力的分区后端选择、规范符号 ID、查询接口、基线加增量覆盖层、确定性部分覆盖以及安全防护措施——集中保存在唯一可信来源中:
→ ../mantis-structural-index/SKILL.md
精简版参考蓝图见 references/mantis-structural-index.md。
支持两种实现,且共用相同的查询约定:
- 选项 A(默认 — 基于 Skill):
mantis-structural-indexskill 会生成并运行辅助脚本(build_structural_index.py和query_structural_index.py,两者均为# MANTIS_HELPER_VERSION = 5),采用 基于能力的分区后端选择,并在能力不足时回退到 grep。 - 选项 B(能力最强 — 基于 MCP): harness 负责维护持久化的结构化索引,提供
find_callers(symbol)、find_callees(function)、get_function_boundary(file, line)MCP 工具,并由相同的 SQLite 服务存储提供支持。
两种实现都可选。不符合规范的 harness 只需跳过结构化索引阶段。结构化索引仅作为 grep 的排名提示——只决定顺序,绝不决定审计集合的成员。
使用者必须通过查询接口(query_structural_index.py)进行查询,而不是直接筛选 JSONL。查询接口可提供有界结果、分页、明确的名称解析、精度和后端元数据,以及空结果的覆盖率信息。
D. 各 Skill 的增强指引
结构化索引可用时,应指示以下 skill 使用该索引。 这些是使用约定——由 harness 传递的运行时指令。结构化索引仅是提示性增强;不使用它的 skill,其行为与当前完全一致:
- mantis-architecture: 在 KB 综合整理期间,可选择读取预先构建的结构化索引(由
mantis-structural-index在 Stage 0.5 构建),并与dependencies.json交叉引用。 - mantis-plan: 使用结构化索引获取函数级依赖扇出信息(比文件级的
dependencies.json更精确)。 - mantis-researcher: Wave 1 子 Agent 使用
find_callers()补充 grep,为调用点发现提供排名提示——只决定顺序,绝不决定成员资格。绝不能用它 替代详尽的 Step-3 调用点扫描;完整 grep 能找到的每个调用点都必须经过审计, 无论它是否在结构化索引中排名靠前。审计 grep 结果与结构化索引结果的并集。Wave 2 深入审计者使用get_function_boundary()从所在函数开始,并根据需要扩展到调用方、被调用方或文件,以获取 跨函数上下文。研究人员现有的 Wave 1/Wave 2 结构保持不变。
E. 与 RAG 集成(指南 6)
- 可以将结构索引条目作为
entity_type: "structural"分块添加到chunks.jsonl中。 - 利用结构索引中的函数边界,可以让代码分块与函数边界对齐(而不是机械地按行范围切片)。
- 如果结构索引和 RAG 索引都已实现,可以共用同一套向量嵌入基础设施。
10. 分层迭代复现与多轮对话重试策略
对于复杂服务,直接针对完整的沙盒服务进行一次性复现,往往会遭遇较高的搜索熵、脆弱的配置以及难以调试的故障。分层策略将复现拆分为逐步推进的里程碑,而跨对话重试架构则可避免推理陷入僵局和上下文膨胀。
A. 编排与跨对话重试
-
对话内重试(本地 Agent 执行轨迹):
- 活跃的子 Agent 对话会在其上下文窗口内本地重试 2–3 次,以调整参数、修复设置问题或完善载荷。
-
跨对话重试(全新上下文 + 累积的产物):
- 触发条件:如果对话内重试未能达到 Tier 3(
reproduced),编排器会终止卡住的对话,并启动一个新的子 Agent 对话(使用全新的上下文窗口)。 - **提供上下文:**编排器会使用
state_root/workspace/archive/.repro_attempts.json中的结构化尝试数据,以及workspace/learnings.jsonl中的执行轨迹经验(例如,“尝试 1 因缺少认证标头 X 而失败;尝试 2 证明解析器会移除未转义的引号”)来填充新提示词。 - **优点:**避免上下文膨胀和推理惯性(“幻觉陷阱”),让新的 Agent 能够利用先前的实证观察解决问题,而不重蹈覆辙。
- 触发条件:如果对话内重试未能达到 Tier 3(
-
尝试次数上限的统计与计算:
- 编排器会维护
state_root/workspace/archive/.repro_attempts.json。 - **仅 Tier 3 会增加计数:**只有 Tier 3 的完整沙盒服务执行(或完整端到端复现器运行)才会增加每个发现对应的尝试次数,计入 6 次的绝对硬上限。
- **试探性子预算:**内部 Tier 1 和 Tier 2 试运行受本地子预算限制(每次对话最多执行 3 次试运行),不会占用绝对的 6 次尝试上限。
- 编排器会维护
B. 由 Harness 强制执行的 Tier 4(预发布与生产前环境执行)
为防止在实时基础设施上执行未经把关的漏洞利用,Tier 4(预发布/生产前验证)必须由程序化编排器 Harness 严格负责并强制执行,绝不能由大模型自行决定:
- 沙盒边界:
mantis-reproduce严格在隔离的本地沙盒中执行(Tier 1–3),并在 Tier 3(reproduced/failed_to_reproduce)结束。 - 确定性关卡:Harness 会拦截 Tier 3 的
reproduced判定。如果已配置实时/预发布验证,Harness 不得自动调用远程执行,而必须强制执行程序化的人在回路关卡:- 提示人工操作员进行明确的交互式确认,或
- 要求提供经加密签名的批准令牌/授权回调。
- **默认拒绝:**如果缺少人工批准或批准被拒绝,则跳过 Tier 4,并以 Tier 3 的沙盒判定为准。
C. 本地入口/中间件边缘注释(Tier 3 沙箱验证后)
为避免默认边缘过滤器导致的误报(“在 localhost:8080 上可运行,但会被 WAF/代理拦截”),编排器可以选择通过在本地沙箱中运行的反向代理或 API 网关(例如 NGINX、Envoy、ModSecurity)执行 Tier 3 PoC:
- 仅添加注释: 本地中间件拦截的载荷不得将 Tier 3 的
reproduced判定降级为failed_to_reproduce。 - Critic 集成: 测试框架会在发现的
repro_hints或历史记录中记录ingress_blocked: true(或边缘过滤器详情)。这为/mantis-critic提供实证依据,使其能够将production_viability判定为"CONDITIONAL_VIABLE"(默认边缘代理配置可缓解)。