Skip to content

(DRAFT) Intermesh WASM Integration Plan -- v5.6 #100

Description

@pcnofelt

This is a more trim version of (DRAFT) Intermesh WASM Integration Plan -- v4.1 , the intent is to be more focused on feasibility rather than future scaffolding that does not offer immediate functionality/impact.


Intermesh WASM Integration Plan -- v5.6

Intermesh knows who is connecting -- mTLS proves that. What it doesn't know is whether that peer should reach this particular target. Today, any authenticated peer can CONNECT to any service on a node. That's the gap.

This plan adds one thing: a sandboxed policy check at the moment Intermesh already has all the information it needs -- peer identity proven, target parsed, relay not yet started. A WASM module looks at the connection metadata, returns Pass or Reject, and gets out of the way. The trust engine, the gossip layer, and the relay path are untouched.

One module. Two verdicts. ~355 lines of new code. Everything else is deferred until this proves its worth.

How it works

Intermesh's proxy has two connection paths:

  • Inbound (run_external_acceptor -> handle_from_external): accepts mTLS connections from remote peers, parses the HTTP CONNECT target into (Name, port), relays to localhost
  • Outbound (run_local_acceptor -> forward_external): intercepts nftables-redirected local traffic, resolves VIP to mesh name, tunnels via HTTP CONNECT over mTLS

The WASM hook sits on the inbound path, between target parsing and the relay. The peer IMID is already known from the mTLS handshake. The target name and port are already parsed. The module sees these facts, makes a decision, and returns. If there's no module configured, nothing changes -- the hook is a zero-cost no-op.

What v1 delivers

Per-target access control. "The database team's IMID can reach db.prod.mesh:5432 but not admin.prod.mesh:22." Policy that varies per deployment, changes faster than release cycles, and doesn't require recompiling Intermesh.

Stateful decisions. The module's init() runs once at load time. The instance persists across connections, so counters, rate-limit windows, and peer tracking survive within a daemon lifetime.

Audit trail. Every verdict carries an optional context string -- human-readable, logged by the host, never parsed. Operators get rejection reasons without building a telemetry pipeline.

What v1 deliberately leaves out

v1 is scoped to prove one thing: that WASM policy at the connection level is worth the complexity cost. Everything below is preserved in the v2+ roadmap but excluded from this implementation:

  • Connection redirection (Update verdict -- exists in ABI, gated off)
  • Passive observation of outbound connections
  • In-module telemetry beyond context strings
  • Multiple modules or composition
  • Payload inspection or L7 rewriting
  • Module distribution, signing, or hot-reload
  • Candidate selection for IMID/IP resolution
  • Store pooling for concurrency

Boundaries

  • This is a policy hook, not a plugin system. The module decides Pass or Reject on connection metadata. It cannot see tunnel bytes, mutate trust state, or call out to the network.
  • Modules load from local filesystem at daemon startup. No gossip distribution, no runtime replacement.
  • The WASM runtime is feature-gated. Without --features wasm, the binary is identical to today.

1. Why WASM, not just Rust

handle_from_external accepts any mTLS-authenticated peer for any CONNECT target. A hospital network, a multi-tenant platform, a compliance-constrained deployment -- they all need per-target policy, and that policy changes faster than release cycles.

Compiled-in Rust would work for one deployment. WASM lets operators ship policy as a file.

The plan hedges this bet: Phases 1-3 deliver a working ConnectionPolicy trait with pure Rust implementations and zero new dependencies. If WASM proves unjustified, the trait stays and the wasmtime dependency never lands.


2. Verdict model

The WASM module returns a verdict. The host acts on it.

v1 verdicts

enum Verdict {
Pass,
Reject,
}
  • Pass -- no objection, proceed with default behavior.
  • Reject -- deny this connection. Host responds with the reject-status-code if provided, otherwise 403. Only 403, 429, and 503 are valid; any other value is treated as 403.

Unsupported verdict: Update

The Update variant exists in the WIT definition to avoid a breaking ABI change when v2 enables it.

  • In v1, returning Update is treated as a WASM failure -- the host applies the configured failure mode (fail-closed: Reject 403; fail-open: Pass)
  • A warn-level log is emitted once per module (not per connection) to avoid log flooding
  • If updated-context is present in the verdict result, it is ignored
  • Module authors should not return Update in v1

Verdict result

record verdict-result {
verdict: verdict,
context: option<string>,
reject-status-code: option<u16>,
updated-context: option<connection-context>,
}
  • context -- optional human-readable string (max 256 bytes, hard-truncated). Logged for all verdicts. Never parsed or branched on by the host.
  • reject-status-code -- only read when verdict is Reject. Must be 403, 429, or 503. Default 403.
  • updated-context -- reserved for Update verdict (v2). Ignored in v1.

3. WIT interface

Communication between host and WASM uses the WIT (WebAssembly Interface Types) component model, not direct memory read/write. WIT is to WASM components what protobuf is to gRPC -- a typed interface definition language that generates bindings for both host and guest. The wasmtime::component::bindgen! macro generates Rust types from .wit files at compile time, similar to how tonic-build generates from .proto files.

Module metadata

packageintermesh:module@0.1.0;interfacemetadata {
name:func() ->string;
version:func() ->string;
direction:func() ->traffic-direction;
failure-mode:func() ->module-failure-mode;
}
enum traffic-direction {
inbound,
outbound,
both,
}
enum module-failure-mode {
fail-open,
fail-closed,
}
  • name: short identifier, e.g., "connect-authz". Logged at startup.
  • version: semver string, e.g., "0.1.0". Logged at startup for debugging.
  • direction: which connection path this module applies to. v1 only invokes modules with inbound or both (in v1, both behaves the same as inbound because only inbound hooks exist). Kept in v1 so we don't need a WIT-breaking change when outbound hooks are added.
  • failure-mode: the module's declared preference for fail-closed or fail-open. This is advisory only -- the host configuration determines actual enforcement (see Configuration section). Logged at startup so operators can see what the module expects.

Hook interface

interfacehook {
enumverdict {
pass,
reject,
update,
}
recordconnection-context {
peer-imid:string,
target-name:string,
target-port:u16,
subsystem:string,
}
recordverdict-result {
verdict:verdict,
context:option<string>,
reject-status-code:option<u16>,
updated-context:option<connection-context>,
}
init:func();
evaluate:func(ctx:connection-context) ->verdict-result;
}

peer-imid is the only identity input. Names are derived views that can differ per node's constraint set; IMID is stable cryptographic identity. subsystem is always "proxy" in v1.

init() is called once at load time. The wasmtime Store persists across calls, so state set during init() is available in subsequent evaluate() calls.

update exists in the verdict enum for ABI forward-compatibility but is treated as a WASM failure in v1 (see Verdict model section).

Host-provided functions

interfacehost {
log:func(message:string);
}

log is the only host-call in v1. It writes to the host's tracing system at debug level.

  • Per-message cap: each message truncated at max_log_bytes (default 1024); one debug note on first truncation per invocation
  • Per-evaluate cap: max max_log_calls (default 3) calls; excess silently dropped; one debug note on first drop per invocation
  • Module continues executing normally in both cases
  • Same caps apply during init()

World definition

worldintermesh-module {
importhost;
exportmetadata;
exporthook;
}

What is excluded from v1 ABI

  • Payload/packet bytes
  • Network egress
  • Filesystem access
  • Inter-module communication
  • Trust engine queries or mutation (by construction: no host-call exists)

4. Module lifecycle and loading

v1 supports exactly one inbound policy module for the CONNECT authorization hook. The module is specified by explicit path in config, not by directory scan.

Loading sequence

  1. Read path from [modules.connect_authz] config
  2. Instantiate the .wasm component with wasmtime (with memory cap applied)
  3. Call metadata::name(), metadata::version(), metadata::direction(), metadata::failure_mode()
  4. Log module metadata (name, version, direction, declared failure-mode preference)
  5. Call hook::init() under the same resource limits as evaluate() (fuel + memory + log caps)
  6. If init() fails: daemon startup fails (fail-closed -- a configured module that can't initialize is a deployment error)
  7. If direction is outbound (and does not include inbound): daemon startup fails with a clear error ("configured module does not apply to any active hook in v1"). This surfaces misconfig early rather than silently falling back to AllowAll.

No hot-reload. Module changes require daemon restart.

Configuration

[modules.connect_authz]
path = "~/.intermesh/modules/connect-authz.wasm"failure_mode = "fail-closed"# "fail-closed" (default) | "fail-open"fuel_limit = 100_000# max instructions per evaluate() and init()max_memory_bytes = 33_554_432# 32MB hard cap on module memorymax_log_calls = 3# max host::log() calls per evaluate()max_log_bytes = 1024# max bytes per host::log() message

Loading rules:

  • If [modules.connect_authz] is absent or path is unset: no module loads. Behavior identical to today.
  • path points to a single .wasm component file. No directory scanning, no duplicate detection, no sorting ambiguity.
  • The module must export metadata and hook interfaces and must successfully run hook::init().

Failure mode is host-owned:

  • Module's metadata::failure_mode() is advisory only -- logged at startup for operator visibility
  • Host configuration (failure_mode in [modules.connect_authz]) determines actual enforcement
  • Default: fail-closed; operator must explicitly opt into fail-open
  • Prevents a buggy/malicious module from declaring fail-open and deliberately trapping to bypass policy

Failure handling

v1 uses a single deterministic execution budget (fuel) plus hard resource limits enforced by the host. No wall-clock timeout -- fuel is a deterministic instruction budget (wall-clock time to burn that fuel still depends on CPU, but the instruction count is fixed).

Resource limits (host-enforced, applied to both init() and evaluate()):

  • Fuel: default 100,000 instructions. Reset fresh for each evaluate() call (no carry-over).
  • Memory: hard cap on module instance memory (default 32MB). Enforced via wasmtime's ResourceLimiter.
  • host::log() cap: max max_log_calls (default 3) calls per evaluate(), each truncated at max_log_bytes (default 1024) bytes. One debug note on first truncation per invocation; one debug note on first call drop per invocation.

What counts as a WASM failure:

  • Fuel exhausted
  • Trap (panic/abort)
  • Memory limit exceeded
  • Invalid/ill-typed return value
  • Returning Update verdict (unsupported in v1)

(host::log() cap exceeded is not a failure -- calls are silently dropped, execution continues.)

Outcome on failure (host-owned policy):

Failurefail-closed (default)fail-open
Any WASM failureReject (403)Pass (skip module)
5 consecutive failuresDisable module, logDisable module, log

Failure outcome rules:

  • For fail-closed: rejection status is always 403 (even if the module attempted to return a different status before failing)
  • For fail-open: the failure is logged and the module is skipped for that evaluation

Consecutive failure tracking:

  • After 5 consecutive failures, the module is disabled for the remainder of the daemon lifetime
  • Disabling is logged at warn once
  • A successful evaluation resets the counter
  • A Reject verdict is a normal policy decision, not a failure -- both Pass and Reject reset the consecutive failure counter

Disabled module behavior:

  • When disabled, the policy behaves as if evaluate() failed: fail-closed returns Reject 403; fail-open returns Pass

"No module" fast path

If no module is loaded (no [modules.connect_authz] config), evaluate() returns Pass immediately with no context allocation. Zero overhead on the CONNECT hot path when WASM is not in use.


5. Hook point: CONNECT authorization

Remote peer
│
▼
mTLS handshake (IntermeshVerifier + StrictPolicy)
│
▼ peer IMID known
│
HTTP CONNECT request received
│
▼
parse_connect_target → (Name, port)
│
▼
┌─────────────────────────────┐
│ WASM policy hook │
│ evaluate(peer_imid, name, │
│ port, "proxy") │
│ │
│ Pass → continue │
│ Reject → 403/429/503 │
└─────────────────────────────┘
│
▼ Pass
upgrade::on(req)
│
▼
copy_bidirectional (relay)
  • Where:handle_from_external in src/modules/proxy/mod.rs at line 198, after parse_connect_target succeeds and returns (Name, port), but before upgrade::on(req) and the relay spawn
  • Today: any mTLS-authenticated peer can CONNECT to any localhost port; the peer IMID is known (from tls_stream.connect_info().peer) but no per-target policy is applied
  • With hook: build a connection-context from the peer IMID and parsed target, call evaluate() on the loaded inbound module
    • Pass: proceed to upgrade/relay as today
    • Reject: respond with HTTP status code (default 403), do not upgrade, close connection
    • Update: treat as WASM failure (apply host failure mode)
  • Inputs: peer IMID (string), target name, target port, subsystem="proxy"
  • Fallback on WASM failure: determined by host configuration (failure_mode in [modules.connect_authz]); default: fail-closed
  • No module loaded: hook is a no-op -- returns Pass immediately with no allocation; behavior identical to today

6. Code isolation: the wasmrunner module

All WASM-related code lives in src/wasmrunner/, not under src/modules/. This is deliberate: modules/proxy and modules/adhoc are Intermesh feature modules that implement mesh functionality. wasmrunner is infrastructure -- it provides a policy evaluation service that the proxy module consumes via a trait. It sits alongside connect.rs, verifier.rs, and gossip.rs as a peer utility.

src/
├── wasmrunner/
│ ├── mod.rs # Public API: ConnectionPolicy trait, WasmPolicy impl
│ ├── loader.rs # Load module from path, read metadata, call init()
│ └── types.rs # Verdict, ConnectionContext, VerdictResult, AllowAll
├── modules/proxy/mod.rs # Calls wasmrunner via ConnectionPolicy trait
├── daemon.rs # Creates WasmPolicy at startup, passes to proxy
└── ... # Everything else unchanged

With single-path loading and one module per hook, loader.rs is ~40 lines. There is no registry. If config is absent, the daemon uses AllowAll; if configured, load_module returns exactly one LoadedModule or fails startup. If multi-module support is added in v2, a registry.rs can be extracted then.

The proxy module never imports wasmtime. It calls connection_policy.evaluate(ctx) and gets back a Verdict. Whether that policy is a compiled-in Rust struct or a WASM module is invisible to the caller.

Feature-gated:

[features]
default = []
wasm = ["wasmtime"]
[dependencies]
wasmtime = { version = "...", features = ["component-model"], optional = true }

Without --features wasm, the wasmrunner module provides AllowAll and adds zero dependencies.


7. Implementation sequence

Each phase is a single PR. Every phase must pass cargo local and all existing tests.

Phase 1: Define the ConnectionPolicy trait

Goal: Introduce the trait that will be the boundary between proxy and policy logic. No behavioral change.

What changes:

  • New: src/wasmrunner/types.rs -- ConnectionPolicy trait, Verdict enum (Pass, Reject), ConnectionContext struct, VerdictResult struct, AllowAll default implementation
  • New: src/wasmrunner/mod.rs -- re-exports the public API

Tests: Unit tests for AllowAll returning Pass for any input.

Phase 2: Wire ConnectionPolicy into the proxy

Goal:handle_from_external calls the policy after parsing the CONNECT target. With AllowAll, behavior is identical to today.

What changes:

  • proxy::Handle gains a policy: Arc<dyn ConnectionPolicy> field. Handle is Clone (it carries Arc references to shared state), so the policy is shared across all connection-handling tasks.
  • handle_from_external calls policy.evaluate() between parse_connect_target (line 197) and upgrade::on(req) / relay spawn (line 199)
  • daemon.rs passes AllowAll to proxy::Handle::new()

Tests: Existing e2e tests pass unchanged (proving AllowAll preserves behavior).

Phase 3: Test the policy trait with Rust implementations

Goal: Prove the hook point works with real policy logic, no WASM yet.

What changes:

  • Add DenyAll and AllowList test implementations in src/wasmrunner/types.rs (behind #[cfg(test)])
  • Tests that exercise the full proxy path with each policy

Tests:

  • AllowAll: connection proceeds (baseline)
  • DenyAll: connection gets 403
  • AllowList { targets: ["db.test.mesh:5432"] }: selective gating
  • Verdict context string appears in logs

Phase 4: Add wasmtime and create the engine

Goal: Introduce the wasmtime dependency behind a feature gate. Initialize the engine. No module loading yet.

What changes:

  • Cargo.toml: add wasmtime as optional dependency with component-model feature
  • src/wasmrunner/mod.rs: conditionally create wasmtime::Engine when wasm feature is enabled

Tests: Engine initializes successfully. Compiles cleanly with and without --features wasm.

Phase 5: Write the WIT interface

Goal: Define the contract between host and WASM modules.

What changes:

  • New: wit/intermesh-module.wit -- full WIT definition (metadata, hook with init/evaluate, host with log)
  • src/wasmrunner/mod.rs: add wasmtime::component::bindgen! macro to generate Rust bindings

Tests: Bindings compile. Generated types align with the Verdict/ConnectionContext types from Phase 1.

Phase 6: Module loader

Goal: Load a single .wasm file from the configured path, read metadata, call init() under resource limits.

What changes:

  • New: src/wasmrunner/loader.rs -- load_module(path, limits) -> Result<LoadedModule> that reads the file, instantiates the component with memory cap, reads metadata, and calls hook::init() under fuel + memory + log caps. If direction does not include inbound, returns an error (configured module does not apply to any active hook in v1).

Tests:

  • Valid .wasm component: metadata read correctly, init() called
  • Corrupt/invalid file: returns error
  • Missing metadata exports: returns error
  • init() trap: returns error (module not loaded)
  • init() exceeds fuel: returns error
  • Outbound-only module: returns error, startup fails

Phase 7: Daemon wiring

Goal: Wire module loading into daemon startup. Pass the loaded module (or AllowAll) to the proxy.

What changes:

  • src/wasmrunner/mod.rs: WasmPolicy struct that implements ConnectionPolicy. The wasmtime Store is not Send + Sync, but handle_from_external runs in tokio::spawn tasks concurrently. WasmPolicy wraps the Store in a Mutex to serialize access (acceptable for v1; see risk register).
  • src/daemon.rs: if [modules.connect_authz] config has path, call load_module(), create WasmPolicy, pass to proxy Handle. Otherwise pass AllowAll. Read host-enforced limits from config.
  • src/daemon_state.rs: add modules config fields (path, failure_mode, fuel_limit, max_memory_bytes, max_log_calls, max_log_bytes)

Tests:

  • No modules config: daemon starts normally, AllowAll used
  • Valid path with one module: module loaded, logged with metadata
  • Invalid/missing path: daemon startup fails with clear error
  • init() failure: daemon startup fails

Phase 8: Active hook execution with failure handling

Goal:WasmPolicy.evaluate() calls the WASM module with resource limits, handles failures per host-configured failure-mode, tracks consecutive failures, disables on fault. Implements host::log import.

What changes:

  • src/wasmrunner/mod.rs: implement evaluate() -- reset fuel fresh each call, apply memory cap via wasmtime ResourceLimiter, call hook::evaluate(), check result. On failure (including Update verdict): use host-configured failure_mode (fail-closed -> Reject 403, fail-open -> Pass). Track consecutive failures; disable after 5.
  • src/wasmrunner/mod.rs: implement the host::log import in the wasmtime linker. Track call count per evaluate() invocation; cap at max_log_calls (default 3). Each message truncated at max_log_bytes (default 1024). One debug note on first truncation per invocation; one debug note on first call drop per invocation.

Tests:

  • Module returning Pass: connection proceeds
  • Module returning Reject with context: context string logged
  • Module returning Reject with status 429: status code returned
  • Module returning Update: treated as failure, outcome per host failure-mode
  • Fuel exhaustion with fail-closed: Reject (403)
  • Fuel exhaustion with fail-open: Pass
  • Memory limit exceeded: Reject (403) under fail-closed
  • Module trap with fail-closed: Reject (403)
  • 5 consecutive failures: module disabled, logged at warn
  • 4 failures then success: counter resets, module stays active
  • Module disabled: subsequent calls return per host failure-mode
  • host::log() call: message appears in tracing output
  • host::log() exceeding max_log_bytes: truncated
  • host::log() called 4+ times: excess silently dropped

Phase 9: Verdict handling in the proxy

Goal:handle_from_external acts on the verdict -- Reject with status code, Pass proceeds.

What changes:

  • src/modules/proxy/mod.rs: after policy.evaluate(), match on verdict. Reject -> respond with HTTP status code (403/429/503, default 403), do not upgrade the connection, close it. Pass -> proceed to upgrade/relay. Log verdict + context string at info level.

Tests:

  • Reject with no status code: HTTP 403
  • Reject with 429: HTTP 429
  • Reject with 503: HTTP 503
  • Reject with invalid status (e.g., 200): treated as 403
  • Pass: connection proceeds, context string in logs
  • No module loaded: connection proceeds (AllowAll)

Phase 10: Reference module and documentation

Goal: Ship a working example so module authors have a template.

What changes:

  • New: examples/wasm-modules/connect-authz/ -- Rust crate that compiles to a WASM component. Implements intermesh-module world with a simple allow-list policy. Demonstrates: metadata exports, init() for setup, evaluate() returning Pass/Reject, context strings, host::log() calls. Documents clearly: "do not return Update in v1."
  • New: docs/wasm-modules.md -- how to write, build, and install modules. Covers: WIT interface, guest bindings with wit-bindgen, building with cargo component, configuring the module path.

Tests: The example module compiles, loads, and correctly gates CONNECT requests in an integration test.


8. Testing strategy

Invariants enforced across all phases

  • No-module baseline:cargo local passes with no modules configured. Zero behavioral regression.
  • Feature-gate baseline: Compiles without --features wasm with no wasmtime dependency. AllowAll is the only policy.
  • Trust boundary: No WASM module can produce an Endor, modify a Derivation, or influence constraint_authority. Enforced by WIT design -- no host-call exists for trust mutation. WASM cannot influence trust resolution; it can only accept or reject connections that the trust engine has already authorized at the mTLS layer.
  • Identity input:peer-imid is the only identity input to WASM. Names are derived views that differ per node's constraint set; IMID is stable cryptographic identity.
  • Isolation: No file outside src/wasmrunner/ imports wasmtime.
  • Resource bounding: Fuel, memory, and log calls are all capped and host-enforced. Failure mode is host-owned -- a module cannot opt itself into fail-open.

Deferred to hardening

  • ABI fuzzing (malformed WIT payloads, oversized strings)
  • N-1 compatibility (old module / new host)
  • Load testing under sustained connection pressure
  • Benchmark: latency impact of fuel-budgeted WASM on CONNECT path
  • Concurrency stress test (many concurrent CONNECT requests hitting Mutex)

9. Explicit v2+ deferrals

  • Update verdict -- enable via allow_update = true config; requires trust engine validation (Derivation.name_to_imid check) and immutable-field enforcement
  • Passive observation -- bounded channel, background executor, outbound connection events
  • emit() host-call -- in-module telemetry with bounded queue and drop-on-pressure
  • Multiple modules per hook -- composition, ordering, conflict resolution
  • Payload windows and L7 inspection
  • Gossip-based module distribution
  • Module signing and trust-store verification
  • Hot-reload and runtime module replacement
  • Network egress host-calls
  • Store pooling for WASM concurrency (replace Mutex with pool)
  • Candidate selection (Select verdict for IMID/IP choice in connect_name)
  • Gossip abuse filtering via WASM (do in plain Rust first)

10. Risk register

RiskSeverityMitigation
wasmtime dependency size -- adds ~200 transitive crates, ~10-20MB to release binary, significant compile-time increaseHighFeature-gate behind wasm cargo feature. Without the feature, zero impact. Phases 1-3 deliver value with no wasmtime.
WIT component model maturityMediumStable since 2025. Pin wasmtime version. WIT surface is minimal (one world, three interfaces) so migration cost is low.
Latency on CONNECT hot pathMediumFuel budget (100K instructions) caps worst case. Benchmark in Phase 8. If unacceptable, make the hook opt-in via config.
Store concurrency -- Mutex<Store> serializes all WASM callsMediumAcceptable for v1 (CONNECT auth is not high-QPS). If contention is visible, reduce fuel_limit first. Store pooling is v2.
Module authoring complexityLowShip working example in Phase 10. wit-bindgen generates guest bindings for Rust, Go, JS, Python.

Appendix A: Files changed and estimated lines of code

New files

FilePhaseEst. linesPurpose
src/wasmrunner/mod.rs1, 4, 7, 8~75Re-exports, engine init, WasmPolicy with fuel/memory/log limits, failure tracking
src/wasmrunner/types.rs1~35Verdict, ConnectionContext, VerdictResult, ConnectionPolicy trait, AllowAll
src/wasmrunner/loader.rs6~40Load module from path, read metadata, call init() with resource limits
wit/intermesh-module.wit5~40WIT interface definition
examples/wasm-modules/connect-authz/src/lib.rs10~50Reference guest module
examples/wasm-modules/connect-authz/Cargo.toml10~15Guest crate manifest
docs/wasm-modules.md10~100Module authoring guide

Total new code: ~355 lines (excluding docs and tests)

Modified files

FilePhaseEst. changeWhat changes
Cargo.toml4+5 linesAdd optional wasmtime dependency, wasm feature
src/lib.rs1+1 lineAdd pub mod wasmrunner;
src/modules/proxy/mod.rs2, 9+15 linesAdd policy field to Handle, call evaluate() in handle_from_external, act on verdict
src/daemon.rs7+10 linesCreate WasmPolicy or AllowAll at startup, pass to proxy
src/daemon_state.rs7+10 linesAdd modules config fields (path, failure_mode, fuel_limit, max_memory_bytes, max_log_calls, max_log_bytes)

Total modified: ~41 lines across 5 existing files

Summary

  • ~355 lines of new Rust in src/wasmrunner/ (3 files, self-contained)
  • ~41 lines changed in existing Intermesh code
  • ~40 lines of WIT interface definition
  • ~100 lines of docs
  • 5 existing files touched, all with minimal changes
  • 0 lines changed in trust_engine.rs, gossip.rs, verifier.rs, connect.rs, endor/, constraint.rs, ident.rs, imid.rs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions