mcpField
B
blue-team

blue-team

github.com/gaasher开发17835 次安装17 周前更新
代码仓库

关于 blue-team

blue-team 是针对 red-team 测试或 CI 报告中的具体失败目录进行修复的防御技能。它每次处理一个根因类别,只有在故障减少且没有回归时才保留补丁。

主要功能

  1. 01导入 red-team 或 JUnit 故障
  2. 02按根因类别归组案例
  3. 03使用回归防护验证修复
  4. 04逐项保留或撤销补丁
  5. 05跟踪残留故障与迭代预算
  6. 06准备 PR 交接材料

适用场景

  1. 01修复 red-team 测试发现的问题
  2. 02处理一批 CI 测试失败
  3. 03加固过滤器并检查新增误报

安装

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

$npx skills add https://github.com/gaasher/agent-loop-skills --skill blue-team

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
run.example.yaml
tests.run.yaml
tools/
ingest.py
verify.py

详细介绍

蓝队

一个防御性修复循环——与 red-team 相反。现在可以修改目标产物;反馈信号由两部分组成,类似于 optimize-loop:一个必须保持通过的门槛(之前通过的内容不能回归),以及一个必须下降的指标(未解决失败类别的数量,目标为零)。将一组具体失败案例交给它,逐个根因类别进行修复。每次迭代修复一个类别,然后运行 tools/verify.py;只有在修复该类别且没有回归时才保留补丁,否则就撤销。持续循环,直到所有类别都已解决(归零)或预算耗尽,然后将补丁集作为拉取请求提交。这是查找→修复流程中的修复部分(见配对)。

失败案例来自真实来源;tools/ingest.py 会将它们规范化到同一个目录中:

  • oracle 模式——red-team 的 failures.jsonl:每个案例都是一个输入,其中目标的判定与真实情况预言机不一致。目标与预言机现在达成一致时,案例即为已解决;回归指某个良性的 <holdout> 输入新出现了不一致(通常是新增了过度拦截)。
  • tests 模式——CI/CD 测试失败报告(pytest --junitxml / JUnit XML,或失败的节点 ID 列表):每个案例都是一个失败测试。测试现在通过时,案例即为已解决;回归指任何其他原本通过的测试现在失败。

适用场景

用于修复代码或用户拥有的防护栏/分类器/过滤器/提示词/API 中一组具体失败案例——无论是红队目录,还是 CI 运行中的失败测试——在不破坏已有功能的前提下,将未解决类别的数量降至零。class 是循环作为一个整体予以解决的根因组(红队技术,或 CI 失败领域/测试类)。

默认情况下,根据来源选择匹配的模式(红队用 oracle,CI/CD 用 tests)。例外情况:在没有单独功能测试套件的 oracle 模式下,仅用 <holdout> 作为回归防护;在 tests 模式下,由测试套件中此前已通过的测试作为防护。此工具不用于发现新失败(请运行 red-team),也不用于修改真实标准(预言机、测试或 <holdout>)。

设置

以交互方式解析绑定项。如果存在 loop.run.yaml,则加载它,用一行确认各项值,然后跳到循环步骤。否则:在 Claude Code 上(可使用 AskUserQuestion 工具),为每个绑定项推断一个可能的值并给出建议;在其他宿主上,则将每项作为引用提示逐一询问。然后写入 loop.run.yaml,并在创建任何其他文件之前确认。两个配置示例: examples/run.example.yaml(oracle 模式)和 examples/tests.run.yaml(tests 模式)。

绑定项含义默认值推断方式
<source>失败用例的来源:oracle(红队)或 tests(CI/CD)—红队 failures.jsonl → oracle;失败的 pytest/JUnit → tests
<target_files>循环可编辑以修复目标的文件—失败背后的源代码/护栏/分类器
<catalogue>待解决的失败用例,格式为 JSONL;使用 tools/ingest.py 构建(见下文)<sandbox_root>/catalogue.jsonl红队的 <failures_log>,或 JUnit 报告
<oracle_cmd>(oracle 模式) 真实判定结果(已冻结),与红队相同的 stdin→判定结果约定—参考检查器/策略实现
<holdout>(oracle 模式) 必须继续通过的良性输入(回归防护)<sandbox_root>/holdout.jsonloracle 判定为正确的已知良性输入
<test_cmd>(tests 模式) 运行测试套件并写入 JUnit XML;回归信息从中读取—pytest --junitxml=<junit>(或任何能生成 JUnit 的运行器)
<junit>(tests 模式) <test_cmd> 写入的 JUnit XML 路径<sandbox_root>/junit.xml—
<iter_strategy>branches(每个保留的修复对应一个提交 → 纳入 PR)或 snapshots(每次迭代对应一个文件夹)branches工作区有未提交更改/非 git 工作区 → snapshots
<pr_branch>修复提交到的分支,以及 PR 从该分支发起blue-team/<tag>将今天的日期用作 <tag>
<sandbox_root>快照和运行记录的存放位置./sandbox—
<budget>最大迭代次数8—
<patience>在对某个类别尝试失败 N 次后放弃,并将其标记为遗留项3—

<skill_dir> 是此技能的安装文件夹;写入 loop.run.yaml 时,请替换为实际路径。

先构建目录:使用 tools/ingest.py 将任意来源规范化为 {id, ..., class}:

python3 <skill_dir>/tools/ingest.py --from red-team --in <failures.jsonl> --out <catalogue>   # oracle mode
python3 <skill_dir>/tools/ingest.py --from junit    --in <report.xml>     --out <catalogue>   # tests mode

每次迭代的信号是 tools/verify.py,模式需与 <source> 匹配:

# oracle mode — <target_cmd> runs <target_files>, e.g. "python3 ./guardrail.py"
python3 <skill_dir>/tools/verify.py --target "<target_cmd>" --oracle "<oracle_cmd>" \
  --catalogue <catalogue> --holdout <holdout>
# tests mode — <test_cmd> writes the JUnit report verify.py then reads
python3 <skill_dir>/tools/verify.py --test-cmd "<test_cmd>" --junit <junit> --catalogue <catalogue>

无论哪种模式,都会打印一个 JSON 对象: {mode, open_classes, closed_classes, open_count, closed_count, regressions, regression_count, still_failing}。

循环

复制此检查清单,并逐项勾选:

  • 第 0 轮 — 基线:在 <source> 模式下运行 tools/verify.py;将未解决类别 (应与目录一致)记录为当前状态,并确认 regression_count 为 0 — 如果不是,则目录或 留出集存在问题,请先修复,再处理目标。记录基线行。将 <target_files> 的原始副本 保存到 <sandbox_root>/iter0/(快照模式),或记下分支基点(分支模式)——这就是最终 交接进行差异比较的基线,也是第 1 轮恢复到的快照。
  • 在 branches 模式下,在新分支上开始运行:git checkout -b <pr_branch>。
  • 对于第 N 轮(≥1):在编辑之前,将当前、修改前的 <target_files> 快照保存到 iter<N>/(或记下 git HEAD),以便丢弃时能精确恢复到此状态。
  • 选择一个未解决类别。阅读目录中的 still_failing 示例和建议的修复方案,并从 根本原因入手修改 <target_files> — 一项修复应关闭该类别的所有载荷(例如,只 需统一规范大小写一次,而不是为每个关键词分别处理)。每轮只处理一个类别,以便明确 归因每次改动。
  • 检查信号:运行 tools/verify.py。如果 regression_count > 0(门槛),或目标类别 仍未解决,则丢弃 — 恢复快照 / 执行 git reset --hard。verify.py 的回归检查 就是门槛:在 oracle 模式下,回归指新变为失败的 <holdout> 用例(例如,某项修复因 过度拦截良性输入而关闭了绕过);在 tests 模式下,回归指补丁破坏了任何此前通过的测试。
  • 如果没有回归且 open_count 严格下降,则保留。在 branches 模式下提交: git commit -am "close <class>: <one-line fix>"。追加一行台账记录。
  • 如果某个类别经过 <patience> 次尝试仍未解决,则将其标记为未解决残项并继续处理, 不要反复折腾。当 open_count = 0(已清空)、达到 <budget>,或所有剩余类别都是残项时 停止。<budget> 计算的是尝试次数(每次保留或丢弃都算一轮),而非已关闭的类别数 — 丢弃也会消耗预算。

停止时,将工作文件恢复到最佳轮次(关闭类别最多且无回归),并报告:已关闭类别与残项数量、 已解决的失败(oracle 模式:绕过 / 过度拦截的分类),以及避免的回归。然后创建拉取请求(参见 交接)。

修复工具包。 在 tests 模式下,补丁是常规缺陷修复,按失败领域分组,每轮处理一个领域。 在 oracle 模式下(强化防护规则 / 过滤器),可参考以下根因修复模式,对应红队攻击工具包:

  • 匹配前先规范化 — 大小写折叠、去 leet 化(同形异义字符 / leet → 字母)、去除空格和标点, 对 unicode 进行 NFKC 规范化。一次规范化即可关闭大小写 / leetspeak / 空格类问题。
  • 扩展策略覆盖范围 — 将缺失的同义词 / 扩展词加入拦截集合(missing-synonym 类别), 按 oracle 的分类处理,而非临时添加字符串。
  • 收紧过宽规则 — 将匹配范围限定为完整单词 / 正确上下文,避免误触发良性输入(overblock 类别);这是最常见的回归来源。

注意交互顺序(两种模式均适用):先修复收窄范围 / 过宽规则的问题,再做大范围修复。 去除分隔符的修复(关闭 spacing)可能会将良性输入重新组合成过宽子串,悄然导致 overblock 类别再次出现 — 大范围代码改动也可能重新引入较窄修复原本防住的测试失败。先修复 范围较窄 / 过宽的情况,再推广处理。

Ledger

<sandbox_root>/ledger.tsv,以制表符分隔,描述中绝不使用逗号。regr = regression_count 本次迭代(门槛:0 表示通过);status ∈ {keep,discard,baseline,residual}。表头 iter class_targeted regr open_classes status description:

iter	class_targeted	regr	open_classes	status	description
0	-	0	5	baseline	catalogue: 5 open classes
1	case-bypass	0	4	keep	case-fold the input before matching
2	leetspeak	1	4	discard	de-leet regex also over-blocked a holdout input (regression)
3	leetspeak	0	3	keep	de-leet via translate table, holdout clean
4	missing-synonym	0	2	keep	add passphrase/credentials/api-key to the policy set
5	overblock	0	1	keep	require whole-word "secret key", not bare "secret"
6	spacing	0	0	keep	strip non-alphanumerics before matching — dry

报告最佳迭代(regr 为 0 且 open_classes 最低的迭代),不一定是最后一次。

约束

  • 只能编辑 <target_files>。 真实依据——oracle + <holdout>(oracle 模式)或测试套件(tests 模式)——以及 tools/verify.py 都是冻结的;编辑用于衡量修复的内容等于人为制造通过(与 red-team 和 optimize-loop 的规则相同)。如果 oracle 或测试本身有误,应将其报告为发现,而不是在此处修补。
  • 修复根因,而不是载荷。 一项修复应关闭某个类别的所有条目;只修补单个示例字符串,而同类项仍然失败,意味着该类别并未关闭。这与 red-team 的类别计数方式一致,确保两个循环对“关闭”的定义相同。
  • 回归门槛不可妥协。 如果补丁破坏了之前通过的内容——新增过度拦截/绕过(oracle 模式)或导致之前通过的测试失败(tests 模式)——这就是回归,而非进展;无论关闭了多少类别,都必须撤销。优先采用范围更窄的修复,而非大范围修改。
  • 每次迭代处理一个类别,以便明确归因每次改动,并能低成本撤销错误修复。
  • 修改须限于项目现有依赖集(标准库即可);操作范围限于仓库和 <sandbox_root>;不要暂停循环询问是否继续——一直运行,直到没有待处理项、预算耗尽或只剩残留问题。

交接:拉取请求

交付物是一份便于人工审查的拉取请求——这是与目标负责人沟通的接口(与 Copilot Autofix 一样,最终审批权由人工保留)。停止时,确保工作树处于最佳迭代状态:

  • 在 branches 模式下,每项保留的修复都已作为提交保存在 <pr_branch> 上,提交说明写明类别 + 一行修复内容。推送并使用 gh pr create 创建 PR,正文使用 ledger(问题目录 → 修复、已关闭的类别、列出的残留问题、避免的回归),并为每个已关闭类别提供一个可复现示例。
  • 创建 PR 前确认一次——推送分支和创建 PR 会对外产生影响;绝不可静默自动推送。
  • **降级处理,不要失败:**如果没有远程仓库,或 gh 不可用/未通过身份验证,仍须完成交接——将提交保留在 <pr_branch> 上,在 <sandbox_root> 中写入 git format-patch 输出和 PR_BODY.md,并告知用户一条可自行创建 PR 的命令。在 snapshots 模式(无 git)下,则输出 <target_files> 相对于 iter0/ 基线副本的统一 diff,并另附 PR_BODY.md。

配对

此技能负责修复——是查找→修复循环的后半部分。它假设问题目录已存在;它自身会关闭类别,但不会查找新问题。

  1. 查找 — red-team 针对冻结的目标运行 → failures.jsonl(不同类别)。
  2. 修复(本循环)— 在 red-team 两次运行之间修补目标,使其在门槛下关闭这些类别,绝不要在一次 red-team 运行期间修补。
  3. 重新验证— 针对已修补目标运行一次全新的 red-team,确认每个类别已关闭,并发现修复引入的任何新类别(本循环中的回归门槛已防护过度拦截方向的风险)。

确保两个 Agent 相互独立——编写问题目录的攻击者不应评估自己的补丁。 purple-team 循环负责协调完整的查找 → 修复 → 重新验证周期,直到一次全新的查找未发现问题;本技能有意仅涵盖修复阶段。

评论

支持 Markdown