troublemaker

by wonderfulcode1

0 开发与运行时github未核验到 manifest收录于 08-16

故意注入一个已知的小错误到可丢弃的git工作树中,以便学习者练习查找和修复它。教学工具 - 阅读README了解其教育理念和安全性保证。

Deliberately inject a small, known bug into a disposable git worktree so learners can practice finding and fixing it. A teaching tool - read the README for its educational philosophy and safety guarantees.

安装

dsh plugin --profile web add github:wonderfulcode1/troublemaker

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

安装与环境配置指引、插件开发教程见 DSH 中文社区文档 ↗

安装即在你的机器上以你的权限运行第三方代码——它可读写文件、使用凭据、访问网络,DSH 的工具审批不会为插件代码加沙箱。「检测到 manifest」仅代表发现 dsh.bundle / dsh.plugin 清单,不构成兼容性或安全审查;安装前请审阅源码,不熟悉的插件先在不含密钥的环境试用。

README

目录

往一个一次性的 git worktree 里故意注入一个小而明确的 bug,让学习者练习"找到它、修好它"。

English

troublemaker 是一个教学工具。它故意"制造麻烦"——但只发生在一个它为你创建的一次性 worktree 里,绝不会动你的真实代码——并用"探针-预言机"流水线来判定学习者的修复是否成功。

状态:v0.1.0 教学原型。 在把它用于练习之外的任何场景之前,请先阅读当前局限。

它为什么存在(教学理念)

调试是一项只能靠调试来练的技能。真实代码库太大、太吵、也太珍贵,不适合拿来练习;完全虚构的练习题又太假,提不起劲。

troublemaker 取中间路线:它拿你自己的仓库(或自带的示例仓库),检出一个一次性的 worktree,然后注入一个小而明确、可描述的 bug——比如一个单字符的 off-by-one 变异。学习者随后:

  1. 阅读 bug 描述;
  2. 在 worktree 里找到变异点;
  3. 亲手修复;
  4. 反复运行检查,直到报告 solved;
  5. 回滚 worktree。

这个工具存在的意义是让练习可验证,而不是骗人。每个注入的场景都自带:

  • 探针(probe)——插入源码的一行日志,运行时报告 bug 行为;
  • 预言机(oracle)——该探针应有的正确值;
  • 注入时的 kill check——证明预言机确实能检测出注入的 bug(检测不出的变异会立即回滚);
  • gate 与 regression——修复后的代码必须继续通过的检查命令。

这与真实的 bug 注入教学系统是同一套模式:难度在场景里,机制是诚实的——预言机从不谎报正确行为是什么。注入的 bug 不会对你隐藏:bug 描述会点名它,而真相就藏在 worktree 与你已提交代码的 diff 里。

这个工具不是什么

  • 不是破坏工具。 它碰不到你的工作区,也碰不到任何你没指向的仓库,更不会修改已提交的分支——见安全保障。
  • 不是安全工具,不是模糊测试器,也不是"测试你有多容易被骗"的基准。
  • 不是生产软件。 它是一个用于学习 bug 注入教学原理的 MVP,公开出来是为了让别人研究、复用和改进这个想法。

未经他人同意,把 bug 注入别人的代码,是对这个工具的滥用。设计上已经尽量让这种滥用变难(worktree、要求仓库干净、可回滚),但没有任何工具能拦住铁了心的滥用者。请把它用在它该用的地方:教学与学习。

安全保障

以下是这个工具实际强制实施的技术保障,不是口头承诺:

  1. 只碰一次性 worktree。 每个场景都在 <repo>/.dsh-teaching-worktrees/<scenarioId> 下,由 git worktree add --detach <path> HEAD 创建。你的工作区、分支、stash、已提交历史都不会被修改。rollback 会删除 worktree 并清理陈旧的 worktree 记录。
  2. 拒绝脏仓库。 inject 要求 git diff 与 git diff --cached 都为干净状态,未提交的工作永远不会被带进或破坏某个场景。
  3. bug 一定可被检测。 注入时会跑 kill check:driver 必须走到探针路径,且预言机必须在变异代码上观察到不匹配。检测不到的变异会被回滚、注入失败。你永远不会拿到一个检查器都看不见的 bug。
  4. 仓库必须包含场景目标文件,且每个锚点必须恰好出现一次。 找不到预期的原始源码时,注入会大声失败(并回滚)——绝不猜测、绝不部分变异。
  5. 失败即回滚。 inject 中任何一步失败,都会先删掉它创建的 worktree 再报错。
  6. 无网络、无遥测、无隐藏行为。 包零运行时依赖,只执行本地 git 和 node 命令,全部源码可读。
  7. check 只读。 它在 worktree 里运行场景的 gate、driver、regression 并读取文件;除 inject 已产生的 .dsh-teaching 产物外,不写任何东西。
  8. 命令不经 shell 执行。 工具直接用参数向量启动 git 和 node(manifest 里的命令按空白切分);场景无法通过引号把 shell 元字符偷渡进来——详见下方局限。

你需要知道的一个注意事项

场景里的 gate、driver、regression 字符串是会在你机器上、以你的用户权限、在 worktree 内执行的命令。这是设计使然——场景要能被检查,就必须运行代码。请把场景 manifest 当作可执行文件对待:只注入你信任的场景,且只注入你拥有的仓库。内置场景只运行 node --check 和一个纯 node 回归脚本。

当前局限

v0.1.0 明确不做的事情:

  • 只有一个内置场景。 目前只有 v0-retain-items(一个小型 retainer 类里的 off-by-one)。它针对自带的示例练习仓库(examples/practice-repo);要在别处使用,仓库必须包含同样的目标文件与锚点。
  • 还没有场景编写格式。 场景是代码而非数据:目前没有文档化的"仅靠 manifest 编写新场景"的方式,不改包就写不了新场景。磁盘上的 worktree manifest(dsh-teaching-scenario v1 格式)会被读写,但编写工具是后续工作。
  • 只支持零依赖场景。 gate 与 regression 用纯 node 运行;worktree 里不会安装 node_modules 或工具链(本工具所源自的 harness 版本会链接 node_modules,这个独立 CLI 不会)。
  • 命令只按空白切分。 manifest 里的 gate/regression 字符串不能包含带引号的参数或 shell 运算符。这是刻意的安全取舍(不用 shell),代价是复杂命令需要包装脚本。
  • 没有鉴权、没有远程面。 一切都在本地 CLI。没有服务器、没有 GUI、也没有任何联网使用方式。
  • Windows 上测试过,要求 git 在 PATH 上。 换行处理会把注入文件规范化为 LF;其他平台应该能工作,但未测试。
  • fix 只对内置场景有效。 已知修复命令需要场景定义;它无法修复包中没有定义该场景的 worktree。
  • 没有并发控制。 两个进程同时对同一个仓库注入没有协调。
  • 注入的探针行是普通的 console.log。 学习者删除或改名探针行会触发 tampered 判定——这是设计意图——但大量日志也可能拖慢 driver。

安装

npm install -g dsh-troublemaker
troublemaker --help

或免安装运行:

npx dsh-troublemaker --help

五分钟快速上手

自带的示例是一个极小的零依赖仓库。初始化、注入、亲手修复、回滚:

git clone https://github.com/wonderfulcode1/troublemaker.git
cd troublemaker/examples/practice-repo

git init -b main
git add -A
git commit -m "pristine practice repo"

troublemaker inject .
# Injected scenario v0-retain-items into .../.dsh-teaching-worktrees/v0-retain-items
#   gate: PASS
#   kill check: mismatch (oracle detects the injected bug)

troublemaker check . v0-retain-items
# verdict: bug-alive

# 在 .dsh-teaching-worktrees/v0-retain-items/src/retainer.js 里手工修复
# (把 `<=` 改回 `<`),然后:

troublemaker check . v0-retain-items
# verdict: solved

troublemaker rollback . v0-retain-items

CLI 参考

troublemaker list <repo>                     列出某个仓库下已注入的场景
troublemaker inject <repo> [--scenario ID]   注入内置场景(默认 v0-retain-items)
troublemaker check <repo> <scenarioId>       运行完整检查流水线(判定 + 探针)
troublemaker fix <repo> <scenarioId>         应用已知修复(仅内置场景,演示用)
troublemaker rollback <repo> <scenarioId>    删除场景 worktree
troublemaker scenarios                       列出内置场景
troublemaker --version | --help

--json   以 JSON 输出命令结果

工作原理

学习者循环

  1. inject——要求仓库干净。创建 detached worktree,应用变异(每个锚点必须恰好匹配一次),写入场景 manifest,跑 gate,再跑 driver 并证明预言机能检测出 bug(kill check)。
  2. check——按顺序短路判定:
    • tampered——某探针行不再以其源码文件中的原样出现。
    • type-fail——gate 命令在注入后的源码上失败。
    • bug-alive——driver 跑通了,但至少一个探针与预言机不一致。
    • incomplete——driver 没有触发某个必需探针。
    • regression-failed——探针全部匹配,但回归套件失败。
    • solved——探针全部匹配且回归套件通过。
  3. fix——应用已知修复(仅内置场景;学习者应当亲手修复)。
  4. rollback——删除 worktree 并清理陈旧记录。

状态在磁盘上

每个答案都在调用时由 worktree 的 manifest.json 和源码推导而来。工具不保留任何跨场景内存,所以多个 shell 看到的是同一份事实,一个进程创建的 worktree 可以由另一个进程检查或回滚。

内置场景

v0-retain-items 在自带示例仓库的 ItemRetainer.push 中注入一个 off-by-one:比较符 < 被变异为 <=,导致 retainer 多保留一个条目(maxItems + 1)。探针在 finish() 内触发,报告保留条目、seen 计数与 omitted 计数;预言机固定了正确值。这也是 DeepSeek Harness 教学功能(bug 注入教学)使用的同一场景,此处移植为零依赖独立运行。

项目状态

v0.1.0 以一个诚实的 MVP 身份发布。它刻意保持小巧,上面的局限都写了出来而不是藏着掖着,整个工具是一份可以通读到底的教学产物。欢迎在 issue 区提交 bug 报告和下一个场景的想法。

License

MIT——见 LICENSE。

原始 README: https://github.com/tmpdot/troublemaker/blob/main/README.zh-CN.md ↗