mcpField
M
mantis-architecture

mantis-architecture

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

关于 mantis-architecture

mantis-architecture 是用于仓库分析的安全知识库构建技能。它结合代码结构与当前及历史经验,维护相互链接的 Markdown 架构、组件和漏洞记录。

主要功能

  1. 01分析组件与信任边界
  2. 02构建相互链接的 Markdown 知识库文件
  3. 03记录架构及漏洞模式
  4. 04提取依赖关系
  5. 05归档经验及每轮知识库副本

适用场景

  1. 01为代码库创建安全文档
  2. 02使组件与漏洞记录随源代码变化更新
  3. 03在分析轮次间保存安全经验

安装

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

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

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

详细介绍

Architect (/mantis-architecture)

系统目标

知识库综合器。将学习队列(workspace/learnings.jsonl)中的临时见解与代码库的结构分析,整合为规范化、相互关联的 Markdown 知识库(workspace/kb/)。

命令定义

  • 命令: /mantis-architecture
  • 描述: 通过定义系统架构、映射特定实体(组件)并归纳历史漏洞模式,为知识库奠定基础。
  • 参数(均为可选;由 LOCATOR RESOLUTION / Block A 解析): --snapshot_root=<dir>(或 SNAPSHOT_ROOT 环境变量)— 要读取目标源码的固定代码快照;--snapshot_id=<id> — 该快照的 SNAPSHOT_ID;--state_root=<dir> — 所有状态和知识库路径所在的 workspace/ 的父目录;--target_root=<dir> — 已准备好的目录树,用于覆盖快照(此阶段很少传入)。若未传入任何参数,行为将与今日完全一致(降级/未固定):从当前目录读取源码,并将 snapshot_pinned 视为 false。

输入/输出约定

  • 读取:
    • workspace/learnings.jsonl(当前轮次的原始洞见)。
    • workspace/historical_learnings.jsonl(可选,以往的漏洞元数据)。
    • 代码库目录结构和关键源文件。
    • workspace/kb/ 中现有的 Markdown 文件(用于验证/检查衰减)。
    • workspace/.mantis_state.json(用于获取轮次计数)。
    • workspace/.mantis_state.json → active_snapshot(root、snapshot_id、snapshot_pinned)和 snapshot_history — KB 新鲜度门禁(步骤 0b)的来源信息。只能从 STATE 读取快照;绝不能运行实时 VCS 命令(git/hg/repo)来判断 KB 是否为最新。
    • workspace/.mantis_state.json → kb_snapshot_id(当前 KB 上次构建所依据的 SNAPSHOT_ID;首次构建或旧版 KB 中可能不存在)。
    • workspace/.mantis_state.json → changed_files 和 changed_files_status(由 mantis-plan 的 Block E 写入;在步骤 0b 结果 3 中用于限定范围的 KB 失效处理。自第 2 轮起存在,但可能已过时(在之前的轮次写入)——限定范围路径会将 changed_files_pass 与 state.pass_number 进行比对;若不一致,则回退到完整重建。)
  • 写入:
    • workspace/kb/ 下的 Markdown 文件(architecture.md、entities/[component_name].md、vulnerabilities/[CWE-ID].md、index.md)。
    • workspace/kb/dependencies.json — 架构分析期间提取的导入/依赖关系边 JSON 映射(键 = 相对于 CODE_ROOT 的源文件路径;值 = 导入/依赖该键文件的文件数组)。此文件供 mantis-plan 在第二阶段使用依赖感知的扩散分析。如果代码库没有可解析的导入结构,则写入 {}。限定范围失效处理期间仅重新推导变更条目(见下文结果 3)。
    • 将 workspace/learnings.jsonl 归档至 workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl。
    • 在每个(重新)写入的 KB 文件(index.md、每个 entities/*.md、每个 vulnerabilities/*.md)的首行写入一个 `` 标记,并在 workspace/.mantis_state.json 中将 kb_snapshot_id 设为 SNAPSHOT_ID。
    • 将整个 KB 目录树按轮次复制一份不可变副本至 workspace/archive/kb/kb_pass_${N}_${X}/(这样之后回退的修复不会悄然抹去 KB 在第 N 轮所记录的内容)。
  • 前提条件:
    • workspace/learnings.jsonl 必须存在。
  • 幂等性保证:
    • 事务性:仅在通过程序验证所有 KB Markdown 更新均已成功写入后,才将 workspace/learnings.jsonl 移至归档。KB 文件会原位覆盖。
    • 快照标记属于同一事务:KB_SNAPSHOT 标记、每轮的 workspace/archive/kb/kb_pass_${N}_${X_kb}/ 副本,以及 kb_snapshot_id 状态写入,必须在(或与)learnings 移动之前完成。任何步骤失败时,都要保留 workspace/learnings.jsonl。

说明

分析代码库和待处理的 learnings,为未来的 Agent 构建一份永久的、基于 Markdown 的记忆。

按以下步骤执行架构阶段:

  1. 定位器解析(Block A,内嵌如下):
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.

这是一个代码阅读阶段(步骤 2 和 4 会读取目标源代码),因此 Block A 的步骤 1-6 全部适用;这并非仅分析发现。开始以下任何操作前,先从状态中解析 CODE_ROOT、SNAPSHOT_ID 和 snapshot_pinned。根据 Block A 步骤 3,所有 workspace/kb/... 路径均相对于 STATE:在 state_root/workspace 下读取和写入,绝不能在 CODE_ROOT 下操作。所有目标源代码均在 CODE_ROOT 下读取。不要运行任何 VCS 命令来判断 KB 新鲜度(Block A 步骤 5 的例外仅适用于历史/差异/归责分析,本阶段不使用这些)。

0b. KB 快照新鲜度门禁(机械检查;仅使用 STATE 和 KB 标记,不使用实时 VCS):

- `CUR` = `SNAPSHOT_ID` (resolved by Block A; the empty string if
  `active_snapshot` was absent). `PINNED` = `snapshot_pinned` (false if absent).
- **MODE-OFF short-circuit (3-state rule):** if `active_snapshot` is ABSENT
  in state (no `--sync` was requested — MODE-OFF = today's default), SKIP the
  freshness gate entirely: do a best-effort build/update against `CODE_ROOT`,
  do NOT prepend any STALE banner, and do
  NOT stamp `kb_snapshot_id`. This is byte-for-byte today's behavior. (Only
  HALT and PINNED run the gate below.)
- `KB_ID` = the `kb_snapshot_id` value in `.mantis_state.json` (primary); else the
  text after `KB_SNAPSHOT:` on the FIRST line of
  `state_root/workspace/kb/index.md` if that file exists (secondary fallback,
  for legacy runs without state); else `""` (no prior KB). State is primary so
  the file-marker parsing pitfall (comment-wrapped first line, no `-->`
  stripping) can never strand `KB_ID` with the comment closer and force BUILD
  FRESH every pass.
- Choose EXACTLY ONE outcome by string checks, top to bottom, first match wins:
  1. `PINNED` is false (HALT mode — `active_snapshot` present but unpinned)
     ->  **STALE / HALT.** Do a best-effort build/update against `CODE_ROOT`,
     but PREPEND the STALE banner (below) as the first lines of `index.md`.
     Do NOT claim currency: leave the
     banner in place. Set `kb_snapshot_id` = `CUR` (a `live:` id).
  2. Else `KB_ID` == `CUR` (both non-empty)  ->  **CURRENT.** Do the incremental
     update + decay-check (step 4) as today. Re-stamp `KB_SNAPSHOT: CUR` on
     every (re)written file. REMOVE any STALE banner previously prepended to
     `index.md`.
  3. Else (`PINNED` true AND (`KB_ID` is empty OR `KB_ID` != `CUR`)) ->
     **BUILD FRESH (full or scoped re-architecture).** The pinned code advanced
     since the KB was built (a sync / pass-boundary change), OR the KB is
     unstamped / legacy. Choose full or scoped:
     - **Scoped invalidation (Phase 2 incremental efficiency):** If
       `changed_files_status` is known (not UNKNOWN) AND the KB already has a
       `KB_SNAPSHOT` stamp (KB_ID was non-empty, just different) AND
       `changed_files_pass` equals the current `state.pass_number` (the diff
       is from THIS pass, not a stale prior pass — absent or different →
       treat as UNKNOWN → full rebuild below), attempt a SCOPED rebuild: only
       invalidate KB entries whose source files are in `changed_files`, plus
       their parent-rollup dependents (KB entities that import/reference the
       changed files). Re-derive ONLY those entries from `CODE_ROOT`; carry
       forward all other KB entries unchanged (they were built against the
       same code, just a different snapshot ID). Re-stamp `KB_SNAPSHOT: CUR`
       on every (re)written file.
        - **Parent-rollup (2-hop, matching plan's fan-out):** When
          invalidating a KB entry for changed file F, also invalidate any KB
          entry that REFERENCES F directly (1-hop) AND any entry that
          references a 1-hop dependent of F (2-hop). This matches
          `mantis-plan`'s dependency-aware fan-out (which expands up to 2
          hops), ensuring that a grandchild entity (H imports G, G imports
          changed F) is not carried forward stale and later fed as a
          `kb_reference` while its dependency has changed.
       - **Guardrail:** If ANY uncertainty arises (can't determine which KB
         entries map to which source files, the KB structure is ambiguous, or
         changed_files is empty but KB_ID != CUR), fall back to full rebuild
         below. Never carry forward a stale entry for a changed file.
     - **Full rebuild (Phase-1 fallback):** If KB_ID is empty (no prior KB),
       OR `changed_files_status` is UNKNOWN, OR the scoped invalidation guardrail
       fired, REBUILD every KB file from scratch against `CODE_ROOT`. Do NOT
       carry forward any prior assertion you have not re-derived from
       `CODE_ROOT` this pass. Stamp `KB_SNAPSHOT: CUR`. REMOVE any STALE banner.
- STALE banner (paste verbatim, substituting `<KB_ID>` and `<CUR>`; keep the
  leading `>` on every line so it renders as a visible blockquote):

  ```
  > **STALE KB WARNING — do not trust without re-verifying.**
  > snapshot_pinned=false, or the KB was built against a different snapshot.
  > KB_SNAPSHOT=<KB_ID> does not match active_snapshot.snapshot_id=<CUR>.
  > Every SECURE/FIXED/NON_VIABLE/SAMPLE_OR_TEST claim below is UNVERIFIED
  > against the current code. Re-verify before trusting; do NOT filter, skip,
  > or down-prioritize work based on this KB.
  ```
  1. 读取收件箱(workspace/learnings.jsonl 和 workspace/historical_learnings.jsonl):

    • 解析 workspace/learnings.jsonl 的内容(如果存在 workspace/historical_learnings.jsonl,也一并解析)。提取所有 轨迹洞察、已发现的漏洞、可行的崩溃路径,以及 已验证的补丁。
  2. 分析源代码边界:

    • 检查 CODE_ROOT 下的目录结构和关键源文件 (由 Block A 解析出的固定快照;按 Block A 第 6 步使用绝对路径,且不要运行 VCS 命令)。根据 仓库内容,动态识别系统的核心组件、接口和信任 边界。这广泛适用于各个领域:无论是 软件系统(例如识别解析器、控制器或网络守护进程)、 硬件/RTL 设计(例如识别 IP 块、JTAG 接口或内存控制器)、基础设施即代码(例如 识别云权限、VPC 边界或部署描述符), 还是数据/ML 流水线(例如识别数据入口点、模型 序列化机制或训练边界)。
  3. 构建或更新知识库(KB):

    • 使用标准 Markdown 在 workspace/kb/ 目录中创建或更新文件。 严格遵循以下路径:

      • workspace/kb/architecture.md:高层数据流、区域定义、 系统设计,以及整体可用性/正常运行时间要求(如果有 文档记录,或可从 systemd、kubernetes 或 负载均衡器等配置中推断)。
      • workspace/kb/entities/[component_name].md:组件的具体定义 (例如 auth_module.md)。必须包含指向相关 漏洞类别的链接,并记录已知约束(例如“此模块 会对输入 X 进行净化”)。记录组件的关键性和 可用性要求(如适用,分类为 CRITICAL、STANDARD 或 LOW_CRITICALITY)。在此处纳入轨迹洞察。
      • workspace/kb/vulnerabilities/[CWE-ID_or_BugClass].md:对此代码库 历史上相关的缺陷类别(例如 CWE-79.md 或 Memory-Corruption.md)的 描述,包括说明不应做什么的示例。
      • workspace/kb/index.md:根目录索引,包含指向上述创建的每个文件的 链接和 1 行摘要。这是 Planner 将读取的 地图。
    • 重要格式规则: 使用相对链接交叉引用 实体和漏洞(例如 [Auth Module](entities/auth_module.md))。确保所有 markdown 文件 简洁明了,并聚焦于可操作的安全上下文。

    • 快照标记(在运行新鲜度门控时,即 HALT 或 PINNED,对每个(重新)写入的 KB 文件为必需; 在 MODE-OFF 下绝不使用): 使 index.md、每个 entities/*.md 和每个 vulnerabilities/*.md 的第一行恰好为 (替换 第 0b 步中的 `CUR`;它是 HTML 注释,因此不会渲染)。这是下一 轮的新鲜度门控(第 0b 步)检测漂移的方式。**MODE-OFF 门控(3 态 规则):** 如果 `active_snapshot` 为 ABSENT(MODE-OFF — 未请求 `--sync`),则不要为每个文件标记 `KB_SNAPSHOT` 标记:`CUR` 是 空字符串(`arch:145`:“如果 `active_snapshot` 不存在,则为空字符串”), 因此强制要求的标记将是 (空 值)— 这是 Phase 1 中不存在的快照时代产物。 每文件标记仅由第 0b 步的新鲜度门控消费,而 MODE-OFF 完全跳过该门控(arch:147-152:“完全跳过新鲜度门控... 这与今天的行为逐字节相同。只有 HALT 和 PINNED 运行下面的门控。”)。此 MODE-OFF 门控与下面的新鲜度门控逻辑 以及第 0b 步的结果子句相同,后者仅在 HALT/PINNED 结果中 提及每文件 KB_SNAPSHOT: CUR 标记(CURRENT :164, 限定作用域的 BUILD FRESH :178,完整 BUILD FRESH :195)。

    • **按文件标记 KB_SNAPSHOT 是 KB 断言唯一的溯源机制。**不要添加逐条断言的 (AS_OF:<snapshot>) 标签——AS_OF 重新验证读取器从未实现,而新鲜度门控(步骤 0b)通过比较 kb_snapshot_id 与 SNAPSHOT_ID,以及每条发现的 discovery_commit(由 mantis-critic Block B 强制执行),已经提供了过时保护。之后被撤销的修复由这些机制捕获,而非逐条断言标签。

  4. 验证并衰减知识(防止漂移):

    • 代码经过修补或重构后,知识会过时。在最终确定 KB 更新之前,针对 CODE_ROOT 下的源码(固定的快照——不是实时 VCS 查询,也不是实时工作树)抽查现有 workspace/kb/entities/ 中的断言。在 BUILD FRESH 结果(步骤 0b)下,完全不要抽查:丢弃先前的断言,并在本轮从 CODE_ROOT 重新推导每个实体。在 STALE / HALT 结果下,仅尽力抽查,并且无论结果如何都保留 STALE 横幅。
    • 如果实体文件声称某个变量未经清理(基于旧的学习),但当前实时代码中已有清理函数(因为补丁已合入),则在 KB 中删除或更正该过时的学习。
    • 如果当前轨迹洞察反复证明某项学习有误,请主动更正,防止“错误的学习”持续存在并误导未来的 Agent。
    • 更正或重新确认基于发现的断言时,重新在该 KB 文件上标记 KB_SNAPSHOT。
  5. 事务性收件箱清理与归档:

    • 为防止无限循环和令牌膨胀,必须清空队列并归档学习成果。
    • 验证并完成: 以编程方式验证所有 Markdown 知识库更新均已成功写入磁盘,且交叉引用有效。此外,在提交前验证每个被(重新)写入的知识库文件都以其 `` 标记开头,并且每项基于发现结果的判定都有当前 SNAPSHOT_ID 作为依据。
    • 通过移动文件来提交: 只有在验证综合整理成功后,才能将 workspace/learnings.jsonl 移至归档目录:
      • 确保目标目录存在(例如,运行 mkdir -p workspace/archive/learnings/)。
      • 通过读取 workspace/.mantis_state.json 中的 "pass_number",确定循环轮次编号 N。如果缺失或无效,则扫描 workspace/archive/ 中匹配 findings_pass_N 或 loopN_findings 的文件夹,并将 N 设为 max_found + 1;如果不存在归档,则默认为 1。
      • 通过统计 workspace/archive/learnings/ 中匹配 learnings_pass_${N}_*.jsonl 的现有文件数量并加 1,确定子索引 X。
      • 移动文件: mv workspace/learnings.jsonl workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl。
    • 快照知识库(每轮归档): 综合整理成功后,将整个知识库目录树复制到每轮对应的归档目录:
      • 确保目录存在(运行 mkdir -p workspace/archive/kb/)。
      • 计算子索引 X_kb = workspace/archive/kb/ 中现有 kb_pass_${N}_* 目录的数量 + 1。
      • 复制(切勿移动——实时的 workspace/kb/ 必须保留,以供下一轮使用):cp -a workspace/kb/. workspace/archive/kb/kb_pass_${N}_${X_kb}/。
    • 写入状态标记: 将 kb_snapshot_id = SNAPSHOT_ID(步骤 0b 中的 CUR)写入 workspace/.mantis_state.json。如果 active_snapshot 不存在(MODE-OFF),则不要写入 kb_snapshot_id,也不要在 index.md 前添加任何 STALE 标记(已跳过新鲜度检查)。在 HALT 模式下,写入 kb_snapshot_id = CUR,并保留 index.md 中的 STALE 标记。
    • 如果综合整理失败或被中断,请将 workspace/learnings.jsonl 保留在原位置,以确保数据不会丢失。
    • 如果进入时 workspace/learnings.jsonl 不存在(例如 Stage-15 调用,因为 Stage-2 调用已在本轮将其归档),则只跳过学习成果文件的移动;仍需运行新鲜度检查(步骤 0b)、写入 KB_SNAPSHOT 标记、写入 kb_snapshot_id,并复制每轮对应的知识库归档。每次调用都必须记录知识库来源信息。

完成后,通知用户。

评论

支持 Markdown