How to Publish a Plugin
Editions: Open Source · Free Cloud · Pro
Pipeline from apito-io/plugins CONTRIBUTING, Cloudinary build-release.yml, and plugin-release-sync.yml.
git tag vX.Y.Z
→ build-release.yml
→ GitHub Release zips + checksums
→ repository_dispatch plugin-release
→ apito-io/plugins plugin-release-sync
→ Update registry JSON + sign catalog
→ catalog-v1 release
→ Engine Install / Update
→ Project activate + env
Author steps
- Public GitHub repo, Apache-2.0, id
hc-<name>-plugin. - Copy Cloudinary build-release.yml: tests, UI build, six OS/arch zips (
linux/darwin/windows×amd64/arm64). Each zip has root-levelbinary + config.yml + ui.js. - Zip name:
hc-<name>-plugin-v<semver>-<os>-<arch>.zip. NeverlatestURLs in the registry. - Tag
vX.Y.Zmatchingconfig.ymlplugin.versionandsdk.Init. - First plugin: PR
registry/<id>.jsonto apito-io/plugins. Reviewers check handshake (APITO_PLUGIN/apito_plugin_magic_cookie_v1), capabilities allowlist, SHA-256, byte size. Labelofficialfor auto-merge after Registry CI. - Later versions: set
REGISTRY_DISPATCH_TOKENon the plugin repo. The notify-registry job sendsrepository_dispatchplugin-releasesoplugin-release-syncupdates catalog JSON without a manual PR. - Super-admin: Administrator → Plugins → Install / Update. Engine: catalog signature → SHA-256 zip → zip-slip-safe extract →
config.ymlvs catalog runtime (version stamp if the zip forgot to bump) → hot-load. - Project admin activates and sets
env_vars.
CLI alternative: apito plugin add hc-cloudinary-plugin (still Engine-side verify + install).
Registry JSON
Point releases[] at immutable GitHub Release asset URLs. Include SHA-256 and size. plugin_version / runtime.version must match the zip config.yml after extract.
First-plugin PRs fail if registry/<id>.json is missing. Later dispatch also fails if that file was never merged.
Engine install path
- Verify
catalog-v1Ed25519 against EnginePLUGIN_REGISTRY_PUBLIC_KEY(orkeys/catalog.pub). - Download the OS/arch zip; check SHA-256.
- Extract without zip-slip.
- Compare
config.ymlid, capabilities, handshake to catalogruntime. If those match but version differs, installer stamps catalog version onto the YAML. - Hot-load the HashiCorp child.
Ops gotchas (no secrets)
PLUGIN_REGISTRY_SIGNING_KEYonapito-io/pluginsmust be the private key matching EnginePLUGIN_REGISTRY_PUBLIC_KEY/keys/catalog.pub. Wrong key → livecatalog-v1fails verify → Engine falls back to on-disk.catalogcache. Marketplace then looks “stuck” on an old snapshot.config.ymlversion must match catalogruntime.version. Stamping is a safety net, not a substitute for bumping YAML +sdk.Init+ the git tag.- After replacing
ui.jslocally, Engine must reload sobundle_sha256reseals. Otherwise Console shows checksum mismatch / “no signed bundle”.
Never commit catalog.priv or signing material.
Checklist
| Done | Check |
|---|---|
Public repo, Apache-2.0, hc-*-plugin |
|
Tag = config version = sdk.Init |
|
| Six zips, root-level files, checksums txt | |
First: registry/<id>.json PR; later: dispatch token |
|
| Handshake v1 cookie pair | |
| Capabilities from the allowlist only | |
| Super-admin Install, then project Activate |
Back to Architecture or the operator hub Plugins.