🐹 Go Fan Report: tetratelabs/wazero
Module Overview
wazero is a zero-dependency WebAssembly runtime for Go, written in pure Go with no CGo. It provides both a compiler (near-native speed) and interpreter engine, WASI support, and a rich embedding API for host functions — exactly the sandboxing primitive gh-aw-mcpg needs for its WASM guard system.
Current Usage in gh-aw-mcpg
- Files: 6 files reference
tetratelabs/wazero (internal/guard/wasm_lifecycle.go, wasm_exec.go, plus test files wasm_test.go, wasm_dispatch_test.go, wasm_parse_coverage_test.go, wasm_new_options_coverage_test.go)
- Key APIs Used:
wazero.NewRuntimeConfigCompiler() with WithCloseOnContextDone(true) and WithMemoryLimitPages(512) (32 MiB hard cap) for production guards
wazero.NewRuntimeConfigInterpreter() in tests (faster startup, no JIT, good for short-lived test runtimes)
wazero.NewCompilationCache() / NewCompilationCacheWithDir() — a process-global shared compilation cache (globalCompilationCache) reused across all WasmGuard instances to avoid redundant JIT compilation
wasi_snapshot_preview1.Instantiate for WASI support
wazero.NewModuleConfig() with WithStartFunctions() (suppress _start), WithStdin(strings.NewReader("")) (stdin isolation from the MCP protocol stream), WithStdout/WithStderr redirection
- Custom host functions bridging guest WASM calls to a
BackendCaller interface
Research Findings
Latest release v1.12.0 (2026-08-17, same day as this review) is the most-recently-pushed direct dependency — great timing! The project already pins v1.12.0 in go.mod, so it's up to date.
Recent Updates
- Continued hardening of interpreter/compiler engines and WASI parity fixes across recent releases.
- Ongoing focus on memory-safety and resource-limiting APIs (
WithMemoryLimitPages, WithCloseOnContextDone) — both of which this project already adopts, which is excellent alignment with upstream security guidance for sandboxing untrusted guest code.
Best Practices
- Maintainers recommend
wazero.NewRuntimeConfigCompiler() for production workloads needing near-native speed and NewRuntimeConfigInterpreter() for short-lived/test scenarios or platforms without JIT support — this project follows that split precisely (compiler for guards in production, interpreter in unit tests).
- Sharing a single
CompilationCache across runtimes to avoid recompiling identical WASM bytes is a documented pattern; the project's globalCompilationCache with a sync.Mutex-guarded swap (ConfigureGlobalCompilationCache) matches this recommendation closely.
WithCloseOnContextDone(true) is the documented way to guarantee a WASM guest can't hang indefinitely; already used for the main guard runtime.
Improvement Opportunities
🏃 Quick Wins
- The rationale for
WithMemoryLimitPages(512) and repeated NewRuntimeConfigInterpreter() calls in wasm_test.go (6+ occurrences) could be consolidated into a shared test helper (e.g. newTestRuntime(ctx)), reducing duplication and making future config changes a one-line edit.
- Consider extracting the repeated
moduleConfig := wazero.NewModuleConfig().WithName(...).WithStartFunctions().WithStdin(...).WithStdout(...).WithStderr(...) pattern into a shared builder function to keep stdin/stdout isolation guarantees consistent everywhere WASM modules are instantiated, including in tests.
✨ Feature Opportunities
- wazero's compiler config exposes
WithDebugInfoEnabled(bool) (default true). Since guard WASM binaries are untrusted third-party artifacts and this is a security-sensitive path, explicitly disabling debug info (WithDebugInfoEnabled(false)) for production guard runtimes could shave compile time/memory without functional loss, since this project doesn't symbolicate guest stack traces.
- The in-memory compilation cache (
wazero.NewCompilationCache()) has no explicit eviction bound. Given guards can be loaded from arbitrary WASM files (FindServerWASMGuardFile), consider defaulting long-running gateway deployments to the already-supported disk-backed cache (newCompilationCache(dir)) to bound memory growth.
📐 Best Practice Alignment
- Current usage is already strongly idiomatic: WASI isolation, per-guest memory caps, context-cancellation-driven cleanup, and a shared compilation cache all match wazero's own recommended production patterns for sandboxing untrusted code. No corrections needed here.
🔧 General Improvements
- Test files instantiate raw
wazero.Runtime objects independently of the shared helpers in wasm_lifecycle.go (repeated across 6 test files). Centralizing this into a small helper in internal/guard would reduce risk of test/production config drift.
Module Summary
Key Features
- Pure Go, zero-CGo, zero-dependency WebAssembly runtime
- Compiler (near-native) and Interpreter (portable) engines
- WASI Preview 1 support (
wasi_snapshot_preview1)
- Memory limiting (
WithMemoryLimitPages), context-based cancellation (WithCloseOnContextDone)
- Shared/disk-backed compilation caching for fast repeated instantiation
References
Recommendations
- Consolidate test-only runtime construction into a shared helper to reduce duplication (low risk, low effort).
- Evaluate
WithDebugInfoEnabled(false) for the production guard compiler config as a minor hardening/perf tweak.
- Consider defaulting to a disk-backed compilation cache in long-running gateway deployments to bound memory growth from arbitrarily many distinct guest WASM binaries.
Next Steps
- Prototype the test-runtime helper and measure any reduction in test boilerplate.
- Benchmark
WithDebugInfoEnabled(false) compile-time/memory impact on a representative guard binary.
- Discuss whether disk-backed compilation cache should become the default for containerized gateway deployments (already configurable via
MCP_GATEWAY_WASM_CACHE_DIR).
Generated by Go Fan
Generated by Go Fan · auto · 45.4 AIC · ⊞ 11.9K · ◷
🐹 Go Fan Report: tetratelabs/wazero
Module Overview
wazero is a zero-dependency WebAssembly runtime for Go, written in pure Go with no CGo. It provides both a compiler (near-native speed) and interpreter engine, WASI support, and a rich embedding API for host functions — exactly the sandboxing primitive gh-aw-mcpg needs for its WASM guard system.
Current Usage in gh-aw-mcpg
tetratelabs/wazero(internal/guard/wasm_lifecycle.go,wasm_exec.go, plus test fileswasm_test.go,wasm_dispatch_test.go,wasm_parse_coverage_test.go,wasm_new_options_coverage_test.go)wazero.NewRuntimeConfigCompiler()withWithCloseOnContextDone(true)andWithMemoryLimitPages(512)(32 MiB hard cap) for production guardswazero.NewRuntimeConfigInterpreter()in tests (faster startup, no JIT, good for short-lived test runtimes)wazero.NewCompilationCache()/NewCompilationCacheWithDir()— a process-global shared compilation cache (globalCompilationCache) reused across allWasmGuardinstances to avoid redundant JIT compilationwasi_snapshot_preview1.Instantiatefor WASI supportwazero.NewModuleConfig()withWithStartFunctions()(suppress_start),WithStdin(strings.NewReader(""))(stdin isolation from the MCP protocol stream),WithStdout/WithStderrredirectionBackendCallerinterfaceResearch Findings
Latest release v1.12.0 (2026-08-17, same day as this review) is the most-recently-pushed direct dependency — great timing! The project already pins
v1.12.0ingo.mod, so it's up to date.Recent Updates
WithMemoryLimitPages,WithCloseOnContextDone) — both of which this project already adopts, which is excellent alignment with upstream security guidance for sandboxing untrusted guest code.Best Practices
wazero.NewRuntimeConfigCompiler()for production workloads needing near-native speed andNewRuntimeConfigInterpreter()for short-lived/test scenarios or platforms without JIT support — this project follows that split precisely (compiler for guards in production, interpreter in unit tests).CompilationCacheacross runtimes to avoid recompiling identical WASM bytes is a documented pattern; the project'sglobalCompilationCachewith async.Mutex-guarded swap (ConfigureGlobalCompilationCache) matches this recommendation closely.WithCloseOnContextDone(true)is the documented way to guarantee a WASM guest can't hang indefinitely; already used for the main guard runtime.Improvement Opportunities
🏃 Quick Wins
WithMemoryLimitPages(512)and repeatedNewRuntimeConfigInterpreter()calls inwasm_test.go(6+ occurrences) could be consolidated into a shared test helper (e.g.newTestRuntime(ctx)), reducing duplication and making future config changes a one-line edit.moduleConfig := wazero.NewModuleConfig().WithName(...).WithStartFunctions().WithStdin(...).WithStdout(...).WithStderr(...)pattern into a shared builder function to keep stdin/stdout isolation guarantees consistent everywhere WASM modules are instantiated, including in tests.✨ Feature Opportunities
WithDebugInfoEnabled(bool)(default true). Since guard WASM binaries are untrusted third-party artifacts and this is a security-sensitive path, explicitly disabling debug info (WithDebugInfoEnabled(false)) for production guard runtimes could shave compile time/memory without functional loss, since this project doesn't symbolicate guest stack traces.wazero.NewCompilationCache()) has no explicit eviction bound. Given guards can be loaded from arbitrary WASM files (FindServerWASMGuardFile), consider defaulting long-running gateway deployments to the already-supported disk-backed cache (newCompilationCache(dir)) to bound memory growth.📐 Best Practice Alignment
🔧 General Improvements
wazero.Runtimeobjects independently of the shared helpers inwasm_lifecycle.go(repeated across 6 test files). Centralizing this into a small helper ininternal/guardwould reduce risk of test/production config drift.Module Summary
github.com/tetratelabs/wazerov1.12.0Key Features
wasi_snapshot_preview1)WithMemoryLimitPages), context-based cancellation (WithCloseOnContextDone)References
Recommendations
WithDebugInfoEnabled(false)for the production guard compiler config as a minor hardening/perf tweak.Next Steps
WithDebugInfoEnabled(false)compile-time/memory impact on a representative guard binary.MCP_GATEWAY_WASM_CACHE_DIR).Generated by Go Fan