A wasm check is a WASI module that jaque instantiates inside its own
process, on the WASM runtime embedded in the binary (nothing to install
beside it, consistent with the single-binary invariant). It speaks the
same exit-code and stdout protocol as a legacy plugin, so any language
that compiles to wasip1 writes a jaque plugin with no jaque-specific
code. What it buys over a fork is a module that is one portable file,
sandboxed by construction rather than by convention, and runnable without
spawning a process. What it costs is a compile target: existing plugins do
not become WASM, and were never meant to.
1. The sandbox
#WASMCheck, the CUE shape a wasm check is written against, accepts
module and args and nothing else.
services: custom: check: {
type: "wasm"
module: "checks/disk-usage.wasm"
args: ["/", "80", "95"]
}
module is a path to a .wasm file, read and compiled once at startup.
A module declared in config gets no filesystem and no network, full stop.
There is no config field for a directory mount or a network grant; the
only way to mount a directory is the embedding API (WithDirMount,
WithReadOnlyDirMount) on a runner that an embedder constructs directly,
which a CUE config file cannot reach. A module that hangs is stopped when
its context expires, the same timeout from #Schedule every other check
type obeys.
2. ABI
A check module is a wasip1 command module: it exports _start and is
instantiated fresh per run; a module without _start is rejected at load.
Exit code 0 to 3 maps to OK, WARNING, CRITICAL or UNKNOWN,
and stdout is the check output with an optional |
splitting off perfdata, parsed by the grammar in Legacy exec
plugins, section 2.
3. Memory cap
Guest linear memory is capped at 128 MiB (2048 wasm pages of 64 KiB) by
default. Growth past the cap fails inside the guest, never outside it: a
runaway allocation in a module cannot take the engine with it. An
embedder may raise or lower the cap per runner; nothing in #WASMCheck
exposes it to a CUE config.
4. Why this exists beside legacy exec
WASM checks are not a replacement for the Nagios exec protocol, which stays supported forever. They are the option for something written new, where distributing one file and trusting the host less matter more than reusing a binary that already exists.
5. Security considerations
The sandbox is the default and the only thing a config file can express:
no filesystem, no network, a bounded heap and a deadline. The one
exception is an embedder that mounts a directory through the embedding
API, and that decision is made in code, by whoever links jaque, not by a
config
edit. args reach the guest as its argument vector and nothing else.