Plugin marketplace
kanros ships a small, opinionated plugin host (kanros-plugin) that runs
sandboxed WASM components and JavaScript bundles to extend the built-in
assertions, providers, and report formats. The plugin marketplace is
the discovery + install surface on top of that host: a published index of
community plugins that users can search, inspect, and install from the
kanros plugin CLI subcommand.
This page documents:
- The published manifest JSON schema.
- The registry HTTP API.
- How to author and submit a plugin.
- The security model — what we verify today, what is deferred to
v0.2.
Status.
v0.1.0ships only the client (kanros-plugin-registry) and thekanros pluginCLI subcommand. The canonical hosting service athttps://registry.kanros.devis a follow-up workstream. The client is designed so users can point it at any registry that implements the API documented below — for example a local mock, a corporate mirror, or a GitHub Pages-hosted static index.
Manifest JSON schema
Every published plugin is described by a PluginManifest document. This is
the single source of truth: the registry's index endpoints return arrays of
manifests, the per-plugin endpoint returns one manifest, and the same shape
is stashed in the local cache directory next to every installed artefact so
kanros plugin list can recover metadata without re-contacting the network.
{
"name": "regex-plus",
"version": "0.1.0",
"description": "Extra regex assertions with named-capture support.",
"authors": ["Alice Example <alice@example.com>"],
"license": "Apache-2.0",
"kanros_min_version": "0.1.0",
"kind": "wasm",
"source_url": "https://registry.kanros.dev/api/v1/plugins/regex-plus/versions/0.1.0/download",
"sha256": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
"tags": ["assertion", "regex"]
}
| Field | Type | Required | Notes |
|---|---|---|---|
name | string (kebab-case) | yes | Globally unique. |
version | string (semver) | yes | Must match ^v?\d+\.\d+\.\d+(-[\w.+-]+)?$. |
description | string | yes | One sentence, < 200 chars. |
authors | string[] | yes | May be empty. |
license | string (SPDX) | yes | Validated against the SPDX list at submission time. |
kanros_min_version | string (semver) | yes | Minimum runtime version that can load this plugin. |
kind | enum: wasm | javascript | yes | Determines on-disk filename (plugin.wasm vs plugin.js). |
source_url | URL | yes | Direct download URL — may point at the registry or any HTTPS host. |
sha256 | hex string (64 chars) | yes | SHA-256 of the payload — verified by the client. |
tags | string[] | no | Free-form, used by the search endpoint. Default []. |
The schema lives in kanros-plugin-registry::PluginManifest and round-trips
through serde JSON. A sample manifest is checked into the repo at
examples/plugin-registry/sample-manifest.json and is used as a fixture
when running the crate's test suite manually.
Registry HTTP API
The registry is read-only over HTTP. All endpoints return JSON encoded as UTF-8.
GET /api/v1/plugins?q={query}
Full-text search. query may be empty — the registry returns its curated
"all plugins" list in that case.
Response (200 OK) — JSON array of PluginManifest documents (newest
version per plugin):
[
{ "name": "regex-plus", "version": "0.1.0", "kind": "wasm", ... },
{ "name": "boa-jsonpath", "version": "0.2.1", "kind": "javascript", ... }
]
Errors. A 404 is treated by the client as "no results". Any 5xx
response surfaces as RegistryError::Server { status }.
GET /api/v1/plugins/{name}
Single-manifest lookup. Returns the manifest of the canonical version (typically the latest stable release). Older versions are accessible via the per-version download endpoint below.
Response (200 OK) — a single PluginManifest:
{
"name": "regex-plus",
"version": "0.1.0",
...
}
Errors. 404 → RegistryError::NotFound { name }. 5xx → Server.
GET /api/v1/plugins/{name}/versions/{version}/download
Binary download endpoint. The body is the raw .wasm or .js payload —
no JSON wrapping, no multipart, no encoding.
Response (200 OK) — application/octet-stream. Content-Length is
required and must match the payload exactly.
Errors. 404 → RegistryError::NotFound { name: "<name>@<version>" }.
Verification. The client downloads the payload into a .partial
sibling of the final destination, computes SHA-256, and only renames into
the final location if the digest matches manifest.sha256. On mismatch,
the partial file is removed and RegistryError::ChecksumMismatch is
returned with both the expected and actual digests.
Optional headers
User-Agent: the client always sendskanros-plugin-registry/<crate-version>.Accept: not required — every endpoint always emits JSON or octet-stream as appropriate.- Bearer auth is not part of
v0.1. A private/corporate mirror that wants gating should sit behind an auth proxy.
Authoring and submitting a plugin
Authoring a plugin is unchanged from the WASM plugins and JavaScript plugins guides — the marketplace only adds a distribution layer on top. The workflow is:
- Build the plugin artefact (
.wasmor.js). - Compute its SHA-256 (
kanros-plugin-registry::sha256_hex(&bytes)orsha256sum). - Author a
PluginManifestJSON file with the schema above. Lint it by loading it throughserde_json::from_str::<PluginManifest>— kanros's own test suite uses the same code path. - Publish the artefact somewhere addressable by an HTTPS URL.
- Open a pull request against the registry index repository (link TBD when
the hosting service ships) with the manifest added under
plugins/<name>/<version>.json.
The registry CI will, at submission time:
- Validate the manifest against the schema.
- Re-download the artefact from
source_urland verifysha256. - Check that
kanros_min_versionis<=the current released kanros version. - Reject names that collide with existing first-party crates.
Local install layout
kanros plugin install <name> (with optional --version) writes the
payload under:
~/.local/share/kanros/plugins/<name>/<version>/{plugin.wasm | plugin.js}
~/.local/share/kanros/plugins/<name>/<version>/manifest.json
The path is platform-aware — on macOS it lives under
~/Library/Application Support/kanros/plugins/, on Windows under
%LOCALAPPDATA%\kanros\plugins\. Override with kanros plugin install --dir <PATH> if you want a project-local cache instead.
kanros plugin list walks the cache and prints every manifest.json it
finds — there is no separate index file, so removing a plugin is as simple
as rm -rf of its directory (or kanros plugin remove <name>).
Security model
v0.1.0:
- SHA-256 integrity on every download. A mismatched payload never reaches the final install path.
- HTTPS-only by convention — the client does not refuse
http://URLs (useful for local mocks) but the canonical registry only serves HTTPS. - No code execution at install time.
kanros plugin installwrites the artefact to disk and stops. The plugin only runs when the user explicitly opts in withkanros run --plugins.
v0.2 (deferred):
- Signed manifests via Sigstore. The plan is to publish a Rekor entry
for every manifest signed by the author's GitHub identity, and to require
kanros plugin installto verify the signature against the certificate transparency log before writing to disk. ThePluginManifestschema will gain optionalsignature_urlandrekor_log_indexfields; the client will pull a Sigstore bundle and callsigstore-rsto verify. - Provenance. SLSA build-provenance attestations attached to each release, also verified through Sigstore.
- Per-plugin permission manifests. Today, a WASM plugin runs with the
capability set declared in the user's kanros config; the marketplace
manifest will gain a
requested_permissionsarray so users can be warned before granting filesystem or network access to a third-party plugin.
Users who want stronger guarantees today should:
- Run a corporate mirror that re-hosts only audited plugins.
- Override
--registryto point at that mirror. - Keep the install dir under version control so unexpected changes surface as a diff.
Related reading
- WASM plugins — how the host loads
.wasmcomponents. - JavaScript plugins — the Boa-backed runtime.
- The
kanros-plugin-registrycrate docs —cargo doc -p kanros-plugin-registry --open.