plugin/host/Cargo.toml
[package]
name = "holger-plugin-host"
version.workspace = true
edition = "2021"
authors = ["Ignalina ApS", "Vetra Automation AB"]
description = "Loads holger package handlers — linked or from a directory of .wasm — and wraps each in one RepositoryBackendTrait"
license = "AGPL-3.0-only"
repository = "https://git.gunnar.rs/nordisk/holger"
[dependencies]
holger-plugin-abi = { version = "3.0.0", path = "../abi" }
# Floor 0.6.9 -> 0.6.10: this crate calls `ALL_ARTIFACT_FORMATS`, and published
# holger-traits 0.6.9 does not export it. The `path =` hid that locally.
traits = { package = "holger-traits", version = "3.0.0", path = "../../traits" }
anyhow = "1.0.104"
# The FROZEN code registry. A resource bound that fired, or a module that failed
# verification, is a NAMED refusal (`holger-plugin-1..9`) — not a string a caller
# has to pattern-match. A zero-dependency leaf, so this costs the host nothing.
holger-errcode = { version = "3.0.0", path = "../../errcode" }
# THE LIFTED MECHANICS (2026-09-22). Limits, the signature gate, the census digest,
# the alloc/result_len/plugin_call convention and the bounded loader now live in
# edda's `guest-host`, so holger and monetize hold ONE implementation of the parts
# that have nothing to do with what a guest is for. This crate keeps holger's ABI,
# its handler/meter kinds, its grant table and its FROZEN error codes on top
# (`named.rs` puts a `holger-plugin-<n>` on each of guest-host's typed refusals).
# path = the sibling edda checkout, the documented dev layout; a crates.io version
# replaces it once guest-host is released through `dwarves crate-release`.
guest-host = { version = "0.2.0" }
# The wasm runtime, and the ONLY thing the `wasm-plugins` feature adds. With the
# feature off this crate still builds and still hosts linked handlers, so a
# server tier that wants the bundle handlers compiled in carries no wasmtime.
#
# ★ 27 -> 48 (2026-09-19). The floor is a SECURITY floor, not a preference: every
# one of the 17 advisories deny.toml used to accept for wasmtime 27 — four of them
# sandbox escapes — is fixed at or below 48.0.2 (the last two, RUSTSEC-2026-0222
# and -0269, are patched only in >= 46.0.2 / >= 46.0.3, which is why the bump does
# not stop at 45). Do NOT lower this. The API cost of the jump turned out to be
# zero source changes: this host uses Engine/Module/Store/Linker/Caller/Memory/Val
# only, and none of them moved.
# Only the runtime and its compiler (2026-10-22, the dependency dedup): the default
# set carried the compile cache (a second zstd), the text parser (a second
# wasm-encoder), the component model and the GC, none of which this host uses. The
# same set as edda's guest-host.
wasmtime = { version = "49", optional = true, default-features = false, features = ["anyhow", "runtime", "cranelift", "parallel-compilation", "std"] }
# Provenance verification for a loaded `.wasm` — the ONE spec-exact CMS/DSSE
# verifier this constellation has, reused rather than rewritten (`verify.rs`).
# Optional and path-pinned for exactly the reasons `server/lib/Cargo.toml:161-175`
# records: `znippy-common/sign` exists only on the local (patched) znippy.
znippy-common = { version = "0.10.4", optional = true }
[features]
default = []
# Name mirrors `znippy-common`'s feature of the same purpose, so the two repos
# spell the capability identically.
wasm-plugins = ["dep:wasmtime", "guest-host/wasmtime"]
# Verify a module's detached CMS signature against configured trusted roots before
# it is compiled. OFF by default because it pulls `znippy-common/sign`; a policy
# that REQUIRES trust in a build without it is a named refusal
# (`holger-plugin-9`), never a silently skipped check — the same fail-closed shape
# `wire_verified_znippy` has without `sign`.
verify-modules = ["guest-host/verify-modules", "dep:znippy-common", "znippy-common/sign"]
# HOLGER-ROOT-1 (2026-10-27): the test that reads `guest_host::verify::VERIFIER_COMPILED`
# runs only with this on. That item is on edda main (b1e4d2e) but not in crates.io's
# guest-host 0.2.0, and the root builds from crates.io (B7). Publish row: guest-host 0.2.1
# (r5-notes.md "crates.io steps to come"). Once holger asks guest-host 0.2.1, drop this
# feature and its cfg.
guest-host-verifier-probe = []
# The Meter guest kind: its op table, its wire types and `MeterRuntime`. With
# this OFF the binary contains no meter vocabulary at all -- no verdict type, no
# capability names, no meter ops -- which is strictly more absence than a cargo
# `metered` feature gives, because the wasm route also removes the guest itself.
meter-guests = []
# The shared native-vs-wasm agreement assertions, used by each handler pair's
# `tests/native_wasm_agree.rs`. Off by default: a server build has no use for
# them, and one implementation of the comparison is the point (LAW 5).
agreement-harness = ["wasm-plugins", "traits/test-support"]
[dev-dependencies]
# Hand-written modules for the RESOURCE-BOUND guards: a module that loops forever,
# and one that grows memory without end. Both have to be real wasm reaching the
# real host — a bound asserted against a mock is a bound nothing has ever fired.
# `wat` is what wasmtime itself parses text modules with, so it adds nothing new
# to the graph.
wat = "1"
# The OPEN meter guest, called natively in the agreement test beside the same
# logic loaded from its own `.wasm`. Dev-only: the host does not depend on any
# particular guest, exactly as it does not depend on any particular handler.
holger-plugin-allocation = { path = "../guest-allocation" }
# The shared test kit: builds the guests the integration tests load.
traits = { package = "holger-traits", path = "../../traits", features = ["test-support"] }
# The linked half of the agreement guard: the same handlers a `.wasm` is built
# from, called directly. Not a runtime dependency — the host does not know about
# any particular handler.
# path-only: a versioned path DEV-dep is still resolved by `cargo publish` even
# though dev-deps are stripped, and fail-stops when the sibling is not yet live.
holger-handler-skidbladnir = { path = "../handler-skidbladnir" }
# The REAL route table. `tests/router_cannot_tell_them_apart.rs` puts a loaded
# module and a linked handler into the same `FastRoutes` server/lib builds after
# wiring, so the indistinguishability claim is asserted against the actual
# router rather than a stand-in. Dev-only: the host does not depend on the server.
holger-server-lib = { path = "../../server/lib" }
# Feature-gated test targets: cargo skips them unless the features are on,
# instead of linking an empty binary. The gate's arms (.nornir/testmatrix-arms.json)
# turn them on; the silenced-tests guard reads `required-features`.
[[test]]
name = "an_unsigned_module_stops_the_boot"
required-features = ["wasm-plugins", "verify-modules"]
[[test]]
name = "config_names_the_reader"
required-features = ["wasm-plugins"]
[[test]]
name = "resource_bounds_are_named_refusals"
required-features = ["wasm-plugins"]
[[test]]
name = "router_cannot_tell_them_apart"
required-features = ["wasm-plugins"]
[[test]]
name = "the_floor_never_lets_a_module_go_back"
required-features = ["wasm-plugins", "verify-modules"]
[[test]]
name = "the_forge_signed_guests_load"
required-features = ["wasm-plugins", "verify-modules", "meter-guests"]
[[test]]
name = "the_grant_is_the_linker"
required-features = ["meter-guests", "wasm-plugins"]
[[test]]
name = "the_meter_fuel_ceiling"
required-features = ["meter-guests", "wasm-plugins"]