mantis-patch
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePatcher (/mantis-patch)
Patcher (/mantis-patch)
System Goal
系统目标
Security Patching Expert. Generates minimal, correct code fixes, applies them to
source code files, and verifies them inside isolated sandboxes before appending
logs to long-term memory.
安全补丁专家。生成最小化、正确的代码修复方案,将其应用于源代码文件,并在将日志追加到长期内存前,在隔离沙箱中完成验证。
Command Definition
命令定义
- Command:
/mantis-patch [--target_root=<path>] [--state_root=<path>] [--snapshot_root=<path>] [--snapshot_id=<id>] [--snapshot_pinned=<true|false>] - Description: Generates minimal security fixes using transactional isolation (shadow directories or file backups), applies patches, and verifies them.
- Parameters (all optional; absent ⇒ today's behavior):
- : Root of the code snapshot to read (CODE_ROOT). When the orchestrator pins a snapshot it passes
--target_root;--snapshot_rootis reserved for a caller that hands you an already-prepared tree.--target_root - : Root of the pinned immutable snapshot for this pass.
--snapshot_root - : The SNAPSHOT_ID string of the pinned snapshot (used by the Snapshot Match Check).
--snapshot_id - :
--snapshot_pinnedwhen a pinned immutable snapshot exists this pass;true/absent ⇒ degraded/legacy (see Backward-compat).false - : Root of the Mantis state directory that contains
--state_root(defaults to the current directory). ALLworkspace/paths in this file are STATE-RELATIVE and resolve underworkspace/....<state_root>/workspace/...
- 命令:
/mantis-patch [--target_root=<path>] [--state_root=<path>] [--snapshot_root=<path>] [--snapshot_id=<id>] [--snapshot_pinned=<true|false>] - 描述: 借助transactional isolation(shadow directories或文件备份)生成最小化安全修复方案,应用补丁并完成验证。
- 参数(均为可选;未指定则沿用当前行为):
- :待读取的代码快照根目录(CODE_ROOT)。当编排器固定某个快照时,会传入
--target_root;--snapshot_root保留给已准备好代码树的调用方使用。--target_root - :本次流程中固定的不可变快照根目录。
--snapshot_root - :固定快照的SNAPSHOT_ID字符串(用于Snapshot Match Check)。
--snapshot_id - :当本次流程存在固定的不可变快照时设为
--snapshot_pinned;设为true或未指定则表示降级/兼容旧版(参见向后兼容部分)。false - :包含
--state_root的Mantis状态目录根目录(默认值为当前目录)。本文件中所有workspace/路径均为相对STATE的路径,会解析为workspace/...。<state_root>/workspace/...
Input/Output Contract
输入/输出契约
- Reads:
- (reproduced finding JSON files where
workspace/findings/is notpatch_statusor"VERIFIED_SECURE")."MITIGATION_PROPOSED" - (to track current loop pass).
workspace/.mantis_state.json workspace/.mantis_state.json(active_snapshot,root,snapshot_id) — resolved via Block A; supplies CODE_ROOT and the SNAPSHOT_ID used by the Snapshot Match Check when nosnapshot_pinnedflag is passed.--snapshot_*- Target source code files.
- Reproducer script path () and command (
repro_file_path) from findings.run_command - Pre-existing backup files matching finding ID (if Option B is used).
- Writes:
- Source code modifications (applied transactionally and rolled back).
- Updates finding JSON files in-place (sets ,
"patch_status", re-attack details including"patch_diff"and"reattack_status", and history)."reattack_variants" - Appends to .
workspace/learnings.jsonl - Reusable helper script .
workspace/helpers/append_patch.py
- Preconditions:
- Findings must exist in .
workspace/findings/
- Findings must exist in
- Idempotency Guarantee:
- Snapshot-aware skip: Skips a finding whose is already
patch_statusor"VERIFIED_SECURE"ONLY when its recorded"MITIGATION_PROPOSED"equals the current SNAPSHOT_ID (i.e. it was verified against THIS snapshot). Ifpatch_base_snapshotis absent, empty, or different from the current SNAPSHOT_ID, the terminal status is stale — do NOT skip; re-open and re-verify the finding against the current snapshot. In legacy mode (nopatch_base_snapshotand noactive_snapshotflags) skip exactly as today (by--snapshot_*alone).patch_status - Transactional isolation: modifies code inside uniquely generated temporary
directories or creates temporary file backups (), restoring baseline state upon completion (using
target.c.bak-[id]rollback mechanisms).try...finally - Reuses the existing script once created.
append_patch.py
- Snapshot-aware skip: Skips a finding whose
- 读取内容:
- (已复现问题的JSON文件,其中
workspace/findings/不为patch_status或"VERIFIED_SECURE")。"MITIGATION_PROPOSED" - (用于跟踪当前循环流程)。
workspace/.mantis_state.json - 中的
workspace/.mantis_state.json(active_snapshot、root、snapshot_id)——通过Block A解析;当未传入snapshot_pinned参数时,提供CODE_ROOT和Snapshot Match Check所需的SNAPSHOT_ID。--snapshot_* - 目标源代码文件。
- 问题记录中的复现脚本路径()和命令(
repro_file_path)。run_command - 与问题ID匹配的预存在备份文件(若使用Option B)。
- 写入内容:
- 源代码修改(以事务方式应用并可回滚)。
- 原地更新问题JSON文件(设置、
"patch_status"、包含"patch_diff"和"reattack_status"的重新攻击详情,以及历史记录)。"reattack_variants" - 追加内容到。
workspace/learnings.jsonl - 可复用辅助脚本。
workspace/helpers/append_patch.py
- 前置条件:
- 目录下必须存在问题记录。
workspace/findings/
- 幂等性保证:
- 快照感知跳过: 仅当问题的已为
patch_status或"VERIFIED_SECURE",且其记录的"MITIGATION_PROPOSED"等于当前SNAPSHOT_ID(即已针对此快照完成验证)时,才跳过该问题。若patch_base_snapshot不存在、为空或与当前SNAPSHOT_ID不同,则终端状态已过期——请勿跳过;需针对当前快照重新开启并验证该问题。在旧版模式(无patch_base_snapshot且无active_snapshot参数)下,完全按照当前逻辑仅通过--snapshot_*判断是否跳过。patch_status - 事务隔离:在唯一生成的临时目录中修改代码,或创建临时文件备份(),完成后通过
target.c.bak-[id]回滚机制恢复基线状态。try...finally - 一旦创建脚本,后续将复用该脚本。
append_patch.py
- 快照感知跳过: 仅当问题的
Instructions
操作说明
Fix successfully reproduced security flaws without breaking standard code
behavior.
Execute the patching and verification stage as follows:
-
Snapshot & Locator Resolution (run once, before touching any code):0a. Resolve CODE_ROOT, SNAPSHOT_ID, snapshot_pinned, and state_root via Block A (Locator Resolution):
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.[!NOTE] CURRENT-PASS CHECK (defensive; the binding guarantee is on the harness perScenario 2): ifmantis-pipeline-adapteris present ANDactive_snapshot, treat the snapshot as STALE for this pass — STOP "stale active_snapshot: pass mismatch" or degrade as HALT (active_snapshot.pass != state.pass_numbereffectively false: no authoritative verdicts, Block B NOT_MATCHED, reproducesnapshot_pinned). This catches a custom harness that preservednot_attemptedacross the Stage 15 pass increment without re-pinning. The reference meta-agent re-pins every pass, so this check never fires there. Block B itself cannot detect this (it isactive_snapshot-only, notsnapshot_id-aware).passFor this stage: mantis-patch READS target code (it is NOT a findings-only stage), so it runs Block A steps 1–6 in full. CODE_ROOT is the immutable pinned snapshot; you MUST NOT write, compile, or run reproducers under it (Block A step 4) — do all mutation in a private shadow (step 2 below).0b. Determine PATCH_MODE (mechanical, using the resolved values):- absent AND no
active_snapshot/--snapshot_root/--snapshot_idpassed ⇒ LEGACY mode (today's behavior; the new ceilings in step 3 do NOT fire).--target_root - ⇒ PINNED mode (full gates below apply).
snapshot_pinned == true - AND SNAPSHOT_ID begins with the literal
snapshot_pinned == false⇒ HALT/DEGRADED mode (a snapshot was attempted but could not be pinned; authoritative verdicts are forbidden this pass — see step 3).live:
0c. For each finding you process, compute its MATCHED/NOT_MATCHED result via Block B (Snapshot Match Check):SNAPSHOT MATCH CHECK for finding F (decides MATCHED vs NOT_MATCHED): 1. If snapshot_pinned is false -> NOT_MATCHED. Stop. 2. Read F.discovery_commit: - missing OR empty OR the literal "MIXED" -> NOT_MATCHED. - not exactly equal to SNAPSHOT_ID -> NOT_MATCHED. - exactly equal to SNAPSHOT_ID -> MATCHED. There is no other route to MATCHED; never fuzzy-compare. The global "default the field and proceed" backward-compat rule does NOT apply to discovery_commit: absent = NOT_MATCHED. (There is NO separate "dirty" gate: a dirty tree's SNAPSHOT_ID already embeds the working-tree content hash, so within-pass findings MATCH and cross-pass bare-commit findings do not.)The MATCHED/NOT_MATCHED result is consumed in step 2 (isolation-mode choice) and step 3 (verdict). It never on its own downgrades a verdict in PINNED mode: a NOT_MATCHED finding is RE-verified against the current snapshot via the step-3 gate and, if it passes, is stamped with the current.patch_base_snapshot -
Load Findings to Patch: Read the JSON files in thedirectory. Filter for findings that are NOT already terminally verified AGAINST THE CURRENT SNAPSHOT — i.e. treat a finding as still-to-process unless its
workspace/findings/ispatch_statusor"VERIFIED_SECURE"and its"MITIGATION_PROPOSED"equals the current SNAPSHOT_ID (Snapshot & Locator Resolution step 0). A terminal finding whosepatch_base_snapshotis absent/empty/different is STALE — include it for re-verification. (In LEGACY mode, where there is no SNAPSHOT_ID, fall back to filtering onpatch_base_snapshotalone, exactly as before.) Among the included findings, keep those where (eitherpatch_statusisrepro_statusOR the finding is an exploit chain, e.g., the title starts with"reproduced", or history has an entry from the"Exploit Chain:"stage, or the"chainer"property is present and non-empty). If none exist, notify the user."constituent_findings" -
Generate and Apply Minimal Patches: For each reproduced security flaw:
-
Target Agnosticism (Binaries vs Source): If the target is source code, proceed with generating and applying a code patch as described below. If the target is a compiled binary or firmware blob without source code available, do not attempt to modify the binary or write binary patching scripts. Instead, skip the branch isolation/modification/diff steps and generate a general, high-level recommendation for how this issue could be mitigated in a production environment without requiring deep technical depth. Output this mitigation string in place of thefield, and set
patch_diffto"patch_status"."MITIGATION_PROPOSED" -
Exploit Chains: If the finding is an exploit chain (identified byin the title, or history details, or if the
"Exploit Chain:"property is present and non-empty), do not generate a code patch or diff. Instead, identify its sub-findings by reading the"constituent_findings"array of UUIDs. Monitor the patch status of these constituent findings (listed on disk as"constituent_findings"). Important: Defer evaluating exploit chains until all individual findings in the batch have been processed, so that the latest patch statuses of their constituents are available on disk.workspace/findings/<uuid>.jsonEvaluate the exploit chain status using these propagation rules (evaluated in order):-
Validity Check: Read the validityof each constituent finding. If any constituent's
"status"is"status", update the exploit chain finding's"FALSE_POSITIVE"to match it (e.g."status") and immediately skip any further patching/verification for the chain. If any constituent's"FALSE_POSITIVE"is"status", resolve it to its canonical finding by recursively following its"DUPLICATE"property."duplicate_of"Duplicate Resolution Process:- Locate the Finding File: The finding file for the duplicate (or
any parent in the duplicate chain) may have been moved. Search for
in the following locations in order:
<uuid>.json- (active findings)
workspace/findings/<uuid>.json - (de-duplicated trash)
workspace/findings/.trash/<uuid>.json - or
workspace/archive/findings_pass_*/<uuid>.json(archives from previous passes) If the file cannot be found in any of these locations, treat it as a missing file error.workspace/archive/loop*_findings/<uuid>.json
- Cycle Detection: Maintain a set of visited finding UUIDs during the resolution. If you encounter a UUID that has already been visited in the current resolution chain, raise a validation error (cycle detected).
- Maximum Depth: Limit the recursion depth to a maximum of 5 steps. If the chain is deeper, abort and report an error.
- Extract Status: Once you resolve to the canonical finding (one
whose is not
"status"or does not have"DUPLICATE"), use that canonical finding's"duplicate_of"and"status"for all downstream checks and propagation. Do not update the exploit chain finding itself to"patch_status"."DUPLICATE"
- Locate the Finding File: The finding file for the duplicate (or
any parent in the duplicate chain) may have been moved. Search for
-
Missing Files: If any constituent finding's JSON file is missing from the disk, set the chain'sto
"patch_status"."ERROR" -
Constituent Unset or Stale (Pending): A constituent counts as NOT-YET-VERIFIED if EITHER itsis unset (null or missing, indicating it has not yet been reproduced/processed) OR its
"patch_status"is terminal but its"patch_status"is absent/empty/different from the current SNAPSHOT_ID (verified against a stale snapshot — Snapshot & Locator Resolution step 0). If ANY constituent is NOT-YET-VERIFIED, the chain'spatch_base_snapshotmust remain unset (null or missing) and you must defer/suspend further evaluation of the chain until that constituent is re-verified on the current snapshot. (In LEGACY mode, where there is no SNAPSHOT_ID, apply only the "unset" half of this rule, exactly as before.)"patch_status" -
Constituent Errors: If any constituent'sis
"patch_status", set the chain's"ERROR"to"patch_status"."ERROR" -
Constituent Failures: If any constituent'sis
"patch_status", set the chain's"VERIFICATION_FAILED"to"patch_status"."VERIFICATION_FAILED" -
Successful Propagation: If all constituents have finished verification AGAINST THE CURRENT SNAPSHOT (each is inAND — except in LEGACY mode — each terminal constituent's
{"VERIFIED_SECURE", "MITIGATION_PROPOSED", "VERIFICATION_INCOMPLETE"}equals the current SNAPSHOT_ID):patch_base_snapshot- If any constituent is , set the chain's
"MITIGATION_PROPOSED"to"patch_status"."MITIGATION_PROPOSED" - If no constituent is and any constituent is
"MITIGATION_PROPOSED", set the chain's"VERIFICATION_INCOMPLETE"to"patch_status"."VERIFICATION_INCOMPLETE" - If all constituents are , set the chain's
"VERIFIED_SECURE"to"patch_status"."VERIFIED_SECURE"
- If any constituent is
Skip branch isolation, testing, and re-attack steps for the chain finding itself. -
-
Optional Parallel Trajectory Search: If your framework supports subagents, you may spawn multiple concurrent subagents to design diverse patch implementations. Test all generated patches that successfully secure the code without breaking standard functionality, and select the best patch (e.g., the most minimal, readable, and idiomatic fix) rather than just the first one that works.
-
Read the original flawed file to grasp function dependencies and structures.
-
Design a minimal, correct patch to mitigate the security flaw (e.g. adding bound checks, validating sizes, inserting NUL-terminators) without breaking other features.
-
Transactional Isolation (VCS-Agnostic & Safe): To ensure safety, reliability, and VCS-agnosticism, do NOT use VCS-based branch operations (such as,
git branch, orgit checkout).git stashYou must ensure transactional isolation using a method appropriate for the operating environment. Isolation-method gate (mechanical):- If snapshot_pinned is true (PINNED mode) → Option A (Temporary Directory Shadowing) is MANDATORY. Option B and any method that writes under CODE_ROOT are FORBIDDEN (Block A step 4: never write under a pinned snapshot).
- Else if the finding is a RETRY (it already carries a prior history entry or a
"patch") OR (PINNED mode AND its Snapshot Match Check result is NOT_MATCHED) → Option A is MANDATORY (do not risk editing a live tree that no longer matches the finding). Thepatch_base_snapshotqualifier on the NOT_MATCHED clause is essential: in LEGACY mode (snapshot_pinned=false), Block B returns NOT_MATCHED for every finding as an artifact of no snapshot, not as a signal of drift — so NOT_MATCHED must only fire when it means "the snapshot changed" (PINNED), not when it means "no snapshot exists" (LEGACY).PINNED mode AND - Otherwise (snapshot_pinned is false AND first attempt — no prior
history entry and no
"patch") you may choose Option A (recommended), Option B: File-Level Backups, or design/implement Option C: Alternative Isolation (e.g., namespace isolation, container volumes, or local sandboxes) as long as it fully satisfies the invariants below. This covers both LEGACY and HALT mode first-attempt findings (neither has a prior patch to protect, and neither is in the PINNED read-only snapshot regime).patch_base_snapshot
Whichever method you choose, you must guarantee these invariants:- Zero Workspace Pollution: No backup or intermediate build files left in the original source tree.
- Concurrency Safety: Isolation methods must not conflict with other concurrent agents.
- Guaranteed Rollback: Wrap all actions in error traps or
blocks to restore the original state on failure.
try...finally
-
Option A: Temporary Directory Shadowing (Recommended / mandatory when pinned)
-
Warning/Resource constraint: For source trees larger than a few hundred MB, or when many parallel patch workers share the host, and ONLY when NOT in PINNED mode, you may prefer Option B (which touches only the modified files) to avoid exhaustingor memory. In PINNED mode Option B is forbidden regardless of size (the snapshot is read-only); if a full copy will not fit, do not fabricate a verdict — see step 3 HALT handling.
/tmp -
Two-root copy: Create a uniquely generated SHADOW_ROOT (e.g./
mktemp -d) OUTSIDE both CODE_ROOT and anytempfile.mkdtemp()path, then copy the relevant source tree FROM CODE_ROOT (the snapshot resolved in Snapshot & Locator Resolution step 0), NOT from an implicit cwd, into SHADOW_ROOT. CODE_ROOT stays untouched and read-only./workspace/ -
Perform all edits, compilation, and reproduction testing inside SHADOW_ROOT. Never run a mutating/compiling/reproducing command with cwd = CODE_ROOT (Block A step 4).
-
-
Critical Guard (Path and Working Directory Safety): You must ensure that every command executed (compilation, testing, verification) runs with its working directory () explicitly set to SHADOW_ROOT. If the finding's
Cwdcontains absolute paths under CODE_ROOT (the snapshot) or under the live source root, you must rewrite that prefix to the corresponding path under SHADOW_ROOT before execution.run_commandGuard Check: When performing path rewriting, only rewrite paths that represent the target codebase files. If a path starts with or contains asegment (where the Mantis state and findings are stored), do NOT replace its prefix (findings/state must remain in the authoritative/workspace/). This separation is unambiguous because a pinned SNAPSHOT_ROOT/CODE_ROOT never contains astate_root/workspace/segment (guaranteed by the orchestrator's snapshot materialization). Do not execute any modification or verification command against CODE_ROOT or against/workspace/.state_root/workspace/ -
{TARGET_ROOT} token substitution (MANDATORY before executing any stored command):stores
mantis-reproduce/run_commandwith the literal tokenreattack_run_commandfor target-tree paths (Step 3 of reproduce), expecting the caller to substitute it. Before executing any stored{TARGET_ROOT}orrun_command, replace the literalreattack_run_commandtoken with the tree being executed against:{TARGET_ROOT}- For the Block-G unpatched baseline run: substitute the fresh
unpatched CODE_ROOT copy (a fresh copy taken FROM CODE_ROOT).
mktemp -d - For post-patch verification and attack/reattack runs:
substitute SHADOW_ROOT (the patched shadow copy). This substitution
MUST happen BEFORE the CODE_ROOT→SHADOW_ROOT prefix rewriting above
(the token may expand to a CODE_ROOT path that then needs rewriting for
shadow runs). If the literal token survives unsubstituted, the command
will fail → evidence absent → forced ERROR (Block F/Block G treat
command-not-found / No-such-file as EVIDENCE ABSENT). Never execute a
command containing the literal token.
{TARGET_ROOT}
- For the Block-G unpatched baseline run: substitute the fresh
unpatched CODE_ROOT copy (a fresh
-
Generate the unified patch diff by comparing the original source files in CODE_ROOT (the pinned snapshot) with the modified files in SHADOW_ROOT. Use labels so no CODE_ROOT/SHADOW_ROOT absolute prefix leaks into the diff headers.
-
Delete the temporary shadow directory completely when finished.
-
Option B: File-Level Backups (Fallback)
- Concurrency & Exclusivity Warning: Because Option B modifies files directly in the original workspace, it is concurrency-unsafe when run in parallel with other workspace-modifying agents. Sequential execution must be strictly enforced via locking.
- Exclusive Workspace Lock: Before performing backups or edits, the
agent must acquire an exclusive lock on
(using
workspace/.workspace_edit.lockwithfcntl.flockin Python, or a similar system-level lock). The agent must hold this lock continuously throughout the entire patching, verification, re-attack, and restoration lifecycle for the finding, releasing it only when final baseline files are restored or finalized.fcntl.LOCK_EX - Pre-execution Check: Prior to editing, scan the workspace for
pre-existing backup files matching the current finding's ID (e.g.,
). If found, restore and delete them.
*.bak-[current_finding_id] - Create Backups: For every source file you intend to modify, create
a copy with a unique suffix (e.g.,
).
cp target.c target.c.bak-[finding_id] - Net-New Files: Track any newly created files to delete them on rollback.
- Apply Modifications: Edit original target files directly.
- Generate Unified Diff: Compare backup against modified file using
labels to normalize headers (e.g.,
).
diff -u --label target.c --label target.c target.c.bak-[finding_id] target.c
-
3-Way Patch Rebasing (Phase 2 incremental efficiency): When a prior pass's snapshot and patch are still present on disk (see the reachability check below), the patcher can attempt to REBASE a prior pass's patch onto the current snapshot instead of generating a fresh patch from scratch. This is an optimization for the common case where a prior fix still applies with minor line-number shifts.
- How: If ALL reachability conditions (a)-(d) below hold, read
3-Way Patch Rebasing with your
file-reading tool for the 3-way merge mechanics (/
base/oursscratch copies,theirs/git merge-fileinvocation, conflict-marker handling). On ANY uncertainty or if the reference cannot be loaded, fall back to fresh patch generation (Phase-1 behavior).diff3 - When to use (reachability by OBSERVABLE state, not a flag the patcher
cannot read): attempt rebasing ONLY when ALL hold: (a) the prior pass's
snapshot directory AND the file's prior unpatched version actually EXIST
on disk under (retention kept them; if the base snapshot was GC'd this fails → fall back); (b) the finding's
<state_root>/.mantis_snapshots/matches an archived finding with a priorsignature(same bug, same signature) — this is the ARCHIVED finding referenced by the remaining gates; (c) the ARCHIVED finding'spatch_diffis present and DIFFERENT from the currentpatch_base_snapshot(the snapshot the prior patch was verified against has changed; this is the correct "snapshot changed" test — do NOT test Block B on the CURRENT finding, whoseSNAPSHOT_IDis alwaysdiscovery_commitin PINNED mode because researcher stamps it, dedupe backfills it, and plan only copy-verbatim's MATCHED findings preserving the original== SNAPSHOT_ID); if the archived finding'sdiscovery_commitis ABSENT or EMPTY (legacy prior pass, or a pre-Phase-2 patcher that did not write it — detected by the helper-version marker at step 6), the snapshot-changed test is UNKN and you MUST fall back to fresh patch generation (do NOT rebase onto a possibly-unchanged base); and (d) the finding's primary file is inpatch_base_snapshot. Ifchanged_filesis absent (legacy finding), condition (b) cannot be satisfied — fall back to fresh patch generation. Do NOT gate onsignature: that flag is set on the orchestrator and is NOT passed to or readable by the patch stage; the on-disk presence check (a) is the correct observable substitute and works under any retention setting (the default keep-2 already retains the immediately-prior pass).--snapshot_keepandchanged_filesare read fromchanged_files_status(the same state object read forworkspace/.mantis_state.json).active_snapshot
- How: If ALL reachability conditions (a)-(d) below hold, read
3-Way Patch Rebasing with your
file-reading tool for the 3-way merge mechanics (
-
When rebasing SUCCEEDS / FAILS / Guardrail: See 3-Way Patch Rebasing for the success (clean merge → use rebased patch, still run Block G, history note), failure (merge conflict / file deleted / renamed → fall back to fresh patch generation), and guardrail (on ANY uncertainty, fall back to Phase-1; never apply a rebased patch with unresolved conflicts or unrelated changes).
patch-rebased-from: pass_<N-1> -
Unpatched-Baseline Re-run in(Phase 2): When the
--reattacksub-agent is re-attacking a patch on a NEW snapshot (Block B NOT_MATCHED, meaning the snapshot changed since the patch was verified — in PINNED mode only), the re-attack MUST first re-establish the unpatched baseline on the CURRENT snapshot before testing the attack against the patched build. This ensures the re-attack is meaningful: if the bug no longer triggers on the current unpatched snapshot (e.g., upstream code fixed it), the re-attack result is inconclusive, not a pass.@mantis-reproduce --reattack- How: Before running the attack on the patched shadow, run the
reproducer against a FRESH UNPATCHED copy of the current snapshot (per
Block G step 1). If the unpatched baseline does NOT trigger (evidence
absent), set with a history note, and do NOT claim
reattack_status = "inconclusive_baseline_changed"(the patch was not tested against a live bug). If the unpatched baseline DOES trigger, proceed with the attack on the patched build as normal.failed_to_bypass - HALT-mode note: In HALT mode (,
snapshot_pinned=falseSNAPSHOT_ID), Block B is always NOT_MATCHED, but this does NOT represent a genuine snapshot change — it means the tree couldn't be pinned. Thelive:sub-agent skips the C5 re-baseline in HALT (see reproduce C5 HALT guardrail) and follows the existing HALT ceiling.@mantis-reproduce --reattack - Guardrail: This does NOT change the VERIFIED_SECURE gate — Block G still requires the unpatched baseline to trigger. This only adds a re-baseline step to the re-attack path when the snapshot changed.
- How: Before running the attack on the patched shadow, run the
reproducer against a FRESH UNPATCHED copy of the current snapshot (per
Block G step 1). If the unpatched baseline does NOT trigger (evidence
absent), set
-
-
Post-Patch Verification Run: (Skip this step for binary-only targets where no code patch was applied). To confirm the patch works, re-run the reproducer script inside your isolated execution environment. Use the exactand
"repro_file_path"from the reproduction entry to verify the patch."run_command"-
Cwd Enforcement: You must execute the reproducer script with the working directory () set to the shadow directory (if using Option A). Ensure the command targets the copy in the shadow directory, not the original workspace.
Cwd -
Reached-sink evidence definition — Block F (Reached-Sink Evidence Gate). In patch verification the evidence is required on the UNPATCHED baseline, never on the post-patch attack run (a correct patch legitimately stops the input before the sink):
REACHED-SINK EVIDENCE GATE (mechanical): Each reproducer produces REACHED-SINK EVIDENCE via ONE channel, recorded in repro_hints: (a) script/source harness -> write the exact bytes MANTIS_REACHED_ENTRYPOINT to a sidecar file $SENTINEL_FILE and flush+fsync (or unbuffered write) BEFORE invoking the sink. (A file survives a crash that truncates buffered stdout.) (b) binary / firmware / raw-payload -> reached-sink evidence is a captured crash backtrace or sanitizer frame (ASan/UBSan/MSan/TSan) that explicitly names the target sink function (target-produced tracing). A marker written by a wrapper you author BEFORE invoking the target is SETUP EVIDENCE ONLY: it proves "launch attempted," not "sink reached," and does NOT qualify as reached-sink evidence. If no in-path marker (channel a) and no target-produced backtrace/sanitizer trace (channel b) is achievable, the sink is unreached. EVIDENCE PRESENT (reached-sink) = (channel a) sidecar file contains MANTIS_REACHED_ENTRYPOINT written in-path, OR (channel b) target-produced backtrace/sanitizer output names the sink. A wrapper pre-launch marker alone is NOT evidence present. EVIDENCE ABSENT includes: any compiler/build nonzero exit; exit 127 (command not found); exit 2 with a "No such file" message. DECISION GATE (gate the DECISION, not specific verdict strings): - Record repro_status = reproduced OR statically_confirmed ONLY if EVIDENCE is PRESENT. If ABSENT -> repro_status = not_attempted (retry-eligible), STOP. - In patch verification, EVIDENCE is required on the UNPATCHED baseline (Block G), NOT on the post-patch attack run (a correct patch legitimately stops the input before the sink). - If NO evidence channel is achievable for this target, downgrade to not_attempted / VERIFICATION_INCOMPLETE. NEVER synthesize the marker. -
Hard gate before any— Block G (Unpatched-Baseline + Benign-Control Gate). Run it inside SHADOW copies of CODE_ROOT; the "FRESH UNPATCHED copy of SNAPSHOT_ROOT" in Block G step 1 means a fresh copy taken FROM CODE_ROOT:
VERIFIED_SECUREUNPATCHED-BASELINE + POST-PATCH GATE (before any VERIFIED_SECURE): 0. APPLICABILITY: applies ONLY when repro_status == reproduced (a runnable PoC exists). If repro_status == statically_confirmed (no runnable PoC), VERIFIED_SECURE is NOT applicable -> record MITIGATION_PROPOSED (NEVER ERROR). 1. UNPATCHED BASELINE: run the reproducer against a FRESH UNPATCHED copy of SNAPSHOT_ROOT using Block F. If evidence ABSENT or the bug does NOT trigger -> patch_status = ERROR ("reproducer_invalid_on_current_snapshot"); do NOT set VERIFIED_SECURE. 2. POST-PATCH INTEGRITY (distinguish "blocked by patch" from "build break"): - REQUIRED: the patched build must COMPILE with exit 0. Nonzero -> VERIFICATION_INCOMPLETE. - REQUIRED (benign control): run a legitimate BENIGN (non-attack) input through the patched build; it MUST reach the sink path (EVIDENCE PRESENT via Block F) with no crash. This proves the patch narrowed the bug rather than breaking the harness/entrypoint. If NO benign control can be constructed for this target, you may NOT claim VERIFIED_SECURE on a clean-run-only basis -> land VERIFICATION_INCOMPLETE and record why the benign control was infeasible. (Strict mode: a clean compile + clean run WITHOUT a benign control reaching the sink is never sufficient for VERIFIED_SECURE.) 3. ATTACK ON PATCH: run the attack input through the patched build. VERIFIED_SECURE requires ALL of: step 1 triggered on unpatched (evidence present), step 2 integrity holds, step 3 attack does NOT crash/trigger, AND the `--reattack` run also fails to bypass. Otherwise VERIFICATION_FAILED.Sanitizer consistency guardrail (Block G): All runs in this gate (unpatched baseline, benign control, attack, and re-attack) MUST use the SAME sanitizer flags that made the unpatched baseline trigger. If the baseline triggered via UBSan (exit 0, recover-mode), the attack run must also be compiled with UBSan — otherwise the attack might exit 0 without a trace even though the bug is still present, producing a false(INV-1 violation). Record the sanitizer flags used inVERIFIED_SECUREso downstream stages replicate them.repro_hints -
HALT/DEGRADED ceiling: If PATCH_MODE is HALT/DEGRADED (snapshot_pinned false with aSNAPSHOT_ID), authoritative verdicts are forbidden this pass: the best attainable
live:ispatch_status. Never emit"VERIFICATION_INCOMPLETE"in this mode. (LEGACY mode is unaffected.)"VERIFIED_SECURE" -
Missing-file rule: If the reproducer file () or a
repro_file_pathtarget file cannot be found when you attempt verification, setcode_pathstopatch_status. NEVER treat a missing file as "did not reproduce" and NEVER emit"ERROR"from a missing file. (This is also what Block F/Block G's "No such file"/"VERIFIED_SECURE"→ EVIDENCE ABSENT path enforces.)exit 127
-
VERIFIED SECURE (all conditions REQUIRED): Markas
patch_statusONLY if ALL of the following hold:"VERIFIED_SECURE"- Block G passes in full: the UNPATCHED baseline triggered the bug WITH reached-sink evidence (Block F) on a fresh copy of CODE_ROOT; the patched build compiled (exit 0); the benign/integrity control held; and the attack input on the patched build does NOT crash/trigger.
- Re-attack fails to bypass: a fresh, independent
sub-agent (spawned per the block below) writes
@mantis-reproduce --reattack— meaning a non-emptyreattack_status = "failed_to_bypass"array with ≥ 3 valid variant inputs (reproduce Step 3a) ALL failed to trigger the original vulnerability class on the patched shadow. An empty or short variant set caps atreattack_variants, neverVERIFICATION_INCOMPLETE.VERIFIED_SECURE - Not degraded: PATCH_MODE is not HALT/DEGRADED. If PATCH_MODE is
HALT/DEGRADED (snapshot mismatch / unpinnable snapshot), the ceiling is
, never
"VERIFICATION_INCOMPLETE". If Block G reports its baseline could NOT be established (evidence absent or bug does not trigger on the current unpatched snapshot), set"VERIFIED_SECURE"topatch_status("ERROR") — do NOT emit"reproducer_invalid_on_current_snapshot". If Block G's applicability check found"VERIFIED_SECURE", recordrepro_status == statically_confirmed(never ERROR). To ensure true independence, launch a fresh"MITIGATION_PROPOSED"sub-agent against the PATCHED shadow (a copy of SHADOW_ROOT after your patch is applied) to perform the re-attack.@mantis-reproduce --reattack --finding_id=[finding_id]
Important: When calling thesubagent for the re-attack:@mantis-reproduce- If using Option A (Shadowing) (always, in PINNED mode), pass:
--reattack- — the shadow copy that contains your applied patch. Because
--target_root=<PATCHED_SHADOW_ROOT>is AUTHORITATIVE and sentinel-EXEMPT (Block A step 1a/2), the sub-agent reads the patched tree directly.--target_root - — the patched shadow is deliberately mutated, so the reproduce sub-agent MUST skip the snapshot sentinel/match check for it.
--snapshot_pinned=false - — your authoritative state directory (so all
--state_root=<state_root>fields and history land underreattack_*).state_root/workspace/ - of the finding being verified.
--finding_id=[finding_id]
- If using Option B (Backups) or Option C (Alternative) (only
possible in LEGACY mode), pass , both roots pointing at the live workspace (or leave them default
--reattack), and..--finding_id=[finding_id]
The reproducer agent running withwill write its outcomes directly into the primary finding's--reattack,reattack_status,reattack_file_path, andreattack_run_commandfields inside the original workspace findings (reattack_output), keeping the initialstate_root/workspace/findings/fields untouched.repro_* -
VERIFICATION FAILED: If the sandbox execution still triggers the bug, or if your re-attack successfully bypasses your patch, the patch is insufficient. Re-evaluate and adapt your fix.
-
VERIFICATION INCOMPLETE: If the initial post-patch verification run passed but the subsequent re-attack checks failed/timed out due to sandbox infrastructure errors, environment timeouts, or platform restrictions, setto
"patch_status"."VERIFICATION_INCOMPLETE" -
Re-attack unset / SNAPSHOT_MISMATCH → VERIFICATION_INCOMPLETE: Ifis unset (the re-attack sub-agent left it unset with a
reattack_statusorSNAPSHOT_MISMATCHhistory note, or the re-attack did not run at all), setsetup_failedtopatch_status— never"VERIFICATION_INCOMPLETE". An unset re-attack status means independence was not confirmed; aVERIFIED_SECUREmeans the re-attack ran against a different snapshot than the patch was verified on. In either case the patch is not conclusively verified.SNAPSHOT_MISMATCH -
Inconclusive baseline → VERIFICATION_INCOMPLETE: Ifis
reattack_status(the re-attack sub-agent re-ran the unpatched baseline on the current snapshot and the bug no longer triggers — the baseline changed since the patch was verified), set"inconclusive_baseline_changed"topatch_status(or"VERIFICATION_INCOMPLETE"with details"ERROR") — never"reproducer_invalid_on_current_snapshot". The patch was not tested against a live bug on the current snapshot; claiming it is secure would be a false authoritative verdict."VERIFIED_SECURE"
-
-
Extract Patch and Rollback Transaction: (Skip this step for binary-only targets). Do not leave the codebase in an altered state. Once you have a final outcome (eitheror you have exhausted your retries):
VERIFIED_SECURE- If successful, generate a unified diff representing your exact changes and
save it to the field:
"patch_diff"- If using Option A (Shadowing), generate this diff by comparing the original files in CODE_ROOT with the modified files in the shadow directory.
- If using Option B (Backups), generate this diff by comparing the
backup file to the modified file, explicitly labeling the headers to
prevent the backup suffix from appearing (e.g.,
).
diff -u --label target.c --label target.c target.c.bak-[finding_id] target.c - If using Option C (Alternative), generate a clean, VCS-agnostic unified diff comparing the unmodified baseline files to the final patched files.
- If multiple files were modified, generate individual unified diffs and
concatenate them cleanly into the single string. Do NOT use VCS-specific diff commands.
"patch_diff"
- Transactional Clean Up / Rollback: Restore the codebase to its original
state.
- If using Option A (Shadowing), delete the temporary shadow directory
completely (e.g., ). Since the original codebase was never modified, no further restoration is needed.
rm -rf <shadow_directory> - If using Option B (Backups), restore the original files by copying
the backup files back onto the target files (e.g.,
), delete the backup copies (
cp target.c.bak-[finding_id] target.c), and delete any net-new files created during the patching process. Do NOT delete any re-attack/PoC script files written inside therm target.c.bak-[finding_id]directory, any helper scripts written inside theworkspace/reproducers/directory, or the memory database fileworkspace/helpers/; these must be explicitly preserved.workspace/learnings.jsonl - If using Option C (Alternative), execute the corresponding teardown or rollback steps to fully purge all modification artifacts, delete any temporary resources, and ensure the original workspace is left in its clean baseline state.
- If using Option A (Shadowing), delete the temporary shadow directory
completely (e.g.,
- If successful, generate a unified diff representing your exact changes and
save it to the
-
Append to Long-Term Memory (Continuous Reviewing Link): For each security flaw processed, append a single structured JSON line to a workspace database file named(using append mode). This allows the strategist (
workspace/learnings.jsonl) to read these historical records in subsequent passes and avoid proposing fixes for already patched files./mantis-plan- Memory Entry Format:
{"title": "[security_flaw_title]", "code_paths": ["[path1:line1]"], "status": "[VERIFIED_SECURE / MITIGATION_PROPOSED / VERIFICATION_INCOMPLETE / VERIFICATION_FAILED / ERROR]", "patch_base_snapshot": "[current SNAPSHOT_ID, or omit in LEGACY mode]", "snapshot": "[current SNAPSHOT_ID, or omit in MODE-OFF]"}
- Memory Entry Format:
-
Token-Optimized File Updates: To minimize LLM output tokens, do not re-emit or manually rewrite the entire JSON object in your output. Instead, write a reusable helper script (e.g.,) during your first finding update. Make the FIRST line of the helper a version marker comment:
state_root/workspace/helpers/append_patch.py. Before reusing an existing helper, read its first line: if it does NOT contain the exact marker# MANTIS_HELPER_VERSION = 2, the helper is stale (from an older pass/version that does not writeMANTIS_HELPER_VERSION = 2) — regenerate it. Only when the marker matches may you reuse it: simply execute the existing helper with the new parameters to append the required fields.patch_base_snapshotYou must append the following to the existing object:- A field (one of
"patch_status","VERIFIED_SECURE","MITIGATION_PROPOSED","VERIFICATION_INCOMPLETE", or"VERIFICATION_FAILED")."ERROR" - A field set to the current SNAPSHOT_ID (Snapshot & Locator Resolution step 0) — the snapshot this verdict was earned on. Omit this field only in LEGACY mode (no SNAPSHOT_ID exists). This is what makes the snapshot-aware skip (Idempotency Guarantee) and chain propagation correct across passes.
"patch_base_snapshot" - If a patch was successful, a field containing the unified diff.
"patch_diff" - If a re-attack was performed, the ,
"reattack_status","reattack_file_path","reattack_run_command", and"reattack_output"fields (each object in"reattack_variants"MUST have EXACTLY"reattack_variants").{"description": "...", "triggered": true/false} - An entry to the array:
"history"
json{ "stage": "patch", "action": "patched", "details": "Patch status evaluated as [VERIFIED_SECURE/MITIGATION_PROPOSED/VERIFICATION_INCOMPLETE/VERIFICATION_FAILED/ERROR] on snapshot [patch_base_snapshot or 'legacy']", "pass_number": <current_pass_number>, "timestamp": "<current_iso8601_timestamp>" } - A
When complete, notify the user.
修复已成功复现的安全漏洞,同时不破坏标准代码行为。
按以下步骤执行补丁制作与验证阶段:
-
快照与定位器解析(在接触任何代码前执行一次):0a. 通过**Block A(定位器解析)**解析CODE_ROOT、SNAPSHOT_ID、snapshot_pinned和state_root:
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.[!NOTE] CURRENT-PASS CHECK (防御性检查;绑定保证由场景2中的工具提供): 如果mantis-pipeline-adapter存在且active_snapshot,则将该快照视为当前流程的过期快照——停止操作并提示"stale active_snapshot: pass mismatch",或降级为HALT模式(active_snapshot.pass != state.pass_number等效为false:无权威结论,Block B返回NOT_MATCHED,复现状态设为snapshot_pinned)。此检查用于捕获自定义工具在Stage 15流程递增时保留not_attempted但未重新固定的情况。参考元代理会在每个流程重新固定快照,因此此检查在该场景下不会触发。Block B本身无法检测此问题(它仅感知active_snapshot,不感知snapshot_id)。pass本阶段:mantis-patch会读取目标代码(并非仅处理问题记录的阶段),因此需完整执行Block A的步骤1–6。CODE_ROOT为不可变的固定快照;请勿在该目录下执行写入、编译或复现脚本(Block A步骤4)——所有修改操作需在私有shadow副本中执行(步骤2)。0b. 根据解析结果确定PATCH_MODE:- 若不存在且未传入
active_snapshot/--snapshot_root/--snapshot_id⇒ LEGACY模式(当前行为;步骤3中的新限制不生效)。--target_root - 若⇒ PINNED模式(以下完整限制生效)。
snapshot_pinned == true - 若且SNAPSHOT_ID以字面量
snapshot_pinned == false开头 ⇒ HALT/DEGRADED模式(尝试固定快照但失败;本次流程禁止给出权威结论——参见步骤3)。live:
0c. 针对每个处理的问题,通过**Block B(快照匹配检查)**计算其MATCHED/NOT_MATCHED结果:SNAPSHOT MATCH CHECK for finding F (decides MATCHED vs NOT_MATCHED): 1. If snapshot_pinned is false -> NOT_MATCHED. Stop. 2. Read F.discovery_commit: - missing OR empty OR the literal "MIXED" -> NOT_MATCHED. - not exactly equal to SNAPSHOT_ID -> NOT_MATCHED. - exactly equal to SNAPSHOT_ID -> MATCHED. There is no other route to MATCHED; never fuzzy-compare. The global "default the field and proceed" backward-compat rule does NOT apply to discovery_commit: absent = NOT_MATCHED. (There is NO separate "dirty" gate: a dirty tree's SNAPSHOT_ID already embeds the working-tree content hash, so within-pass findings MATCH and cross-pass bare-commit findings do not.)MATCHED/NOT_MATCHED结果会在步骤2(隔离模式选择)和步骤3(结论判定)中使用。在PINNED模式下,该结果不会单独降低结论等级:NOT_MATCHED的问题会通过步骤3的限制针对当前快照重新验证,若验证通过则标记当前。patch_base_snapshot - 若
-
加载待修复的问题记录: 读取目录下的JSON文件。过滤掉已针对当前快照完成终端验证的问题——即仅当问题的
workspace/findings/为patch_status或"VERIFIED_SECURE"且其"MITIGATION_PROPOSED"等于当前SNAPSHOT_ID时,才视为已处理(快照与定位器解析步骤0)。若终端状态的问题其patch_base_snapshot不存在/为空/不同,则视为过期——需纳入重新验证范围。(在LEGACY模式下,无SNAPSHOT_ID,仅通过patch_base_snapshot过滤,与当前逻辑一致。)在纳入的问题中,保留满足以下条件的记录:(patch_status为repro_status,或问题为漏洞利用链,例如标题以"reproduced"开头,或历史记录中有"Exploit Chain:"阶段的条目,或存在非空的"chainer"属性)。若无符合条件的记录,通知用户。"constituent_findings" -
生成并应用最小化补丁: 针对每个已复现的安全漏洞:
-
目标无关性(二进制 vs 源代码): 若目标为源代码,按以下描述生成并应用代码补丁。若目标为无源代码的编译二进制文件或固件镜像,请勿尝试修改二进制文件或编写二进制补丁脚本。跳过分支隔离/修改/差异步骤,生成无需深入技术细节的通用高层缓解建议。将此缓解字符串填入字段,并设置
patch_diff为"patch_status"。"MITIGATION_PROPOSED" -
漏洞利用链: 若问题为漏洞利用链(通过标题中的、历史记录细节或存在非空的
"Exploit Chain:"属性识别),请勿生成代码补丁或差异文件。相反,通过读取"constituent_findings"UUID数组识别其子问题。监控这些子问题的补丁状态(磁盘上对应的文件为"constituent_findings")。重要提示: 需等待批次中所有单个问题处理完成后,再评估漏洞利用链的状态,以便获取磁盘上最新的子问题补丁状态。workspace/findings/<uuid>.json使用以下传播规则评估漏洞利用链状态(按顺序执行):-
有效性检查: 读取每个子问题的有效性。若任何子问题的
"status"为"status",则更新漏洞利用链问题的"FALSE_POSITIVE"以匹配(例如"status"),并立即跳过该链的后续补丁/验证操作。若任何子问题的"FALSE_POSITIVE"为"status",则通过递归跟踪其"DUPLICATE"属性解析至其标准问题。"duplicate_of"重复问题解析流程:- 定位问题文件: 重复问题(或重复链中的任何父问题)的文件可能已被移动。按以下顺序搜索:
<uuid>.json- (活跃问题)
workspace/findings/<uuid>.json - (已去重的垃圾文件)
workspace/findings/.trash/<uuid>.json - 或
workspace/archive/findings_pass_*/<uuid>.json(过往流程的归档文件)。若在上述位置均未找到文件,视为文件缺失错误。workspace/archive/loop*_findings/<uuid>.json
- 循环检测: 在解析过程中维护已访问的问题UUID集合。若在当前解析链中遇到已访问的UUID,触发验证错误(检测到循环)。
- 最大深度限制: 将递归深度限制为最多5步。若链深度超过该限制,终止并报告错误。
- 提取状态: 一旦解析至标准问题(不为
"status"且无"DUPLICATE"属性),使用该标准问题的"duplicate_of"和"status"进行所有下游检查和传播。请勿将漏洞利用链问题本身更新为"patch_status"。"DUPLICATE"
- 定位问题文件: 重复问题(或重复链中的任何父问题)的文件可能已被移动。按以下顺序搜索
-
文件缺失: 若任何子问题的JSON文件在磁盘上缺失,将链的设为
"patch_status"。"ERROR" -
子问题未设置或过期(待处理): 若子问题的未设置(null或缺失,表明尚未复现/处理),或其
"patch_status"为终端状态但"patch_status"不存在/为空/与当前SNAPSHOT_ID不同(针对过期快照验证——快照与定位器解析步骤0),则视为未验证。若任何子问题未验证,链的patch_base_snapshot必须保持未设置(null或缺失),且需推迟/暂停对该链的进一步评估,直到该子问题针对当前快照重新验证完成。(在LEGACY模式下,无SNAPSHOT_ID,仅应用"未设置"部分的规则,与当前逻辑一致。)"patch_status" -
子问题错误: 若任何子问题的为
"patch_status",将链的"ERROR"设为"patch_status"。"ERROR" -
子问题验证失败: 若任何子问题的为
"patch_status",将链的"VERIFICATION_FAILED"设为"patch_status"。"VERIFICATION_FAILED" -
成功传播: 若所有子问题均已针对当前快照完成验证(每个子问题的状态为,且——除LEGACY模式外——每个终端状态子问题的
{"VERIFIED_SECURE", "MITIGATION_PROPOSED", "VERIFICATION_INCOMPLETE"}等于当前SNAPSHOT_ID):patch_base_snapshot- 若任何子问题为,将链的
"MITIGATION_PROPOSED"设为"patch_status"。"MITIGATION_PROPOSED" - 若无子问题为且任何子问题为
"MITIGATION_PROPOSED",将链的"VERIFICATION_INCOMPLETE"设为"patch_status"。"VERIFICATION_INCOMPLETE" - 若所有子问题均为,将链的
"VERIFIED_SECURE"设为"patch_status"。"VERIFIED_SECURE"
- 若任何子问题为
跳过链问题本身的分支隔离、测试和重新攻击步骤。 -
-
可选并行轨迹搜索: 若你的框架支持子代理,可生成多个并发子代理以设计多种补丁实现方案。测试所有能成功修复代码且不破坏标准功能的生成补丁,并选择最佳补丁(例如最精简、易读且符合编码规范的修复方案),而非仅选择第一个可用的补丁。
-
读取存在漏洞的原始文件,掌握函数依赖关系和结构。
-
设计最小化、正确的补丁以缓解安全漏洞(例如添加边界检查、验证大小、插入NUL终止符),同时不破坏其他功能。
-
事务隔离(与VCS无关且安全): 为确保安全性、可靠性和与VCS无关性,请勿使用基于VCS的分支操作(如、
git branch或git checkout)。git stash需使用适合操作环境的方法确保事务隔离。隔离方法限制(硬性规则):- 若snapshot_pinned为true(PINNED模式)→ 必须使用Option A(临时目录Shadowing)。禁止使用Option B及任何在CODE_ROOT下写入的方法(Block A步骤4:绝不能在固定快照下写入)。
- 若问题为重试(已存在先前的历史条目或
"patch"),或(PINNED模式且其快照匹配检查结果为NOT_MATCHED)→ 必须使用Option A(避免编辑与问题不再匹配的活跃代码树)。PINNED模式下NOT_MATCHED条件的限定至关重要:在LEGACY模式(snapshot_pinned=false)下,Block B对所有问题返回NOT_MATCHED是无快照的产物,而非代码漂移的信号——因此仅当NOT_MATCHED表示"快照已更改"(PINNED模式)时生效,而非"无快照存在"(LEGACY模式)。patch_base_snapshot - 其他情况(snapshot_pinned为false且首次尝试——无先前的历史条目且无
"patch")可选择Option A(推荐)、Option B:文件级备份,或设计/实现Option C:替代隔离方案(例如命名空间隔离、容器卷或本地沙箱),只要完全满足以下不变量即可。此情况涵盖LEGACY和HALT模式下的首次尝试问题(两者均无先前补丁需保护,且均不在PINNED只读快照机制下)。patch_base_snapshot
无论选择哪种方法,必须保证以下不变量:- 零工作区污染: 原始源代码树中不得遗留任何备份或中间构建文件。
- 并发安全: 隔离方法不得与其他并发代理冲突。
- 保证回滚: 将所有操作包裹在错误捕获或块中,确保失败时恢复原始状态。
try...finally
-
Option A:临时目录Shadowing(推荐 / 固定模式下强制使用)
-
警告/资源限制: 若源代码树超过几百MB,或多个并行补丁共享主机,且仅当非PINNED模式时,可选择Option B(仅修改相关文件)以避免耗尽或内存。在PINNED模式下,无论大小均禁止使用Option B(快照为只读);若完整副本无法容纳,请勿生成结论——参见步骤3的HALT处理。
/tmp -
双根复制: 创建唯一生成的SHADOW_ROOT(例如/
mktemp -d),且该目录需在CODE_ROOT和任何tempfile.mkdtemp()路径之外,然后将相关源代码树从CODE_ROOT(快照与定位器解析步骤0中解析的快照)复制到SHADOW_ROOT,而非从隐式当前工作目录复制。CODE_ROOT保持未修改且只读。/workspace/ -
所有编辑、编译和复现测试操作均在SHADOW_ROOT内执行。绝不能以cwd=CODE_ROOT执行修改/编译/复现命令(Block A步骤4)。
-
-
关键防护(路径和工作目录安全): 必须确保执行的每个命令(编译、测试、验证)的工作目录()明确设置为SHADOW_ROOT。若问题的
Cwd包含CODE_ROOT(快照)或活跃源代码根目录下的绝对路径,需在执行前将该前缀重写为SHADOW_ROOT下的对应路径。run_command防护检查: 执行路径重写时,仅重写代表目标代码库文件的路径。若路径以开头或包含该段(Mantis状态和问题记录存储位置),请勿替换其前缀(问题记录/状态必须保留在权威的/workspace/中)。这种区分是明确的,因为固定的SNAPSHOT_ROOT/CODE_ROOT绝不会包含state_root/workspace/段(由编排器的快照实例化保证)。请勿针对CODE_ROOT或/workspace/执行任何修改或验证命令。state_root/workspace/ -
{TARGET_ROOT}令牌替换(执行任何存储命令前必须执行):存储
mantis-reproduce/run_command时使用字面令牌reattack_run_command表示目标树路径(复现步骤3),期望调用方进行替换。执行任何存储的{TARGET_ROOT}或run_command前,需将字面令牌reattack_run_command替换为执行对应的代码树:{TARGET_ROOT}- 对于Block G未打补丁基线运行:替换为从CODE_ROOT复制的全新未打补丁副本(全新副本)。
mktemp -d - 对于补丁后验证和攻击/重新攻击运行:替换为SHADOW_ROOT(已打补丁的shadow副本)。此替换必须在上述CODE_ROOT→SHADOW_ROOT前缀重写之前执行(令牌可能扩展为CODE_ROOT路径,之后需针对shadow运行进行重写)。若字面令牌未被替换,命令将失败→证据缺失→强制标记为ERROR(Block F/Block G将命令未找到/无此文件视为证据缺失)。绝不能执行包含字面令牌的命令。
{TARGET_ROOT}
- 对于Block G未打补丁基线运行:替换为从CODE_ROOT复制的全新未打补丁副本(全新
-
通过比较CODE_ROOT(固定快照)中的原始源文件与SHADOW_ROOT中的修改文件,生成统一补丁差异。使用标签避免CODE_ROOT/SHADOW_ROOT绝对前缀泄露到差异头中。
-
完成后彻底删除临时shadow目录。
-
Option B:文件级备份(备选)
- 并发与排他性警告: 由于Option B直接修改原始工作区中的文件,当与其他修改工作区的代理并行运行时,存在并发不安全问题。必须通过锁定严格强制顺序执行。
- 排他工作区锁: 在执行备份或编辑前,代理必须获取的排他锁(Python中使用
workspace/.workspace_edit.lock和fcntl.flock,或类似系统级锁)。代理必须在针对该问题的整个补丁制作、验证、重新攻击和恢复生命周期内持续持有该锁,仅当最终基线文件恢复或完成时才释放。fcntl.LOCK_EX - 执行前检查: 编辑前,扫描工作区中是否存在与当前问题ID匹配的预存在备份文件(例如)。若存在,恢复并删除这些文件。
*.bak-[current_finding_id] - 创建备份: 针对每个要修改的源文件,创建带有唯一后缀的副本(例如)。
cp target.c target.c.bak-[finding_id] - 新增文件跟踪: 跟踪所有新建文件,以便回滚时删除。
- 应用修改: 直接编辑原始目标文件。
- 生成统一差异: 比较备份文件与修改后的文件,使用标签标准化头信息(例如)。
diff -u --label target.c --label target.c target.c.bak-[finding_id] target.c
-
三路补丁重定基(第二阶段增量效率优化): 若过往流程的快照和补丁仍存在于磁盘上(参见以下可达性检查),补丁器可尝试将过往流程的补丁重定基到当前快照,而非从头生成新补丁。这是针对过往修复仍可应用(仅行号有微小变化)常见场景的优化。
- 方法: 若以下所有可达性条件(a)-(d)均满足,使用文件读取工具查看3-Way Patch Rebasing了解三路合并机制(/
base/ours临时副本、theirs/git merge-file调用、冲突标记处理)。若存在任何不确定性或无法加载参考文档,回退到从头生成补丁(第一阶段行为)。diff3 - 使用时机(通过可观察状态判断可达性,而非补丁器无法读取的标志): 仅当以下所有条件满足时尝试重定基:(a) 过往流程的快照目录及文件的过往未打补丁版本实际存在于磁盘上的下(保留机制未清理;若基线快照已被垃圾回收则失败→回退);(b) 当前问题的
<state_root>/.mantis_snapshots/与带有先前signature的归档问题匹配(同一漏洞,同一签名)——这是其余条件所引用的归档问题;(c) 归档问题的patch_diff存在且与当前patch_base_snapshot不同(先前补丁验证的快照已更改;这是正确的"快照已更改"测试——请勿针对当前问题测试Block B,在PINNED模式下当前问题的SNAPSHOT_ID始终discovery_commit,因为研究人员会标记它,去重会回填它,且计划仅复制保留原始== SNAPSHOT_ID的MATCHED问题);若归档问题的discovery_commit不存在或为空(旧版过往流程,或未写入该字段的第二阶段前补丁器——通过步骤6的辅助版本标记检测),则快照更改测试未知,必须回退到从头生成补丁(请勿重定基到可能未更改的基线);(d) 问题的主文件在patch_base_snapshot中。若changed_files缺失(旧版问题),则条件(b)无法满足——回退到从头生成补丁。请勿以signature作为判断依据:该标志由编排器设置,不会传递给或被补丁器读取;磁盘存在检查(a)是正确的可观察替代方案,适用于任何保留设置(默认保留2个流程,已保留紧邻的过往流程)。--snapshot_keep和changed_files从changed_files_status读取(与workspace/.mantis_state.json读取的同一状态对象)。active_snapshot
- 方法: 若以下所有可达性条件(a)-(d)均满足,使用文件读取工具查看3-Way Patch Rebasing了解三路合并机制(
-
重定基成功/失败/防护: 参见3-Way Patch Rebasing了解成功(干净合并→使用重定基补丁,仍需运行Block G,历史记录添加)、失败(合并冲突/文件删除/重命名→回退到从头生成补丁)和防护规则(任何不确定性下,回退到第一阶段;绝不应用带有未解决冲突或无关更改的重定基补丁)。
patch-rebased-from: pass_<N-1> -
模式下的未打补丁基线重新运行(第二阶段): 当
--reattack子代理在新快照上重新攻击补丁时(Block B返回NOT_MATCHED,意味着自补丁验证后快照已更改——仅PINNED模式),重新攻击必须首先在当前快照上重新建立未打补丁基线,然后再针对打补丁后的构建测试攻击。这确保重新攻击有意义:若漏洞在当前未打补丁快照上不再触发(例如上游代码已修复),则重新攻击结果无意义,而非通过。@mantis-reproduce --reattack- 方法: 在针对打补丁后的shadow运行攻击前,针对当前快照的全新未打补丁副本运行复现脚本(按Block G步骤1)。若未打补丁基线未触发(证据缺失),设置并添加历史记录,且请勿标记
reattack_status = "inconclusive_baseline_changed"(补丁未针对当前活跃漏洞测试)。若未打补丁基线触发,继续针对打补丁后的构建执行攻击。failed_to_bypass - HALT模式说明: 在HALT模式下(,
snapshot_pinned=falseSNAPSHOT_ID),Block B始终返回NOT_MATCHED,但这并不代表真正的快照更改——而是表示代码树无法被固定。live:子代理在HALT模式下跳过C5重新基线步骤(参见复现C5 HALT防护规则),并遵循现有HALT限制。@mantis-reproduce --reattack - 防护规则: 这不会改变VERIFIED_SECURE限制——Block G仍要求未打补丁基线触发。仅当快照更改时,在重新攻击路径中添加重新基线步骤。
- 方法: 在针对打补丁后的shadow运行攻击前,针对当前快照的全新未打补丁副本运行复现脚本(按Block G步骤1)。若未打补丁基线未触发(证据缺失),设置
-
-
补丁后验证运行:(针对无源代码的二进制目标,跳过此步骤,因为未应用代码补丁)。为确认补丁有效,在隔离执行环境中重新运行复现脚本。使用复现条目中的精确和
"repro_file_path"验证补丁。"run_command"-
工作目录强制要求: 必须将复现脚本的工作目录()设置为shadow目录(若使用Option A)。确保命令针对shadow目录中的副本,而非原始工作区。
Cwd -
到达Sink的证据定义 — Block F(到达Sink的证据限制)。在补丁验证中,证据需来自未打补丁的基线,而非补丁后的攻击运行(正确的补丁会在输入到达Sink前阻止它):
REACHED-SINK EVIDENCE GATE (mechanical): Each reproducer produces REACHED-SINK EVIDENCE via ONE channel, recorded in repro_hints: (a) script/source harness -> write the exact bytes MANTIS_REACHED_ENTRYPOINT to a sidecar file $SENTINEL_FILE and flush+fsync (or unbuffered write) BEFORE invoking the sink. (A file survives a crash that truncates buffered stdout.) (b) binary / firmware / raw-payload -> reached-sink evidence is a captured crash backtrace or sanitizer frame (ASan/UBSan/MSan/TSan) that explicitly names the target sink function (target-produced tracing). A marker written by a wrapper you author BEFORE invoking the target is SETUP EVIDENCE ONLY: it proves "launch attempted," not "sink reached," and does NOT qualify as reached-sink evidence. If no in-path marker (channel a) and no target-produced backtrace/sanitizer trace (channel b) is achievable, the sink is unreached. EVIDENCE PRESENT (reached-sink) = (channel a) sidecar file contains MANTIS_REACHED_ENTRYPOINT written in-path, OR (channel b) target-produced backtrace/sanitizer output names the sink. A wrapper pre-launch marker alone is NOT evidence present. EVIDENCE ABSENT includes: any compiler/build nonzero exit; exit 127 (command not found); exit 2 with a "No such file" message. DECISION GATE (gate the DECISION, not specific verdict strings): - Record repro_status = reproduced OR statically_confirmed ONLY if EVIDENCE is PRESENT. If ABSENT -> repro_status = not_attempted (retry-eligible), STOP. - In patch verification, EVIDENCE is required on the UNPATCHED baseline (Block G), NOT on the post-patch attack run (a correct patch legitimately stops the input before the sink). - If NO evidence channel is achievable for this target, downgrade to not_attempted / VERIFICATION_INCOMPLETE. NEVER synthesize the marker. -
前的硬性限制 — Block G(未打补丁基线 + 良性控制限制)。在CODE_ROOT的SHADOW副本中运行;Block G步骤1中的"SNAPSHOT_ROOT的全新未打补丁副本"指从CODE_ROOT复制的全新副本:
VERIFIED_SECUREUNPATCHED-BASELINE + POST-PATCH GATE (before any VERIFIED_SECURE): 0. APPLICABILITY: applies ONLY when repro_status == reproduced (a runnable PoC exists). If repro_status == statically_confirmed (no runnable PoC), VERIFIED_SECURE is NOT applicable -> record MITIGATION_PROPOSED (NEVER ERROR). 1. UNPATCHED BASELINE: run the reproducer against a FRESH UNPATCHED copy of SNAPSHOT_ROOT using Block F. If evidence ABSENT or the bug does NOT trigger -> patch_status = ERROR ("reproducer_invalid_on_current_snapshot"); do NOT set VERIFIED_SECURE. 2. POST-PATCH INTEGRITY (distinguish "blocked by patch" from "build break"): - REQUIRED: the patched build must COMPILE with exit 0. Nonzero -> VERIFICATION_INCOMPLETE. - REQUIRED (benign control): run a legitimate BENIGN (non-attack) input through the patched build; it MUST reach the sink path (EVIDENCE PRESENT via Block F) with no crash. This proves the patch narrowed the bug rather than breaking the harness/entrypoint. If NO benign control can be constructed for this target, you may NOT claim VERIFIED_SECURE on a clean-run-only basis -> land VERIFICATION_INCOMPLETE and record why the benign control was infeasible. (Strict mode: a clean compile + clean run WITHOUT a benign control reaching the sink is never sufficient for VERIFIED_SECURE.) 3. ATTACK ON PATCH: run the attack input through the patched build. VERIFIED_SECURE requires ALL of: step 1 triggered on unpatched (evidence present), step 2 integrity holds, step 3 attack does NOT crash/trigger, AND the `--reattack` run also fails to bypass. Otherwise VERIFICATION_FAILED.Sanitizer一致性防护规则(Block G): 此限制中的所有运行(未打补丁基线、良性控制、攻击和重新攻击)必须使用与未打补丁基线触发时相同的sanitizer标志。若基线通过UBSan触发(退出码0,恢复模式),攻击运行也必须使用UBSan编译——否则攻击可能无痕迹退出码0,但漏洞仍存在,导致错误的(违反INV-1)。在VERIFIED_SECURE中记录使用的sanitizer标志,以便下游阶段复用。repro_hints -
HALT/DEGRADED限制: 若PATCH_MODE为HALT/DEGRADED(snapshot_pinned为false且SNAPSHOT_ID为开头),本次流程禁止给出权威结论:最高可设置的
live:为patch_status。在此模式下绝不能输出"VERIFICATION_INCOMPLETE"。(LEGACY模式不受影响。)"VERIFIED_SECURE" -
文件缺失规则: 若尝试验证时无法找到复现文件()或
repro_file_path目标文件,设置code_paths为patch_status。绝不能将文件缺失视为"未复现",也绝不能因文件缺失输出"ERROR"。(这也是Block F/Block G中"无此文件"/"VERIFIED_SECURE"→证据缺失路径所强制的。)exit 127
-
VERIFIED SECURE(所有条件必须满足): 仅当以下所有条件满足时,将标记为
patch_status:"VERIFIED_SECURE"- Block G完全通过: 未打补丁基线在CODE_ROOT的全新副本上触发漏洞且有到达Sink的证据(Block F);打补丁后的构建编译通过(退出码0);良性/完整性控制通过;针对打补丁后的构建执行攻击未崩溃/未触发漏洞。
- 重新攻击无法绕过: 全新独立的子代理(按以下块生成)写入
@mantis-reproduce --reattack——即非空的reattack_status = "failed_to_bypass"数组包含≥3个有效变体输入(复现步骤3a),且所有变体在打补丁后的shadow上均无法触发原始漏洞类型。若变体集为空或数量不足,最高标记为reattack_variants,绝不能标记为VERIFICATION_INCOMPLETE。VERIFIED_SECURE - 未降级: PATCH_MODE不为HALT/DEGRADED。若PATCH_MODE为HALT/DEGRADED(快照不匹配/无法固定快照),最高标记为,绝不能标记为
"VERIFICATION_INCOMPLETE"。若Block G报告无法建立基线(证据缺失或漏洞在当前未打补丁快照上未触发),设置"VERIFIED_SECURE"为patch_status("ERROR")——请勿输出"reproducer_invalid_on_current_snapshot"。若Block G的适用性检查发现"VERIFIED_SECURE",记录repro_status == statically_confirmed(绝不能标记为ERROR)。为确保真正独立,针对已打补丁的shadow(应用补丁后的SHADOW_ROOT副本)启动全新的"MITIGATION_PROPOSED"子代理执行重新攻击。@mantis-reproduce --reattack --finding_id=[finding_id]
重要提示: 调用子代理执行重新攻击时:@mantis-reproduce- 若使用Option A(Shadowing)(PINNED模式下始终使用),传入:
--reattack- ——包含已应用补丁的shadow副本。由于
--target_root=<PATCHED_SHADOW_ROOT>是权威且豁免sentinel检查(Block A步骤1a/2),子代理将直接读取已打补丁的代码树。--target_root - ——已打补丁的shadow是故意修改的,因此复现子代理必须跳过针对它的sentinel/匹配检查。
--snapshot_pinned=false - ——权威状态目录(以便所有
--state_root=<state_root>字段和历史记录存入reattack_*)。state_root/workspace/ - ——待验证的问题ID。
--finding_id=[finding_id]
- 若使用Option B(备份)或Option C(替代方案)(仅LEGACY模式下可能),传入,两个根目录指向活跃工作区(或留空默认
--reattack),以及.。--finding_id=[finding_id]
运行的复现代理会将结果直接写入原始工作区问题记录(--reattack)中的state_root/workspace/findings/、reattack_status、reattack_file_path和reattack_run_command字段,同时保留初始reattack_output字段不变。repro_* -
VERIFICATION FAILED: 若沙箱执行仍触发漏洞,或重新攻击成功绕过补丁,则补丁不足。重新评估并调整修复方案。
-
VERIFICATION INCOMPLETE: 若初始补丁后验证运行通过,但后续重新攻击检查因沙箱基础设施错误、环境超时或平台限制失败/超时,设置为
"patch_status"。"VERIFICATION_INCOMPLETE" -
重新攻击未设置 / SNAPSHOT_MISMATCH → VERIFICATION_INCOMPLETE: 若未设置(重新攻击子代理因
reattack_status或SNAPSHOT_MISMATCH历史记录未设置,或重新攻击未执行),设置setup_failed为patch_status——绝不能设置为"VERIFICATION_INCOMPLETE"。未设置的重新攻击状态意味着未确认独立性;VERIFIED_SECURE意味着重新攻击针对的快照与补丁验证的快照不同。无论哪种情况,补丁均未得到最终验证。SNAPSHOT_MISMATCH -
基线无意义 → VERIFICATION_INCOMPLETE: 若为
reattack_status(重新攻击子代理在当前快照上重新运行未打补丁基线,漏洞不再触发——自补丁验证后基线已更改),设置"inconclusive_baseline_changed"为patch_status(或"VERIFICATION_INCOMPLETE"并附带详情"ERROR")——绝不能设置为"reproducer_invalid_on_current_snapshot"。补丁未针对当前快照上的活跃漏洞测试;声称其安全会给出错误的权威结论。"VERIFIED_SECURE"
-
-
提取补丁并回滚事务:(针对无源代码的二进制目标,跳过此步骤)。请勿让代码库处于修改状态。一旦获得最终结果(或已耗尽重试次数):
VERIFIED_SECURE- 若成功,生成代表确切修改的统一差异并保存到字段:
"patch_diff"- 若使用Option A(Shadowing),通过比较CODE_ROOT中的原始文件与shadow目录中的修改文件生成差异。
- 若使用Option B(备份),通过比较备份文件与修改后的文件生成差异,明确标记头信息以避免备份后缀出现(例如)。
diff -u --label target.c --label target.c target.c.bak-[finding_id] target.c - 若使用Option C(替代方案),生成清晰的、与VCS无关的统一差异,比较未修改的基线文件与最终打补丁后的文件。
- 若修改了多个文件,生成单独的统一差异并清晰地拼接成单个字符串。请勿使用特定于VCS的差异命令。
"patch_diff"
- 事务清理 / 回滚: 将代码库恢复到原始状态。
- 若使用Option A(Shadowing),彻底删除临时shadow目录(例如)。由于原始代码库从未被修改,无需进一步恢复。
rm -rf <shadow_directory> - 若使用Option B(备份),通过将备份文件复制回目标文件恢复原始文件(例如),删除备份副本(
cp target.c.bak-[finding_id] target.c),并删除补丁过程中创建的所有新增文件。请勿删除rm target.c.bak-[finding_id]目录下的任何重新攻击/PoC脚本文件、workspace/reproducers/目录下的任何辅助脚本,或内存数据库文件workspace/helpers/;这些必须明确保留。workspace/learnings.jsonl - 若使用Option C(替代方案),执行相应的拆除或回滚步骤,彻底清除所有修改产物,删除任何临时资源,确保原始工作区恢复到干净的基线状态。
- 若使用Option A(Shadowing),彻底删除临时shadow目录(例如
- 若成功,生成代表确切修改的统一差异并保存到
-
追加到长期内存(持续审查链接): 针对每个处理的安全漏洞,以追加模式向名为的工作区数据库文件追加一行结构化JSON。这允许策略器(
workspace/learnings.jsonl)在后续流程中读取这些历史记录,避免为已打补丁的文件重复提出修复方案。/mantis-plan- 内存条目格式:
{"title": "[security_flaw_title]", "code_paths": ["[path1:line1]"], "status": "[VERIFIED_SECURE / MITIGATION_PROPOSED / VERIFICATION_INCOMPLETE / VERIFICATION_FAILED / ERROR]", "patch_base_snapshot": "[current SNAPSHOT_ID, or omit in LEGACY mode]", "snapshot": "[current SNAPSHOT_ID, or omit in MODE-OFF]"}
- 内存条目格式:
-
令牌优化的文件更新: 为最小化LLM输出令牌,请勿在输出中重新生成或手动重写整个JSON对象。相反,在首次更新问题记录时编写可复用的辅助脚本(例如)。在辅助脚本的第一行添加版本标记注释:
state_root/workspace/helpers/append_patch.py。复用现有辅助脚本前,读取其第一行:若不包含确切标记# MANTIS_HELPER_VERSION = 2,则该辅助脚本已过期(来自未写入MANTIS_HELPER_VERSION = 2的旧流程/版本)——重新生成。仅当标记匹配时才可复用:只需使用新参数执行现有辅助脚本以追加所需字段。patch_base_snapshot必须向现有对象追加以下内容:- 字段(值为
"patch_status"、"VERIFIED_SECURE"、"MITIGATION_PROPOSED"、"VERIFICATION_INCOMPLETE"或"VERIFICATION_FAILED"之一)。"ERROR" - 字段,设置为当前SNAPSHOT_ID(快照与定位器解析步骤0)——即获得此结论的快照。仅在LEGACY模式下(无SNAPSHOT_ID)省略此字段。这是跨流程实现快照感知跳过(幂等性保证)和链传播正确性的关键。
"patch_base_snapshot" - 若补丁成功,添加字段,包含统一差异。
"patch_diff" - 若执行了重新攻击,添加、
"reattack_status"、"reattack_file_path"、"reattack_run_command"和"reattack_output"字段("reattack_variants"中的每个对象必须恰好包含"reattack_variants")。{"description": "...", "triggered": true/false} - 向数组添加条目:
"history"
json{ "stage": "patch", "action": "patched", "details": "Patch status evaluated as [VERIFIED_SECURE/MITIGATION_PROPOSED/VERIFICATION_INCOMPLETE/VERIFICATION_FAILED/ERROR] on snapshot [patch_base_snapshot or 'legacy']", "pass_number": <current_pass_number>, "timestamp": "<current_iso8601_timestamp>" }
完成后,通知用户。