mcpField
M
mantis-plan

mantis-plan

github.com/google安全2.7k1.6k 次安装3 天前更新
代码仓库

关于 mantis-plan

mantis-plan 是安全审查规划技能,根据代码结构、威胁模型和历史问题梳理边界并安排定向调查。它既支持首次全面盘点,也可利用累积的审查记录制定后续计划。

主要功能

  1. 01审阅威胁模型背景
  2. 02盘点生产源码
  3. 03检查历史问题与重试情况
  4. 04跟踪各轮次间的文件变化
  5. 05生成定向调查计划

适用场景

  1. 01为陌生代码库制定初始审查计划
  2. 02依据历史问题和代码变更安排后续审查

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/google/mantis --skill mantis-plan

安装后在 Claude Code 中输入/mantis-plan确认已加载。

详细介绍

策略师(/mantis-plan)

系统目标

安全架构师。分析代码结构、目录元数据和历史记录,以绘制外部边界并制定自适应审查路线图。

命令定义

  • 命令: /mantis-plan
  • 描述: 根据当前威胁模型和历史经验,制定有针对性的防御性安全审查计划。
  • 参数(可选;由编排器提供,供 Block A 使用):
    • --snapshot_root / SNAPSHOT_ROOT:固定的只读代码快照的绝对路径(所有相对于快照的路径均以 CODE_ROOT 为根)。
    • --snapshot_id / SNAPSHOT_ID:本轮快照标识符(哨兵 + Block B 比较)。
    • --state_root:workspace/ 状态目录的绝对路径(plan.json、.mantis_state.json、findings/、kb/、archive/)。相对于状态目录 — 绝不以 CODE_ROOT 为前缀。
    • 所有标志均缺省 -> MODE-OFF/旧版模式(Block A 步骤 1d):行为与当前完全相同。

输入/输出约定

  • 读取:
    • workspace/.mantis_state.json(用于跟踪当前循环轮次)。
    • workspace/kb/THREAT_MODEL.md(如果存在)。
    • workspace/kb/index.md(检查其是否存在,以确定 Mode A 还是 Mode B)。
    • Mode A:遍历生产目录和源文件,读取 mantis-summary.md(如果可用)。
    • Mode B:读取 workspace/kb/index.md、workspace/kb/THREAT_MODEL.md、workspace/archive/.repro_attempts.json(如果存在)、版本控制系统(VCS)差异或文件时间戳/哈希值。
    • workspace/kb/structural_index/manifest.json(用于检查结构索引的可用性/状态)。
    • workspace/helpers/query_structural_index.py(用于调用有界结构索引查询)。
    • workspace/.mantis_state.json 新字段: active_snapshot.{snapshot_id, snapshot_pinned, vcs_type}、 snapshot_history(由元 Agent 读取和写入)。读取 vcs_type 是因为 Block E 会根据它分支。Plan 在实时仓库根目录运行 Block E,以计算 changed_files / changed_files_status(COMPUTED 或 UNKNOWN),并将其写回状态。
  • 写入:
    • workspace/plan.json。
    • 将符合重试条件的发现 JSON 文件从 workspace/archive/findings_pass_K/ 或 workspace/archive/loopK_findings/ (K 为其归档时所在的轮次)复制到 workspace/findings/ (保留其原始 UUID 文件名)。
  • 前提条件:
    • 代码库必须可访问。
  • 幂等性保证:
    • 直接覆盖 workspace/plan.json。在 Mode B 中,仅当 Block B 为 MATCHED 且文件未更改并存在时,才会原样复制发现文件;否则会安排重新发现调查。按照缓存读取规则查询 .repro_attempts.json。

说明

步骤 0:定位符解析(先于其他所有操作执行)
LOCATOR RESOLUTION (before reading ANY target code or artifact):
0. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
   you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
   state for provenance/annotation; NEVER stop merely because a code root is unset.
1. Determine CODE_ROOT, in this priority order:
   a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
      It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
      (used when a caller hands you a prepared tree, e.g. a patched shadow).
   b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
   c. Else read state_root/workspace/.mantis_state.json (state_root from
      --state_root if passed, else ./workspace/... relative to the current dir)
      -> active_snapshot.root / .snapshot_id / .snapshot_pinned.
   d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
      treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
2. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
   verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
   or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
   deliberately mutated and is sentinel-EXEMPT.)
3. PATH FIELDS:
   - SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
     that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
     containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
     NOT of the form <existing-path>:<integer> is a non-source LOCATOR
     (symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
     line-range and line-existence logic.
   - STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
     kb_references, repro_file_path, reattack_file_path, helper scripts, report
     files, and all state/findings JSON.
4. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
   compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
   (mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
   cd into CODE_ROOT.
5. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
   run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
   (the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
   lacks .git/.hg/.repo.
6. Every shell command uses ABSOLUTE paths and sets its own working directory on
   that call. Do NOT assume the working directory persists between calls.

说明

**当前轮次检查(防御性检查;绑定保证由 mantis-pipeline-adapter Scenario 2 中的 harness 提供):**如果存在 active_snapshot,且 active_snapshot.pass != state.pass_number,则将该快照视为 本轮的过期快照 — 停止并报告 "stale active_snapshot: pass mismatch",或降级为 HALT(snapshot_pinned 实际为 false:不产生权威判定,Block B 为 NOT_MATCHED,reproduce 为 not_attempted)。这可以捕获在 Stage 15 递增轮次后 保留了 active_snapshot、却未重新固定快照的自定义 harness。参考元 Agent 每轮都会 重新固定快照,因此不会触发此检查。Block B 本身无法检测此情况(它只检查 snapshot_id,不检查 pass)。

策略师专属说明:

  • Plan 是 Mode A 中的代码阅读阶段(会遍历生产目录);仅分析发现的跳过规则不适用。
  • Mode A 的遍历和每个 target_files 路径都相对于快照:在 CODE_ROOT 下遍历并解析这些路径。
  • workspace/kb/、workspace/plan.json、workspace/.mantis_state.json、workspace/archive/ 和 workspace/findings/ 都相对于状态目录:在 --state_root 下读写这些路径,绝不可在 CODE_ROOT 下读写。
  • 绝不可在 CODE_ROOT 下写入、编译或生成内容(Block A step 4)。计划脚本只写入 workspace/plan.json(相对于状态目录)。Block E 中的 VCS diff 按照 Block A step 5 在实时仓库根目录下运行,而非在 CODE_ROOT 下运行。

分析仓库结构,并制定详细的防御性安全审查计划;避免重复以往工作,同时深入检查复杂的进程间路径和未扫描的代码边界。

目标无关性指令: 你评估的目标可能是原始源代码、已编译二进制文件、固件镜像,或实时的预发布/开发端点。规划时应以目标当前所处的格式为依据。你获准并鼓励使用手头任何合适的工具(例如标准 Unix 工具、unblob、radare2、angr、objdump、Ghidra、qemu、unicorn)来探索工件结构。如果没有源代码,请勿强行采用源代码工作流(例如搜索 .c 或 .py 文件);应根据当前工件调整方法,采取行之有效的做法。

按以下步骤执行规划阶段:

  1. 检查威胁模型上下文: 检查知识库目录中是否存在 workspace/kb/THREAT_MODEL.md 文件。如果存在,请完整阅读该文件,以了解程序官方定义的安全边界、威胁主体、资产、高风险接口和可信输入。

  2. 确定模式并获取经验: 检查知识库索引 workspace/kb/index.md 是否存在。

    • 模式 A:首次全面审查模式(未找到 workspace/kb/index.md): 如果这是首次运行,请确保完整覆盖代码库。为避免大型仓库触及输出 Token 限制,请勿在文本回复中手动生成 workspace/plan.json。而应执行 shell 命令,运行一段用你偏好的语言编写的简短脚本,该脚本需:

      1. 使用 find 或 os.walk 遍历所有生产目录。如果某个目录中存在 mantis-summary.md 文件,则使用其内容了解该目录结构,而不是逐个读取所有源文件。否则,遍历所有生产源代码文件(例如 .c、.cpp、.py、.js、.go、.rs、.java)。
      2. 忽略测试文件夹、构建产物和供应商依赖项(例如 node_modules、.git、tests/)。
      3. 以编程方式将列表格式化为 workspace/plan.json 架构,并直接写入磁盘。由于这是自动化脚本,请指示脚本在 "question" 字段中使用通用的总体基线问题(例如“开展基线审计,以检查内存安全和逻辑缺陷”),将高度贴合上下文的自定义问题留给模式 B。
    • 模式 B:战略学习模式(存在 workspace/kb/index.md): 阅读 workspace/kb/index.md 和 workspace/kb/THREAT_MODEL.md,以回顾代码库积累的历史知识,包括信任边界、漏洞类别和架构组件。调整审查重点,为曾有漏洞记录的组件和文件设计新的、有针对性的深度审查和回归审查。在此模式下,你可以使用文件写入工具手动生成 workspace/plan.json,因为审查范围会窄得多。

      • 针对性重新评估与重试:检查 KB 索引、实体文件和复现尝试缓存文件 (如果存在,则为 workspace/archive/.repro_attempts.json)。你必须 找出需要重新评估或重试的发现:

        还要读取 workspace/.mantis_state.json 中的快照上下文: active_snapshot.{snapshot_id, snapshot_pinned} 和 snapshot_history (两者均由元 Agent 写入)。然后通过在实时仓库根目录中运行下方的 Block E, 为本轮计算 changed_files / changed_files_status(依据 Block A 第 5 步中的 VCS 元数据例外规则;固定的 --snapshot_root 会剥离 .git/.hg/.repo,因此 diff 必须针对实时树运行)。将计算得出的 changed_files(仓库相对路径数组)和 changed_files_status(COMPUTED 或 UNKNOWN)写回 workspace/.mantis_state.json,然后在本阶段剩余步骤中使用它们。 同时写入 changed_files_pass = 状态中的当前 pass_number,以便使用方检测是否使用了 过期的(上一轮)diff。使用以下规则确定自上一轮以来更改的文件:

        自上次以来的更改:在实时仓库根目录(而非 SNAPSHOT_ROOT)中运行。CUR = 当前提交/修订版; PREV = 本轮之前的 snapshot_history 条目。如果 PREV 缺失,或 vcs_type 属于 {none,unknown},或 prev 或 cur 的 SNAPSHOT_ID 是 content:/live:/+content_hash 回退值,或 diff 命令出错 -> changed_files_status = UNKNOWN。 将每个文件都视为已更改。绝不能视为未更改。绝不能丢弃。(注意: snapshot_pinned false 本身不会触发 UNKNOWN —— 在 HALT 模式下, active_snapshot 存在且 snapshot_history 中有 PREV 条目,因此仍可运行 diff。 在 MODE-OFF 模式下 —— 没有 active_snapshot —— 不存在 PREV 条目,因此 PREV 缺失, diff 状态降级为 UNKNOWN,但这不会强制执行完整的 Mode-A 遍历;参见下方的 Mode-A 触发条件。)否则,git: git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR(-M 标志用于检测重命名;-C 用于检测复制;--name-status 会为重命名输出 R<score>\told_path\tnew_path,因此旧路径和新路径都会显示;--diff-filter=RAMDCT 包含重命名、新增、修改、删除、复制和类型变更的文件)hg: hg status -C --rev PREV:CUR(-C/--copies 会在后续行中显示重命名/复制文件的源路径; hg 状态码:A=新增,R=删除,M=修改)multi-vcs: repo forall -c 'git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR' (任何错误 -> UNKNOWN)。如果某个发现的任意一个 code_paths(路径部分)属于该集合, 或其路径是重命名后的路径或重命名前的路径,则该发现的文件视为已更改(解析 R<score>\told\tnew 行:旧路径和新路径都属于更改集合)。如果某个发现的主文件 出现在重命名源文件(旧路径)中,也将新路径视为已更改 —— 缺陷很可能随文件一起移动。 检查 workspace/archive/.repro_attempts.json 时,也要应用此缓存读取规则。首先,完全按照 mantis-reproduce 写入的方式选择缓存键:如果发现项有 signature 字段,则该键就是 signature;否则,该键为 stable_key = normalized_title + "@" + primary_file_path(标题需转为小写并移除所有非字母数字字符;primary_file_path = code_paths 中第一个去除末尾 :line 的条目)。然后读取该键下的值 V:如果 V 是整数,则 count=V 且 last_snapshot=UNKNOWN;如果 V 是对象,则 count=V.count 且 last_snapshot=V.last_snapshot(默认值为 UNKNOWN)。如果所选键下没有条目,在判定 count=0 之前,也要尝试另一种键形式,以免使用 signature 键的写入方和使用 stable_key 键的读取方彼此错过,导致错误重置尝试预算。(迁移期间,缓存混合了两种值形式和两种键样式。)

        1. 安排研究: 对于档案中标记为 "NEEDS_RESEARCH" 的发现项,在 workspace/plan.json 中安排有针对性的调查(收集缺失的上下文,并将其判定为 "VALID" 或 "FALSE_POSITIVE")。

        2. 复制以重试(受快照检查控制)或重新发现: 对于每个原本符合重试条件的档案发现项(尚未尝试复现,或根据上述缓存读取规则,failed_to_reproduce 且尝试次数少于 2 次,或 patch_status 为 {VERIFICATION_FAILED,ERROR,VERIFICATION_INCOMPLETE}),运行:

          针对发现项 F 进行 SNAPSHOT MATCH CHECK(判定为 MATCHED 还是 NOT_MATCHED):
          1. 如果 snapshot_pinned 为 false -> NOT_MATCHED。停止。
          2. 读取 F.discovery_commit:
             - 缺失、为空或为字面值 "MIXED" -> NOT_MATCHED。
             - 与 SNAPSHOT_ID 不完全相等 -> NOT_MATCHED。
             - 与 SNAPSHOT_ID 完全相等 -> MATCHED。
          除此之外,没有其他方式能得到 MATCHED;绝不进行模糊比较。全局的“为字段设默认值并继续”向后兼容规则不适用于 discovery_commit:
          缺失 = NOT_MATCHED。(不存在单独的“dirty”门槛:dirty 树的
          SNAPSHOT_ID 已包含工作树内容哈希,因此同一轮次内的发现项
          MATCH,而跨轮次的裸提交发现项不 MATCH。)
          

          然后按规则判定:

          • 原样复制(快速重试)仅当以下条件全部成立时:该发现项的 Block B 为 MATCHED,且其主文件(code_paths 中第一个条目,去除行号后)不在 changed_files 中,并且该文件在 CODE_ROOT 下存在。将档案中的 <uuid>.json 复制回 workspace/findings/<uuid>.json,保留 UUID 和原始 discovery_commit(不要重新盖戳——必须继续能够检测到漂移)。

          • **MODE-OFF 绕过(3 状态规则):**如果状态中不存在 active_snapshot (MODE-OFF — 未请求 --sync),Block B 始终返回 NOT_MATCHED (snapshot_pinned is false -> NOT_MATCHED),因此上方的 COPY-VERBATIM 门控永远不会触发,每个符合重试条件的发现都会被重新发现——这会导致行为 退化,相较于当前行为(如今,当文件仍然存在时,第 ≥2 次通过会原样保留 未更改的发现)。在 MODE-OFF 下,如果发现的主要文件(第一个 code_paths, 去除行首空白)存在于 CODE_ROOT 下,则 COPY-VERBATIM(去掉 Block B MATCHED 和 file NOT in changed_files 这两个条件——MODE-OFF 下本来就没有 changed_files 差异)。这与 mantis-patch 的 LEGACY 模式例外 一致(patch:133-138、patch:172-174)。不要将绕过条件设为 snapshot_pinned==false——这也会匹配 HALT 模式,而在该模式下,STALE 横幅 会合理地标记发现为需要重新验证。仅当不存在 active_snapshot 时才启用。 (不要更改 Block B——根据 README_AGENTS.md:711-718 的块一致性警告, 各技能中的 Block B 必须逐字符一致;修复应放在计划中使用 Block B 的 CONSUMERS,而不是 Block B 本身。)

          • 在所有其他情况下重新发现(Block B 为 NOT_MATCHED,或文件在 changed_files 中,或文件缺失,或 changed_files_status==UNKNOWN):不要复制回去。应改为向 workspace/plan.json 追加新的调查,其中包含该发现的 title、description 和 repro_hints,将 target_files 设为旧 code_paths 的目录子树,以及覆盖整个仓库的符号/关键词 搜索(搜索该发现的函数/结构体/标题词语),以便重新找到已移动/重命名的 bug,并要求研究人员在当前快照上重新推导确切行号。此外,在归档的发现上 记录历史备注 unconfirmed-regression-pending,这样在某次通过重新发现它或人工将其 驳回之前,它绝不会被悄然丢弃。

          • **行号/AST 重新锚定(第 2 阶段增量效率):**在退回到完整的重新发现之前, 尝试使用向前行号跟踪(反向 blame 或 diff 块偏移)将发现的行号重新锚定到 当前快照。这是一项优化:如果发现的主要函数/符号仍在附近,重新锚定会生成 行号提示,以便聚焦重新发现调查——但它不能取代重新验证(快照已更改,因此 下游仍需重新研究该发现)。

            • How(方法): 将 finding 的旧行号从 PREV 向前映射到 CUR (不要单独 blame PREV——那样只会返回截至 PREV 的行号,不会向前映射)。在 LIVE 仓库根目录中运行(Block A step 5 carve-out):git: git blame --reverse <PREV>..<CUR> -L <old_line>,<old_line> -- <file> (反向 blame 会沿着该行向前追踪到 CUR),或者将 git diff <PREV> <CUR> -- <file> 中的区块偏移量加到 <old_line> 上。 然后在 CODE_ROOT(当前固定的快照)中读取映射后的行,并确认 finding 的主要函数/符号存在于其 ±50 行范围内。这样只会得到一个 CANDIDATE 新行号——仅供 RE-DISCOVER 使用的搜索提示,绝不能视为可信的重新验证结果。
            • 重新锚定成功时(在映射后的行找到符号): 使用新行号来 FOCUS 此 finding 的 RE-DISCOVER 调查(优先将研究人员指向映射后的 code_paths 位置)。不要将 finding 转为 COPY-VERBATIM,也不要跳过重新验证:Block B 为 NOT_MATCHED,因此后续仍会重新研究/复现该 finding(符号可能仍存在于映射后的行,但问题可能已经 FIXED)。保持 discovery_commit、signature 和 lineage_id 不变;添加历史记录: re-anchored: <old_line> -> <new_line> (search hint)。
            • 重新锚定失败时(函数已删除、未找到符号、diff 过大、blame 出错,或旧行处的代码完全不同):按上述方式回退到完整的 RE-DISCOVER。这是保守的防护措施:只要存在任何不确定性,就重新发现。
            • 绝不要使用重新锚定来压下或丢弃 finding。 这只是快速更新行号的途径;若失败,仍须通过常规流程重新发现该 finding。
            • 与 VCS 无关: 对于 hg,比较 PREV:CUR (hg diff --rev PREV:CUR -- <file>),并将区块偏移量应用于 <old_line>,以获得向前映射后的行号。对于无 VCS/二进制目标,不适用重新锚定;始终回退到 RE-DISCOVER。
          • 绝不要复制回 "status" 为 "FALSE_POSITIVE"、"patch_status" 为 "VERIFIED_SECURE"、或 "repro_status" 为 "reproduced" 的 finding(除非 patch 如上所述失败),也不要复制回已达到当前快照 2 次尝试上限的 finding。但如果此类 finding 的文件在 changed_files 中,或 Block B 为 NOT_MATCHED,则将其视为可能的回归:重新发现它(不要将针对已更改代码的旧终局判定视为可信)。MODE-OFF 例外: 如果 active_snapshot 不存在(MODE-OFF),则移除上文中的 or Block B is NOT_MATCHED 条件——在 MODE-OFF 下,每个 finding 的 Block B 都是 NOT_MATCHED(这是没有快照所致,并非发生漂移的信号),若保留该条件,每次都会重新打开所有终局判定(FALSE_POSITIVE/VERIFIED_SECURE/reproduced)。在 MODE-OFF 下,仅依赖 file IS in changed_files(这在 MODE-OFF 下恒为假——没有 changed_files diff),因此终局 finding 会原样沿用。这就是当前的行为。

      • 变更 / 新增攻击面覆盖(MANDATORY): 对 changed_files 中的每个路径,都必须添加一项标题为 Exhaustive Review: <path> 的调查,无论其是否对应已归档的发现。如果 changed_files_status==UNKNOWN,且 active_snapshot 存在(HALT 或 PINNED 模式——本轮请求了同步),或者本轮发生了同步(snapshot_id != snapshot_history 中前一条记录的 id),则不能信任范围狭窄的文件集:本轮必须回退到完整的 Mode A 穷尽式扫描,即使 kb/index.md 存在也不例外(这是发现新增文件的唯一方式)。但是,在 MODE-OFF 模式(没有 active_snapshot——没有 --sync)下,即使 changed_files_status==UNKNOWN,也不要在第 2 轮及后续轮次强制进行完整的 Mode-A 扫描:这是当前的默认行为;在每一轮 MODE-OFF 的第 2 轮及后续轮次强制进行 Mode-A 扫描会造成回归。在 MODE-OFF 模式下,像现在一样,依靠现有的 kb/index.md(Mode B)缩小范围。

      • 依赖感知的扩展覆盖(Phase 2 增量效率): 当 changed_files_status 已知(不是 UNKNOWN)且依赖关系图可用时,将调查范围扩展到变更文件本身之外。目标是找出导入或依赖变更文件的文件,以便规划器为变更代码的使用方安排有针对性的调查,而不只是调查变更代码本身。

        • 方式: 以文件级依赖关系图(workspace/kb/dependencies.json 或实体关系 Markdown)作为强制基线:对每个变更文件 F,找出所有导入 F 的文件(直接导入或最多跨 2 层传递导入)。将这些依赖文件以 Exhaustive Review: <dependent_file> 条目的形式加入调查范围。然后再加入结构索引中的调用方:如果可用,使用查询辅助工具(workspace/helpers/query_structural_index.py)进行函数级精确查询——对变更文件导出的函数调用 resolve_symbol(),再调用 find_callers() 枚举符号级别的依赖方。安排调查时,取依赖关系图找到的依赖方与结构索引找到的调用方的并集——两者互为补充,不能互相替代。如果结构索引不存在(没有 manifest.json)、为空,或缺少查询辅助工具,则依赖关系图仍是基线。
        • 使用条件: 仅当 changed_files_status 已知且知识库包含依赖信息时使用。如果知识库缺少导入 / 构建图,或知识库已过期(检查 workspace/.mantis_state.json 中的 kb_snapshot_id 是否与 SNAPSHOT_ID 一致——如果不同,则知识库是基于不同快照构建的,可能已过期),请回退到 Phase 1 的行为(完整 Mode-A 扫描或 Mode-B 缩小范围)。
        • 护栏: 如果依赖关系图不完整、已过期,或出现任何不确定情况,则回退到 Phase 1 的重新发现(将所有文件视为可能受影响)。绝不能用依赖关系缩小范围来删除调查项——它只能为依赖文件新增有针对性的调查。变更文件本身始终必须调查。
        • 与 VCS 无关: 依赖关系图源自知识库的架构分析,而非 VCS 元数据。对于知识库已索引其 import/include/use 语句的任何语言,此方法都适用。
      • 结构索引查询(仅作提示的增强): 如果结构索引可用(存在 workspace/kb/structural_index/manifest.json),则使用它来补充上述依赖感知的扩展覆盖,精准发现符号级别的调用方。结构索引只决定调查的优先顺序,绝不决定审计集合的成员范围。

        • 优先解析协议(MANDATORY): 查询调用方之前,先解析符号:

          python3 workspace/helpers/query_structural_index.py resolve_symbol --name "<function_name>" [--language "<lang>"] [--file "<path>"] --state_root <state_root>

          如果响应包含 ambiguous: true,请勿默默选择某个匹配项。 使用 --file/--language 缩小范围,或为所有匹配的符号安排调查。

        • 有界调用方查询: 解析完成后,使用明确的边界查询调用方:

          python3 workspace/helpers/query_structural_index.py find_callers --symbol_id "<resolved_id>" --limit 100 --offset 0 --state_root <state_root>

          如果 has_more 为 true,请使用 --offset 翻页。

        • 考虑覆盖范围的结果解读: 检查每个结构索引响应中的 coverage.partition_status:

          • complete + precision == semantic + 无调用方 =“没有已索引的 调用方”——该分区已完整索引,且使用语义后端,因此空结果对于已索引代码具有权威性。仍须按仅作提示的规则运行 grep(grep 可以捕获基于宏的调用、函数指针和动态分派)。
          • complete + precision != semantic + 无调用方 =“没有已索引的 调用方”——该分区已完整索引,但精度低于语义级,因此空结果不具有权威性。必须运行穷尽式 grep 回退。
          • partial / empty / failed + 无调用方 =“未完全索引”——该分区并不完整,因此应扩大调查范围,并且必须运行穷尽式 grep 回退。
        • 防护措施:

          • 仅作提示:结构索引结果决定顺序,而非成员范围。 它们只用于优先调查哪些依赖文件;绝不能导致任何文件被排除在审计范围之外。
          • 每个结果都带有 precision 和 backend 字段——使用 precision(semantic > typecheck > ast > symbol-only > heuristic > deferred > coverage-only)来衡量对结果的信任度。
          • 如果结构索引不存在(没有 manifest.json)、为空,或缺少查询辅助工具:回退到基于 grep 的发现方式(当前行为)。结构索引仅作覆盖范围提示。
      • 上下文注入(kb_references): 对于计划开展的每项调查,你必须确定 workspace/kb/ 目录中的哪些文件(例如, workspace/kb/entities/auth_module.md 或 workspace/kb/vulnerabilities/CWE-79.md)能为研究人员提供必要的上下文。在该调查的 "kb_references" 数组中填写这些 Markdown 文件的确切路径。这样可以免去研究人员收集上下文的负担。

      • 探索性/不受约束的调查(中等概率): 在计划过程中,以中等概率 (例如,每次规划有 25-50% 的概率)加入一次不受约束的对抗性扫描或随机探索:

        1. 对抗性扫描: 选择威胁模型当前标记为安全、低风险或范围外的组件或目录。指示研究人员进行不受约束的扫描,不采纳 workspace/kb/THREAT_MODEL.md 中的安全假设。

        2. 随机探索: 在代码库中随机选择一个起点(文件或目录)。这项调查的问题应尽量简短且开放,只需指示研究人员“深入查看”或“探索”所选区域,不提供特定的威胁模型背景或预定义的漏洞类别。将这项调查的 kb_references 设为空列表,以确保以全新的视角进行调查。 令牌优化: 无论使用脚本(模式 A)还是文件写入工具(模式 B),都应将计划直接写入磁盘,不要在聊天回复中打印 JSON 内容。

  3. 模式校验: 无论使用哪种模式,最终写入磁盘的 workspace/plan.json 文件都应符合以下模式,以确保下游审计 Agent 能够正确解析:

计划模式格式
{
  "investigations": [
    {
      "title": "Exhaustive Review: [relative_file_path]",
      "target_files": ["[relative_file_path_1]", "[relative_file_path_2]"],
      "kb_references": ["workspace/kb/entities/auth_module.md", "workspace/kb/vulnerabilities/CWE-79.md"],
      "question": "Detailed reviewing prompt instructions asking the researcher to trace specific input pathways, variables, memory allocations, or function constraints."
    }
  ]
}

确保已成功写入 workspace/plan.json。完成后,请通知用户。

评论

支持 Markdown