这是 Java Chains V2 的公开、多模块插件开发仓库。它提供可直接下载的
plugin-api / common 编译依赖、一个零第三方依赖的 Starter,以及一个
带真实 LibrarySet 的 FineReport 示例。
本仓坚持:
一个 plugins/<plugin-id> Maven 模块
= 一个独立插件 jar
= 一个 META-INF/chains-plugin.json
= 一个 manifest id / PluginUnit
根 POM 只聚合模块,不是可安装插件。
要求:JDK 8、Maven 3、bash、jar、unzip,以及 sha256sum 或
shasum。
git clone https://github.com/Java-Chains/chains-plugin-demo.git
cd chains-plugin-demo
./build.shbuild.sh 会依次:
- 校验仓库内公开 API jar 的 SHA-256。
- 将 API/common 注册到本地 Maven。
- 运行所有模块的
mvn clean verify。 - 检查每个插件 jar 的 manifest、插件/宿主 API 版本、pluginId、LibrarySet 和禁止包。
产物:
plugins/starter-demo/target/chains-plugin-starter-demo-2.0.0-beta7.1.jar
plugins/finereport/target/chains-plugin-finereport-2.0.0-beta7.1.jar
建议先 Fork 本仓库到自己的 GitHub 账号或组织,再让 AI 在 Fork 中开发。不要只 复制某个插件目录,因为根 POM、公开 API jar、构建校验和 Release workflow 是一套 完整的公开插件开发环境。
可直接告诉 AI:
先完整读取 AGENTS.md 和 .codex/skills/chains-plugin-authoring/SKILL.md,
使用 plugins/starter-demo 创建新插件,保留 .github/workflows/tag-build.yml,
完成后运行 mvn clean verify 和 ./build.sh,并按 README 的版本规则创建 tag。
不要引入任何非公开仓库、源码、jar 或本机路径。
Cursor 和 Claude Code 的兼容入口分别位于
.cursor/skills/chains-plugin-authoring/SKILL.md 与
.claude/skills/chains-plugin-authoring/SKILL.md。Fork 后应保留这些入口以及
.codex skill,让 AI 能先读取本仓的插件 API、Tag、LibrarySet、测试和发布约定。
仓库的 tag-build.yml 会监听任意 Git tag。
Fork 后保留该文件并启用 GitHub Actions,即可在自己的仓库自动编译和发布。
发布版本统一使用:
<Java Chains API 版本>.<插件发布序号>
插件发布序号从 1 开始,每次发布递增;例如宿主 API 为 2.0.0-beta7 时,
前两次插件发布依次是 2.0.0-beta7.1、2.0.0-beta7.2。tag、根/子模块
Maven 版本以及每个 chains-plugin.json 的插件 version 必须完全一致,
manifest 的 apiVersion 仍只填写宿主 API 版本 2.0.0-beta7。
推送 tag 前,先同步版本并完成本地验证:
./build.sh
git tag 2.0.0-beta7.1
git push origin main
git push origin 2.0.0-beta7.1tag 推送后,GitHub Actions 会在该 tag 指向的提交上:
- 使用 JDK 8 运行完整
./build.sh。 - 收集每个
plugins/*模块独立生成的chains-plugin-*.jar。 - 生成插件 jar 的
SHA256SUMS与包含 tag、commit、宿主 API 版本的BUILD-INFO.txt。 - 校验 tag 的末段插件发布序号从
1开始,并确认每个 manifest 的插件版本 与 tag 一致。 - 上传一份 Actions artifact,便于排查单次构建。
- 创建同名 GitHub Release,并把插件 jar、
SHA256SUMS、BUILD-INFO.txt作为正式下载入口;带-beta、-rc等后缀的 tag 会标记为 prerelease。
对外发布和下载以 GitHub Release 为准,Actions artifact 仅用于构建排查。
只有完整构建和所有 PluginUnit 校验通过后才会上传 artifact 和 Release 附件。
tag 只是发布批次标识,不会自动改写 POM、插件 manifest 或 jar 文件名;打 tag
前必须自行确保这些版本正确。普通分支 push 和 pull request 仍由
verify.yml 负责验证,因此 tag push 不会重复跑通用 CI。
若 tag 已存在但尚无 Release,可在 GitHub Actions 中打开 Build tagged plugins,
选择 Run workflow 并输入已有 tag。workflow 会检出该 tag,而不是当前 main,
再执行相同的构建、校验和 Release 发布。为保护已经发布的二进制,同名 Release
存在时 workflow 会失败,不会覆盖或删除原附件。
Java Chains 2.0.0-beta7 的插件开发 jar 已提交在 deps/api/:
| 坐标 | 是否必需 | 说明 |
|---|---|---|
org.vulhub:java-chains-plugin-api:2.0.0-beta7 |
必需 | Gadget、注解、Tag、Param、PluginClasses |
org.vulhub:java-chains-common:2.0.0-beta7 |
可选 | 宿主公开且明确放行的 helper |
单独安装依赖:
./scripts/install-api-deps.sh
mvn clean verify这两个依赖必须使用 provided。它们由宿主提供,禁止复制到
libraries/ 或 shade 进插件 jar。来源 tag、commit 和 SHA-256 见
deps/api/README.md。
| 模块 | 适合学习 | 第三方 jar |
|---|---|---|
plugins/starter-demo |
Payload、Gadget、Tag、Param、YAML、preset、字节码衔接 | 无 |
plugins/finereport |
private LibrarySet、间接依赖、隔离 ClassLoader、真实插件迁移 | 有 |
建议先复制 Starter,再阅读 FineReport。不要从复杂厂商依赖开始创建第一个插件。
最小文本链:
StarterDemoPayload → StarterDemoText(END)
字节码类型流:
StarterDemoPayload
→ StarterDemoBytecodeBridge
→ BytecodeConvert
→ Sleep(second=2, END)
逐段匹配:
StarterDemoPayload.gadgetTags ∩ StarterDemoBytecodeBridge.provides
StarterDemoBytecodeBridge.accepts ∩ BytecodeConvert.provides
BytecodeConvert.accepts ∩ Sleep.provides
用户看到的链从左向右,执行值从右向左返回。中间 Gadget 必须先执行
chain.doCreate(context),再包装下游真实返回值。
- 复制
plugins/starter-demo为plugins/<plugin-id>。 - 在根 POM
<modules>中加入新模块。 - 选择稳定的小写 manifest id;带
-的 id 映射为合法 Java 包段。 - 更新
META-INF/chains-plugin.json的id、插件version、apiVersion和libraries。 - Gadget 使用
@GadgetMeta + @ChainSpec;Payload 使用@PayloadAnnotation。 - Gadget id 使用简单类名并保持全局唯一;
@Param放在 public 实例字段。 - 为每个节点添加
metadata/nodes/<Id>.yaml;常用安全链放在metadata/presets/*.yaml。 - 增加契约测试,再运行单模块和全仓构建。
mvn -pl plugins/<plugin-id> -am clean verify
./build.sh插件版本和宿主 API 版本是两个概念。例如本次插件版本是
2.0.0-beta7.1,但 manifest apiVersion 仍是 2.0.0-beta7;末尾 .1
只表示针对该宿主大版本的第 1 次插件发布。
子模块显式声明 API/common,版本和 provided scope 由根 POM 统一管理:
<dependency>
<groupId>org.vulhub</groupId>
<artifactId>java-chains-plugin-api</artifactId>
</dependency>
<dependency>
<groupId>org.vulhub</groupId>
<artifactId>java-chains-common</artifactId>
</dependency>不要依赖 java-chains-core、java-chains-server、java-chains-nodes 或
chains-all。插件也不能假设宿主应用中的第三方库对其 ClassLoader 可见。
FineReport 模块演示了完整绑定:
plugins/<id>/libs/vendor.jar
→ POM 编译依赖
→ jar 内 libraries/<setId>/vendor.jar
→ chains-plugin.json libraries[].entries
→ @GadgetMeta(libraries={"<setId>"})
运行时动态加载 victim 类应使用:
Class<?> victim = PluginClasses.forName("com.vendor.Victim");
ClassLoader loader = PluginClasses.contextLoader();@Dependency 只用于 Catalog 展示,不会加载 jar。Maven 的 systemPath
只解决本地厂商 jar 的编译,因此 Maven 会给出可移植性警告;真正的运行时
可见性仍由插件 jar 内的 LibrarySet、manifest 与节点绑定决定。
最小 manifest:
{
"id": "your-plugin",
"version": "2.0.0-beta7.1",
"apiVersion": "2.0.0-beta7",
"libraries": []
}宿主根据 manifest id 自动注入 plugin:<id> Catalog 来源标签。不要把
它写进 provides、accepts、gadgetTags 或手写进 catalogTags。
Tag 必须表达真实 Java 类型:
| 下游返回值 | 左侧常用 accepts |
|---|---|
原始类文件 byte[] |
Bytecode |
处理后类文件 byte[] |
BytecodeConvertTag |
TemplatesImpl |
TemplatesImplChain |
JDBC URL String |
JdbcUrlChains / JdbcUrlWithSQLChains |
| 终点 | 叶子的 provides 包含 END |
- 注解是节点注册和链路匹配的真相;YAML 只补 Catalog、i18n 与参数文案。
- YAML
params、presetargs、input targetfield都使用 Java 字段名。 - preset id 使用
<pluginId>.前缀,不手写source。 - 默认教学 preset 必须无出网、低副作用;Sleep 参数字段是
second。
把某一个子模块 jar 复制到宿主 chains-config/plugins/,或在 Plugins 页面
Upload / Install,然后 Reload。不要安装根项目,也不要把两个 manifest 合并
进一个 jar。
安装后检查:
- PluginUnit 状态为 loaded/ready。
- Catalog 节点的
pluginId正确。 - Starter 两个 preset 出现,source 为
plugin:starter-demo。 StarterDemoPayload → StarterDemoText可以生成 UTF-8 文本。- 字节码 preset 使用
Sleep.second=2并通过链校验。 - FineReport 的 LibrarySet jar 数量与 manifest entries 一致。
| 现象 | 优先检查 |
|---|---|
| Catalog 没有节点 | 包名、注解、manifest、Reload 日志 |
| next 为空 | 左侧 outgoing tags 与右侧 provides/id/alias |
| 链末失败 | 真实叶子是否提供 END |
ClassNotFoundException |
LibrarySet 路径、manifest entries、注解绑定、TCCL |
| preset 不出现 | metadata/presets/ 路径、id 前缀、jar 布局 |
| 参数不生效 | 是否使用 Java 字段名而非展示名 |
| 单测通过但安装失败 | 测试 classpath 太宽;补隔离 ClassLoader/宿主冒烟 |
CI 和 build.sh 会拒绝插件 jar 中出现:
org/vulhub/javachains/api/
org/vulhub/javachains/common/
org/vulhub/javachains/core/
org/vulhub/javachains/server/
org/vulhub/javachains/nodes/
third-libs/
BOOT-INF/
com/ar3h/
Codex、Cursor 与 Claude Code 的入口均指向本仓公开
chains-plugin-authoring skill。