Skip to content

Repository files navigation

Java Chains V2 公开插件开发示例

这是 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、bashjarunzip,以及 sha256sumshasum

git clone https://github.com/Java-Chains/chains-plugin-demo.git
cd chains-plugin-demo
./build.sh

build.sh 会依次:

  1. 校验仓库内公开 API jar 的 SHA-256。
  2. 将 API/common 注册到本地 Maven。
  3. 运行所有模块的 mvn clean verify
  4. 检查每个插件 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 后交给 AI 编写

建议先 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、测试和发布约定。

使用 Git tag 自动构建与发布

仓库的 tag-build.yml 会监听任意 Git tag。 Fork 后保留该文件并启用 GitHub Actions,即可在自己的仓库自动编译和发布。

发布版本统一使用:

<Java Chains API 版本>.<插件发布序号>

插件发布序号从 1 开始,每次发布递增;例如宿主 API 为 2.0.0-beta7 时, 前两次插件发布依次是 2.0.0-beta7.12.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.1

tag 推送后,GitHub Actions 会在该 tag 指向的提交上:

  1. 使用 JDK 8 运行完整 ./build.sh
  2. 收集每个 plugins/* 模块独立生成的 chains-plugin-*.jar
  3. 生成插件 jar 的 SHA256SUMS 与包含 tag、commit、宿主 API 版本的 BUILD-INFO.txt
  4. 校验 tag 的末段插件发布序号从 1 开始,并确认每个 manifest 的插件版本 与 tag 一致。
  5. 上传一份 Actions artifact,便于排查单次构建。
  6. 创建同名 GitHub Release,并把插件 jar、SHA256SUMSBUILD-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。不要从复杂厂商依赖开始创建第一个插件。

Starter 的安全链

最小文本链:

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),再包装下游真实返回值。

从零新增一个插件

  1. 复制 plugins/starter-demoplugins/<plugin-id>
  2. 在根 POM <modules> 中加入新模块。
  3. 选择稳定的小写 manifest id;带 - 的 id 映射为合法 Java 包段。
  4. 更新 META-INF/chains-plugin.jsonid、插件 versionapiVersionlibraries
  5. Gadget 使用 @GadgetMeta + @ChainSpec;Payload 使用 @PayloadAnnotation
  6. Gadget id 使用简单类名并保持全局唯一;@Param 放在 public 实例字段。
  7. 为每个节点添加 metadata/nodes/<Id>.yaml;常用安全链放在 metadata/presets/*.yaml
  8. 增加契约测试,再运行单模块和全仓构建。
mvn -pl plugins/<plugin-id> -am clean verify
./build.sh

插件版本和宿主 API 版本是两个概念。例如本次插件版本是 2.0.0-beta7.1,但 manifest apiVersion 仍是 2.0.0-beta7;末尾 .1 只表示针对该宿主大版本的第 1 次插件发布。

POM 依赖规则

子模块显式声明 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-corejava-chains-serverjava-chains-nodeschains-all。插件也不能假设宿主应用中的第三方库对其 ClassLoader 可见。

LibrarySet 四段闭环

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、Catalog 与 Tag

最小 manifest:

{
  "id": "your-plugin",
  "version": "2.0.0-beta7.1",
  "apiVersion": "2.0.0-beta7",
  "libraries": []
}

宿主根据 manifest id 自动注入 plugin:<id> Catalog 来源标签。不要把 它写进 providesacceptsgadgetTags 或手写进 catalogTags

Tag 必须表达真实 Java 类型:

下游返回值 左侧常用 accepts
原始类文件 byte[] Bytecode
处理后类文件 byte[] BytecodeConvertTag
TemplatesImpl TemplatesImplChain
JDBC URL String JdbcUrlChains / JdbcUrlWithSQLChains
终点 叶子的 provides 包含 END

Metadata 与 Preset

  • 注解是节点注册和链路匹配的真相;YAML 只补 Catalog、i18n 与参数文案。
  • YAML params、preset args、input target field 都使用 Java 字段名。
  • preset id 使用 <pluginId>. 前缀,不手写 source
  • 默认教学 preset 必须无出网、低副作用;Sleep 参数字段是 second

安装与 Reload

把某一个子模块 jar 复制到宿主 chains-config/plugins/,或在 Plugins 页面 Upload / Install,然后 Reload。不要安装根项目,也不要把两个 manifest 合并 进一个 jar。

安装后检查:

  1. PluginUnit 状态为 loaded/ready。
  2. Catalog 节点的 pluginId 正确。
  3. Starter 两个 preset 出现,source 为 plugin:starter-demo
  4. StarterDemoPayload → StarterDemoText 可以生成 UTF-8 文本。
  5. 字节码 preset 使用 Sleep.second=2 并通过链校验。
  6. 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/

面向 AI 作者

Codex、Cursor 与 Claude Code 的入口均指向本仓公开 chains-plugin-authoring skill

About

Java Chains 插件编写 demo

Resources

Stars

14 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages