Developer docs/Guides
Security model
- Addons run in a wasmtime sandbox. Memory, fuel and time are limited, and there is no ambient file, network or process access.
- Everything an addon can reach is declared in
addon.jsonundercapabilitiesand approved by an admin at install. The host checks each call against what was approved. - Some capabilities are marked dangerous. The installer shows them prominently.
- Iframe UI needs a separate explicit approval. Frames are sandboxed and can only call the API paths listed in
capabilities.bridge. - Outbound HTTP only reaches the hosts listed in
capabilities.http. Link-local and cloud metadata addresses are always refused. - Hook payloads redact password fields, and the host restores any redacted value a hook tries to overwrite. Money fields can only change with
money.modify. - Package files are hashed (
filesmap). Usepelty-cli addon hashafter every change.
#Capabilities
Capabilities approved at install (from addon.json).
| Field | Type | Required | Description |
|---|---|---|---|
http | Vec<String> | no | Allowed hosts: api.stripe.com, *.example.com, $server, $setting:<key>. |
secrets | Vec<String> | no | |
kv | bool | no | |
events | Vec<String> | no | |
hooks | Vec<Hook> | no | Synchronous pre-action hooks (invoice.before_create, …). |
routes | Vec<Route> | no | HTTP routes served under /api/v1/addons/<id>/…. |
ui | Vec<String> | no | UI powers beyond the declarative schema: iframe = sandboxed pages and widgets served from the addon's assets/ (admin-approved). |
bridge | Vec<String> | no | Core GET /api/v1/… prefixes an iframe may read through the postMessage bridge (with the viewer's own permissions). |
http_private | bool | no | http: ["*"] may also reach loopback/private/LAN addresses. Link-local and cloud metadata stay refused. |
money | MoneyCaps | no | Change money amounts in pre-event payloads (audited, exact Decimal). |
db | DbCaps | no | Core data access through the host (power interface). |
fs | bool | no | Private data directory, mounted at /data (WASI preopen). |
exec | Vec<String> | no | Absolute program paths the addon may run (no shell). Off in Docker. |
exec_args | HashMap<String, Vec<String>> | no | Optional per-program argument allowlist: each argument must equal a pattern or match a prefix* pattern. Programs not listed only get the baseline checks in [validate_exec_args]. |
fs_quota_mb | Option<u32> | no | Size cap for the /data directory in MiB (default 64, max 1024). Over quota the directory is mounted read-only. |
jobs | Vec<Job> | no | Background jobs: ops the addon may queue, and cron schedules. |
auth_provider | bool | no | Custom login: the host asks the addon to verify credentials (op auth.verify). It never sees stored password hashes. |
emits | Vec<String> | no | Custom events this addon may emit (<id>:<name>, * suffix allowed). |
mixins | Vec<Mixin> | no | Host-enforced wrappers around approved host operations. |
Source: crates/pelty-wasm/src/runtime.rs (Capabilities).
#Hook
A pre-event subscription: the host calls call("hook", {event, payload}) before the action and the addon may continue, cancel or modify it.
| Field | Type | Required | Description |
|---|---|---|---|
event | String | yes | |
priority | i32 | no | Lower runs first; ties ordered by addon id. Accepts an integer or a Bukkit-style name: lowest (0), low (50), normal (100), high (150), highest (200), monitor (1000, observe only). |
ignore_cancelled | bool | no | Also receive the event when an earlier listener cancelled it. |
fail_open | bool | no | On error/timeout: true lets the action continue, false blocks it. |
timeout_ms | u64 | no | Hook budget in milliseconds (capped by the sandbox timeout). |
Source: crates/pelty-wasm/src/runtime.rs (Hook).
#Mixin
A mixin: wraps an approved host operation (an API route template such as POST /api/v1/client/orders). at: before (rewrite the input), after (rewrite the output within its schema), around (both, with shared state) or return (replace the output, same schema).
| Field | Type | Required | Description |
|---|---|---|---|
target | String | yes | |
at | String | yes | |
priority | i32 | no | |
timeout_ms | u64 | no |
Source: crates/pelty-wasm/src/runtime.rs (Mixin).
#Route
An addon HTTP route. access: admin (needs permission), client (any signed-in user) or public.
| Field | Type | Required | Description |
|---|---|---|---|
method | String | yes | |
path | String | yes | Path below the addon prefix, e.g. /stats or /items/:id. |
access | String | yes | |
permission | Option<String> | no |
Source: crates/pelty-wasm/src/runtime.rs (Route).
#Job
A background job op; every_secs > 0 also runs it on a schedule.
| Field | Type | Required | Description |
|---|---|---|---|
op | String | yes | |
every_secs | u64 | no |
Source: crates/pelty-wasm/src/runtime.rs (Job).
#MoneyCaps
| Field | Type | Required | Description |
|---|---|---|---|
modify | bool | no |
Source: crates/pelty-wasm/src/runtime.rs (MoneyCaps).
#DbCaps
| Field | Type | Required | Description |
|---|---|---|---|
read | Vec<String> | no | Entities: clients, services, invoices, orders, tickets, … |
write | Vec<String> | no | Typed write ops: client.note, ticket.reply, … |
sql | bool | no | Free SQL on addon_<id>_* tables. |
Source: crates/pelty-wasm/src/runtime.rs (DbCaps).
#Dangerous capabilities
/// Capabilities shown with a red warning at install; the admin must tick
/// each one (`approve` list in the install request).
#Package permissions
Coarse package permissions in addon.json permissions (shown at install):
payments.processprovisioning.managedomains.managenetwork.outbounddb.migrateui.extend
Addon kinds: provisioning, gateway, registrar, theme, plugin, captcha, sso, integration.