You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
wazero is a zero-dependency, pure-Go WebAssembly runtime โ no CGo, no external C libraries. It supports the WebAssembly Core Specification plus WASI Preview 1, with both JIT (compiler) and interpreter backends. This makes it uniquely suited for embedding WASM execution in Go services like this gateway.
Version in use: v1.11.0
Current Usage in gh-aw-mcpg
The project uses wazero to run WASM-based DIFC security guards in-process. Guards are sandboxed WASM binaries that label MCP resources and responses to enforce information-flow control policies.
โ sys.ExitError used for type-safe WASI exit discrimination
โ Guard-allocator preferred path (alloc/dealloc exports) for safe memory management
โ Trap poisoning โ permanently marks failed guards to prevent use of corrupted state
โ context.WithoutCancel for cleanup to avoid dealloc skips on context cancellation
Recent Updates (wazero v1.11)
The current version v1.11.0 is the latest stable. wazero has an active release cadence with improvements in memory management, WASI compatibility, and compilation speed. Disk-based compilation cache has been available since early versions.
Best Practices from Maintainers
Prefer CompiledModule + multiple instantiations over recreating the runtime for the same binary
Use wazero.NewCompilationCacheWithDir() for disk persistence across restarts
Memory limits should be encoded in the WASM binary itself (max pages in the memory section)
Improvement Opportunities
๐ Quick Wins
Disk-based compilation cache โ Replace wazero.NewCompilationCache() with wazero.NewCompilationCacheWithDir(cacheDir) to persist JIT artifacts across gateway restarts. This eliminates cold-start compilation latency (can be significant for complex WASM guard binaries). A subdirectory of the existing --log-dir or a dedicated cache path (e.g., MCP_GATEWAY_WASM_CACHE_DIR) would work well.
Warn on non-allocator path โ tryCallWasmFunction has a fallback that manually places I/O buffers at the end of WASM linear memory. This is fragile: if the guard's heap grows into that region, behavior is undefined. The fallback should emit a logger.LogWarn when used, encouraging guard authors to export alloc/dealloc.
โจ Feature Opportunities
Instance pooling for concurrency โ Currently each WasmGuard serializes all calls through a mutex because WASM modules are single-threaded. wazero supports instantiating the same CompiledModule multiple times independently. A pool of N instances per guard would allow N concurrent calls without blocking, improving throughput under load. This would require a sync.Pool or a channel-based pool of module instances.
Pre-compile to CompiledModule โ Split guard creation into two phases: runtime.CompileModule(ctx, wasmBytes) โ CompiledModule, then runtime.InstantiateModule(ctx, compiled, config). This separates compilation (done once) from instantiation (done per pool slot), and is also more idiomatic for the pooling opportunity above.
๐ Best Practice Alignment
Trap string matching fragility โ isWasmTrap() uses strings.Contains(err.Error(), "wasm error:") as a fallback for non-WASI execution faults (e.g., Rust panic โ unreachable). This relies on wazero's internal error message format which is not part of the public API and could change across versions. It would be worth opening a discussion with the wazero maintainers about a typed error for execution traps, or adding a version comment to flag this as a known coupling.
Module name collision โ WithName("guard") is hard-coded for all guard instances. Currently each guard gets its own runtime, so there's no collision. But if the architecture ever changes to share runtimes, this would fail silently. A name derived from the guard's name field (e.g., WithName(name)) would be safer and more debuggable in wazero traces.
๐ง General Improvements
Document memory limit responsibility โ There is no per-module memory cap enforced from the host. If a guard WASM binary omits a (memory N M) max bound, it could consume unbounded memory. A code comment or guard authorship guide should document that max memory pages must be set in the WASM binary itself, and that the gateway does not enforce an independent cap.
Recommendations (Prioritized)
Priority
Item
Impact
Effort
High
Disk-based compilation cache
Eliminates cold-start penalty
Low
High
Warn on non-allocator fallback path
Prevents subtle memory corruption
Low
Medium
Pre-compile to CompiledModule
Cleaner architecture, enables pooling
Medium
Medium
Instance pooling
Better concurrency under load
High
Low
Trap string matching โ document or fix
API stability
Low
Low
Module name from guard name
Defensive future-proofing
Very Low
Next Steps
Explore wazero.NewCompilationCacheWithDir() โ add a MCP_GATEWAY_WASM_CACHE_DIR env var and --wasm-cache-dir flag, defaulting to a subdirectory of --log-dir
Add a logger.LogWarn in the non-allocator fallback path in tryCallWasmFunction
Consider refactoring to CompiledModule as groundwork for future instance pooling
Add a note to guard authorship documentation about WASM memory limits
Generated by Go Fan ๐น Module summary saved to: /tmp/gh-aw/agent/wazero.md (specs/mods/ not writable in CI) Run: ยง25364088625
Note
๐ Integrity filter blocked 12 items
The following items were blocked because they don't meet the GitHub integrity level.
search_repositories search_repositories: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".
๐น Go Fan Report: tetratelabs/wazero
Module Overview
wazero is a zero-dependency, pure-Go WebAssembly runtime โ no CGo, no external C libraries. It supports the WebAssembly Core Specification plus WASI Preview 1, with both JIT (compiler) and interpreter backends. This makes it uniquely suited for embedding WASM execution in Go services like this gateway.
Version in use:
v1.11.0Current Usage in gh-aw-mcpg
The project uses wazero to run WASM-based DIFC security guards in-process. Guards are sandboxed WASM binaries that label MCP resources and responses to enforce information-flow control policies.
internal/guard/wasm.go,wasm_parse.go,wasm_test.go)wazero,wazero/api,wazero/imports/wasi_snapshot_preview1,wazero/sysNewRuntimeConfigCompiler()+WithCloseOnContextDone(true)+WithCompilationCache()NewRuntimeWithConfig()โ one runtime per guard instancewasi_snapshot_preview1.Instantiate()โ WASI host supportNewHostModuleBuilder("env")โ customcall_backendandhost_loghost functionsNewModuleConfig()with stdin isolationapi.Module.ExportedFunction(),api.Function.Call()โ function dispatchapi.Memory.Read/Write/Grow/ReadUint32Leโ linear memory accesssys.ExitErrorโ trap/exit discriminationNewCompilationCache()โ shared in-memory JIT cacheResearch Findings
Architecture Quality
The implementation is well-structured:
CompilationCacheacross all guard instances โ avoids redundant JIT compilationWithCloseOnContextDone(true)โ proper context-aware cancellationsys.ExitErrorused for type-safe WASI exit discriminationalloc/deallocexports) for safe memory managementcontext.WithoutCancelfor cleanup to avoid dealloc skips on context cancellationRecent Updates (wazero v1.11)
The current version v1.11.0 is the latest stable. wazero has an active release cadence with improvements in memory management, WASI compatibility, and compilation speed. Disk-based compilation cache has been available since early versions.
Best Practices from Maintainers
CompiledModule+ multiple instantiations over recreating the runtime for the same binarywazero.NewCompilationCacheWithDir()for disk persistence across restartsImprovement Opportunities
๐ Quick Wins
Disk-based compilation cache โ Replace
wazero.NewCompilationCache()withwazero.NewCompilationCacheWithDir(cacheDir)to persist JIT artifacts across gateway restarts. This eliminates cold-start compilation latency (can be significant for complex WASM guard binaries). A subdirectory of the existing--log-diror a dedicated cache path (e.g.,MCP_GATEWAY_WASM_CACHE_DIR) would work well.Warn on non-allocator path โ
tryCallWasmFunctionhas a fallback that manually places I/O buffers at the end of WASM linear memory. This is fragile: if the guard's heap grows into that region, behavior is undefined. The fallback should emit alogger.LogWarnwhen used, encouraging guard authors to exportalloc/dealloc.โจ Feature Opportunities
Instance pooling for concurrency โ Currently each
WasmGuardserializes all calls through a mutex because WASM modules are single-threaded. wazero supports instantiating the sameCompiledModulemultiple times independently. A pool of N instances per guard would allow N concurrent calls without blocking, improving throughput under load. This would require async.Poolor a channel-based pool of module instances.Pre-compile to
CompiledModuleโ Split guard creation into two phases:runtime.CompileModule(ctx, wasmBytes)โCompiledModule, thenruntime.InstantiateModule(ctx, compiled, config). This separates compilation (done once) from instantiation (done per pool slot), and is also more idiomatic for the pooling opportunity above.๐ Best Practice Alignment
Trap string matching fragility โ
isWasmTrap()usesstrings.Contains(err.Error(), "wasm error:")as a fallback for non-WASI execution faults (e.g., Rust panic โunreachable). This relies on wazero's internal error message format which is not part of the public API and could change across versions. It would be worth opening a discussion with the wazero maintainers about a typed error for execution traps, or adding a version comment to flag this as a known coupling.Module name collision โ
WithName("guard")is hard-coded for all guard instances. Currently each guard gets its ownruntime, so there's no collision. But if the architecture ever changes to share runtimes, this would fail silently. A name derived from the guard'snamefield (e.g.,WithName(name)) would be safer and more debuggable in wazero traces.๐ง General Improvements
(memory N M)max bound, it could consume unbounded memory. A code comment or guard authorship guide should document that max memory pages must be set in the WASM binary itself, and that the gateway does not enforce an independent cap.Recommendations (Prioritized)
CompiledModuleNext Steps
wazero.NewCompilationCacheWithDir()โ add aMCP_GATEWAY_WASM_CACHE_DIRenv var and--wasm-cache-dirflag, defaulting to a subdirectory of--log-dirlogger.LogWarnin the non-allocator fallback path intryCallWasmFunctionCompiledModuleas groundwork for future instance poolingGenerated by Go Fan ๐น
Module summary saved to:
/tmp/gh-aw/agent/wazero.md(specs/mods/ not writable in CI)Run: ยง25364088625
Note
๐ Integrity filter blocked 12 items
The following items were blocked because they don't meet the GitHub integrity level.
search_repositories: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".search_repositories: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".search_repositories: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_latest_release: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".get_file_contents: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".list_releases: has lower integrity than agent requires. The agent cannot read data with integrity below "unapproved".To allow these resources, lower
min-integrityin your GitHub frontmatter: