type: reference title: "Plugin manifest and certification contract" description: "The versioned plugin SDK: authoring a manifest, compatibility policy, the security boundary, the application-local registry, the certification kit, signed reports, support status and governance." resource: "honua://capability/plugin.sdk"

Plugin manifest and certification contract

The experimental @honua/sdk-js/plugin entrypoint is the versioned plugin SDK. It lets a third-party package describe its compatibility and authority boundary as inert JSON, produces a deterministic report for a specific host, and runs an application-local lifecycle plus behavioral conformance without granting the plugin ambient authority.

The SDK does not import plugin code, install packages, or maintain a global registry. A certified manifest means only that its declaration is well formed and compatible with the supplied host snapshot. Applications explicitly import factories and may run them through the application-local lifecycle described below. A separate, deterministic behavioral-conformance harness then proves a certified plugin's runtime behavior (retries, performance bounds, and bundle metadata) against committed golden reports, and a machine-readable support-status program records each plugin's lifecycle stage.

Authoring a manifest

import {
  HONUA_PLUGIN_API_VERSION,
  HONUA_PLUGIN_MANIFEST_VERSION,
  certifyHonuaPluginManifest,
  type HonuaPluginManifest,
} from "@honua/sdk-js/plugin";

const manifest = {
  manifestVersion: HONUA_PLUGIN_MANIFEST_VERSION,
  id: "com.example.cloud-tiles",
  version: "1.0.0",
  kind: "protocol",
  package: { name: "@example/honua-cloud-tiles", entrypoint: "./plugin.js" },
  compatibility: {
    pluginApi: HONUA_PLUGIN_API_VERSION,
    minimumSdk: "0.1.0-beta.0",
    maximumSdkExclusive: "0.2.0",
    environments: ["browser", "worker"],
  },
  capabilities: ["tiles"],
  requestedGrants: { networkOrigins: ["https://tiles.example.com"] },
  data: {
    cache: "memory",
    freshness: "ttl",
    authentication: "none",
    provenance: "preserved",
    mutation: "none",
    realtime: "none",
  },
  lifecycle: { initialization: "explicit", disposal: "required" },
  support: "community",
} as const satisfies HonuaPluginManifest<"protocol">;

const host = {
  pluginApi: HONUA_PLUGIN_API_VERSION,
  sdkVersion: "0.1.0-beta.0",
  environment: "browser",
  grants: { networkOrigins: ["https://tiles.example.com"] },
};

// The trust boundary accepts JSON text, never executable object values.
const report = certifyHonuaPluginManifest(JSON.stringify(manifest), JSON.stringify(host));

JSON.stringify is appropriate for trusted application-owned literals like the example above. Do not import an untrusted plugin module and stringify its exports: serialization itself can run getters or Proxy traps before the SDK is called. Read third-party manifest bytes as text (for example, from the package file or an HTTP response) and pass that text directly to the validator.

The report uses the exported HONUA_PLUGIN_CERTIFICATION_REPORT_VERSION schema version. The verifier fails closed on unsupported versions, missing required fields, unknown fields, invalid digest shapes, or malformed check/diagnostic records before it accepts any integrity receipt. The report contains no time, machine path, or random identifier, so the same manifest and host snapshot serialize identically. Its manifest and host blocks contain the complete canonical snapshots plus SHA-256 fingerprints; changing an entrypoint, capability, data semantic, requested authority, peer, grant, environment, API version, or SDK version changes the corresponding fingerprint. CI can reject when status is "rejected" and archive the deeply frozen JSON as certification evidence without permitting manifest/host swaps. The top-level sha256 covers every other report field, including both complete snapshots, their hashes, status, checks, and diagnostics. It is an integrity receipt for externally archived evidence, not a signature or proof of issuer.

Compatibility policy

Security boundary

Extension inventory

The closed HONUA_PLUGIN_KINDS and HONUA_PLUGIN_CAPABILITIES registries cover protocol, source/format, renderer, auth, geocoder/routing, analysis, style, cache, and realtime declarations. Capability names are kind-specific so a manifest cannot inflate its advertised surface with unknown strings. The manifest also records support status and cache, freshness, auth, provenance, mutation, realtime, peer, environment, and disposal semantics for inventory tools.

Application-local registry and lifecycle

HonuaPluginRegistry turns certified declarations into explicit application instances without adding plugins to root SDK workflows:

import {
  HonuaPluginRegistry,
  type HonuaPluginFactory,
  type HonuaPluginManifest,
} from "@honua/sdk-js/plugin";

declare const manifest: HonuaPluginManifest<"style">;
declare const host: unknown;

const stylePlugin: HonuaPluginFactory<"style"> = {
  manifest: JSON.stringify(manifest),
  initialize(context) {
    return {
      extension: { id: context.manifest.id, kind: "style" },
      start() {},
      stop() {},
      dispose() {},
    };
  },
};

const registry = new HonuaPluginRegistry({
  host: JSON.stringify(host),
  services: {},
});
await registry.register([stylePlugin]);
const extension = registry.get("style", manifest.id);
await registry.dispose();

Plugin modules remain external to SDK core. Merely importing the root SDK or an unrelated subpath does not import a plugin factory, initialize a registry, or pull mapping/database peers into the bundle.

Running the certification kit independently

The certification logic is also exposed as a runnable kit so a third party can validate their own plugin outside this repository. Installing the SDK provides the honua-plugin-certify bin — name the package with npx -p, since no npm package is called honua-plugin-certify and a bare npx honua-plugin-certify therefore fails to resolve. It reads a manifest and a host snapshot as inert JSON text, certifies one against the other, prints the deterministic report to stdout (or --out), and resolves an exit code:

# 0 = certified, 1 = rejected, 2 = usage/input error
npx -p @honua/sdk-js honua-plugin-certify --manifest ./manifest.json --host ./host.json --pretty

The bin never resolves or executes the plugin entrypoint; it only reads the two JSON documents. The same logic is available programmatically through the certifyHonuaPluginManifest public API shown above, and the CLI core (runPluginCertificationCli) takes an injected I/O boundary so it can run in any host, not just Node. This makes the harness suitable for a plugin author's own CI: fail the build when status is "rejected", and archive the frozen report — bound to both canonical snapshots by SHA-256 — as certification evidence.

Signed reports and tamper-evident verification

Every certification report carries a top-level sha256 receipt over all its other fields (including both canonical snapshots and their fingerprints). The kit re-checks that receipt so an archived report is verifiably tamper-evident:

# 0 = verified intact, 1 = tampered, 2 = usage/input error
npx -p @honua/sdk-js honua-plugin-certify --verify ./report.json

The same check is available programmatically as verifyHonuaPluginCertificationReport(reportText). It reads the report as inert JSON text and recomputes every stored digest — the top-level receipt plus the manifest.sha256 and host.sha256 snapshot fingerprints — from the report's own content. Any altered field, swapped snapshot, or edited diagnostic changes a recomputed digest and yields a structured REPORT_SIGNATURE_MISMATCH or REPORT_FINGERPRINT_MISMATCH diagnostic. This is a deterministic in-repo integrity proof, not a public-key signature: it proves a report is internally self-consistent and unmodified since issue, not which authority issued it. A trusted-issuer signing authority (which key, which registry) is a product decision and is deliberately out of scope here.

Host-mediated signing envelope (SDK-owned seam)

The SDK also exports HONUA_PLUGIN_CERTIFICATION_SIGNING_ENVELOPE_VERSION and the versioned HonuaPluginCertificationSigningEnvelope shape. An envelope contains the report, an opaque application-selected keyId, the fixed algorithm: "external" marker, and a signature string. Hosts sign the exact canonical payload returned by createHonuaPluginCertificationSigningPayload.

verifyHonuaPluginCertificationSigningEnvelope accepts an explicit HonuaPluginCertificationSignatureVerifier callback. It parses inert JSON, validates the envelope and embedded report, rejects non-certified or altered reports, and only then calls the callback. A missing verifier, callback error, unsupported version, malformed key identifier, or false result fails closed. The callback owns key lookup, cryptographic algorithms, issuer policy, key rotation, and distribution; the SDK stores no keys and makes no trust claim about the opaque identifier. This is an integration seam, not a governance or public-key-distribution implementation.

Support-status program

support records who backs a plugin (community, partner, or honua). The optional, machine-readable supportStatus attestation records the plugin's lifecycle stage so applications and agents can act on it without loading code:

The state vocabulary is exported as HONUA_PLUGIN_SUPPORT_STATES. The broader governance program (who may set partner/honua tiers, security-review sign-off, naming policy) is a process decision layered on top of this schema.

Behavioral conformance and golden reports

runHonuaPluginConformance(spec, host) runs a certified plugin through a deterministic behavioral suite and returns a frozen, digest-sealed HonuaPluginConformanceReport. The harness registers the plugin in an application-local registry with instrumented host services and counts integer observations only — no wall-clock time, randomness, or host path — so the report serializes identically on every run.

Three scenarios are covered, each an observation compared against a declared bound:

Scenario What it proves
retries The plugin recovers from injected transient host failures within its declared attempt budget (hostAttempts <= maxAttempts, recovered).
performance One operation's host-interaction cost stays within bound and is identical across runs (serviceCalls <= maxServiceCalls, deterministic).
cleanup The registry completes the probe and records exactly one successful disposal for the initialized plugin (disposeCalls == 1).
bundle-metadata The declared bundle footprint stays within budget with complete inventory metadata (minifiedBytes, gzipBytes, metadataComplete).

The report binds the certification digest it was run against, so a conformance result cannot be replayed against a different manifest or host.

Certification governance policy

Honua certification is a portable evidence format, not a central plugin registry or certificate authority. The SDK validates inert declarations, produces digest-bound reports, and verifies a host-mediated signing envelope through an application-supplied callback. The consuming application remains the policy authority: it selects trusted issuers and keys, decides which support tier is acceptable, and may reject a schema-valid plugin for local policy reasons. With no configured verifier or matching trust record, signed evidence is untrusted and verification fails closed.

Identity and naming

Compatibility, peers, and deprecation

Security review and support tiers

Support tier and lifecycle state are independent. community means the author is the support authority and carries no Honua endorsement. partner requires a current commercial/technical relationship, a partner-controlled identity and signer, and recorded security approval by the consuming program. honua is reserved for Honua-owned code with approval from a Honua maintainer who did not author the reviewed change. Downgrading a tier or lifecycle state is permitted immediately; upgrading requires fresh evidence.

Before partner or honua approval, the reviewer records all of the following against the exact plugin version and certification digest:

  1. A certified inert manifest with reviewed package ownership, entrypoint, compatibility bounds, capabilities, peers, environment, support status, lifecycle, and complete cache/freshness/auth/provenance/mutation/realtime semantics.
  2. Least-privilege grants: exact HTTPS origins, scope identifiers rather than secrets, bounded storage, and explicit mutation/realtime authority. Reports, review records, diagnostics, and fixtures must contain no credentials, private keys, tokens, copied authorization headers, or customer payloads.
  3. Reproducible semantic and adversarial fixtures covering invalid input, structured errors, cancellation, bounded retries, deterministic cleanup, data/secret boundaries, and any declared mutation or realtime behavior.
  4. A digest-bound behavioral report showing the declared performance and bundle-metadata budgets, plus an installed-consumer/tree-shake check proving that an unused plugin adds no root runtime or optional peer.
  5. Dependency and license review, the owner and response path for security findings, the approved signer key id, and a re-review trigger. A new grant, capability, required peer, entrypoint, ownership change, or incompatible major version always triggers re-review.

Community plugins may self-attest, but applications should apply the same checklist when their risk warrants it. Certification status alone never upgrades a support tier.

Issuers, key rotation, revocation, and expiry

This policy completes the SDK-owned governance contract without creating a hosted marketplace, global key service, or implicit endorsement. A future catalog may distribute inventories and trust records, but applications still opt in to those roots explicitly.