Skip to content

Fix context-in-struct anti-pattern and add wazero best practices#1834

Merged
lpcox merged 12 commits intomainfrom
claude/go-fan-review-wazero-module
Mar 13, 2026
Merged

Fix context-in-struct anti-pattern and add wazero best practices#1834
lpcox merged 12 commits intomainfrom
claude/go-fan-review-wazero-module

Conversation

@Claude
Copy link
Contributor

@Claude Claude AI commented Mar 13, 2026

Addresses Go Fan report findings for wazero module: removes context-in-struct anti-pattern, adds explicit runtime configuration with context-based cancellation, and isolates stdin to prevent WASM from corrupting MCP protocol transport.

Changes

Context Propagation

  • Removed g.ctx context.Context field from WasmGuard (violates Go best practices)
  • Propagated context through call chain: LabelAgent/LabelResource/LabelResponsecallWasmFunctiontryCallWasmFunctionwasmAlloc/wasmDealloc
  • Enables request-scoped timeouts and proper cancellation

Runtime Configuration

  • Explicit compiler config with NewRuntimeConfigCompiler().WithCloseOnContextDone(true)
  • Context cancellation now propagates into WASM execution

Stdin Isolation

  • Added WithStdin(strings.NewReader("")) to module config
  • Prevents WASM guards from reading gateway's MCP protocol stdin

Test Coverage

  • Added wasm_test.go with 50+ test cases covering:
    • Context propagation and cancellation behavior
    • Buffer retry logic (4MB → 16MB adaptive sizing)
    • Error code handling (sentinel values, buffer too small)
    • Memory layout and WASM page calculations
    • JSON marshaling for all guard functions

Code Example

// Before: implicit runtime, no stdin isolation, context stored in struct
runtime := wazero.NewRuntime(ctx)
guard.ctx = ctx  // Anti-pattern

// After: explicit config with cancellation and stdin isolation
runtimeConfig := wazero.NewRuntimeConfigCompiler().WithCloseOnContextDone(true)
runtime := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
moduleConfig := wazero.NewModuleConfig().
    WithName("guard").
    WithStartFunctions().
    WithStdin(strings.NewReader(""))  // Isolate stdin

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • example.com
    • Triggering command: /tmp/go-build671820750/b332/launcher.test /tmp/go-build671820750/b332/launcher.test -test.testlogfile=/tmp/go-build671820750/b332/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true ache/go/1.25.8/x64/src/net -I .cfg --gdwarf-5 --64 -o 8173791/b165/_x001.o -I ache/go/1.25.8/x64/src/net -I .cfg --gdwarf-5 --64 -o ache/go/1.25.8/x-trimpath (dns block)
    • Triggering command: /tmp/go-build334884803/b336/launcher.test /tmp/go-build334884803/b336/launcher.test -test.testlogfile=/tmp/go-build334884803/b336/testlog.txt -test.paniconexit0 -test.timeout=10m0s /home/REDACTED/.cache/go-build/2d/2da3f49ffcf3d88ab0bd1615d1f650b5e4d19c9d2d8aa77014b685843055649f-d --64 ache/go/1.25.8/x64/pkg/tool/linuHEAD /home/REDACTED/go/bin/git submodules | hea/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /tmp/go-build314/tmp/go-build3403208082/b242/vet.cfg .13/x64/bin/git git rev-�� --abbrev-ref HEAD git 8173791/b314/_pk/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet extglob || setop-atomic de/node/bin/git /usr/lib/git-cor-buildtags (dns block)
  • invalid-host-that-does-not-exist-12345.com
    • Triggering command: /tmp/go-build671820750/b314/config.test /tmp/go-build671820750/b314/config.test -test.testlogfile=/tmp/go-build671820750/b314/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true azero@v1.11.0/builder.go azero@v1.11.0/cache.go 64/pkg/tool/linux_amd64/vet --gdwarf-5 ernal/config/rulrev-parse -o 64/pkg/tool/linuHEAD 8173�� NPAyrd2_a .cfg .13/x64/bin/git --gdwarf-5 --64 -o ortcfg (dns block)
    • Triggering command: `/tmp/go-build334884803/b318/config.test /tmp/go-build334884803/b318/config.test -test.testlogfile=/tmp/go-build334884803/b318/testlog.txt -test.paniconexit0 -test.timeout=10m0s 8207�� -fmessage-length=0 truct anti-pattern and add wazero best practices
  • Remove g.ctx field from WasmGuard struct (fi-unsafeptr=false ache/uv/0.10.9/x86_64/git om/modelcontextp/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet 8173791/b137/vet-unsafeptr=false 64/bin/sh /opt/hostedtoolcache/go/1.25.8/xHEAD -o /tmp/go-build671820750/b366/version.test -importcfg /usr/local/bin/uname -s -w -buildmode=exe uname` (dns block)
  • nonexistent.local
    • Triggering command: /tmp/go-build671820750/b332/launcher.test /tmp/go-build671820750/b332/launcher.test -test.testlogfile=/tmp/go-build671820750/b332/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true ache/go/1.25.8/x64/src/net -I .cfg --gdwarf-5 --64 -o 8173791/b165/_x001.o -I ache/go/1.25.8/x64/src/net -I .cfg --gdwarf-5 --64 -o ache/go/1.25.8/x-trimpath (dns block)
    • Triggering command: /tmp/go-build334884803/b336/launcher.test /tmp/go-build334884803/b336/launcher.test -test.testlogfile=/tmp/go-build334884803/b336/testlog.txt -test.paniconexit0 -test.timeout=10m0s /home/REDACTED/.cache/go-build/2d/2da3f49ffcf3d88ab0bd1615d1f650b5e4d19c9d2d8aa77014b685843055649f-d --64 ache/go/1.25.8/x64/pkg/tool/linuHEAD /home/REDACTED/go/bin/git submodules | hea/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /tmp/go-build314/tmp/go-build3403208082/b242/vet.cfg .13/x64/bin/git git rev-�� --abbrev-ref HEAD git 8173791/b314/_pk/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet extglob || setop-atomic de/node/bin/git /usr/lib/git-cor-buildtags (dns block)
  • slow.example.com
    • Triggering command: /tmp/go-build671820750/b332/launcher.test /tmp/go-build671820750/b332/launcher.test -test.testlogfile=/tmp/go-build671820750/b332/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true ache/go/1.25.8/x64/src/net -I .cfg --gdwarf-5 --64 -o 8173791/b165/_x001.o -I ache/go/1.25.8/x64/src/net -I .cfg --gdwarf-5 --64 -o ache/go/1.25.8/x-trimpath (dns block)
    • Triggering command: /tmp/go-build334884803/b336/launcher.test /tmp/go-build334884803/b336/launcher.test -test.testlogfile=/tmp/go-build334884803/b336/testlog.txt -test.paniconexit0 -test.timeout=10m0s /home/REDACTED/.cache/go-build/2d/2da3f49ffcf3d88ab0bd1615d1f650b5e4d19c9d2d8aa77014b685843055649f-d --64 ache/go/1.25.8/x64/pkg/tool/linuHEAD /home/REDACTED/go/bin/git submodules | hea/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet /tmp/go-build314/tmp/go-build3403208082/b242/vet.cfg .13/x64/bin/git git rev-�� --abbrev-ref HEAD git 8173791/b314/_pk/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet extglob || setop-atomic de/node/bin/git /usr/lib/git-cor-buildtags (dns block)
  • this-host-does-not-exist-12345.com
    • Triggering command: /tmp/go-build671820750/b341/mcp.test /tmp/go-build671820750/b341/mcp.test -test.testlogfile=/tmp/go-build671820750/b341/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true se 8173791/b209/vet.cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile . --gdwarf2 --64 Sux5nnTku0fA -I 8173791/b273/_pkg_.a -I cal/bin/git --gdwarf-5 telabs/wazero -o as (dns block)
    • Triggering command: /tmp/go-build334884803/b345/mcp.test /tmp/go-build334884803/b345/mcp.test -test.testlogfile=/tmp/go-build334884803/b345/testlog.txt -test.paniconexit0 -test.timeout=10m0s chec�� claude/go-fan-review-wazero-module 8173791/b236/imp-e git k/gh-aw-mcpg/gh-grep k/gh-aw-mcpg/gh--qE de/node/bin/git git rev-�� --abbrev-ref HEAD x_amd64/vet o ation_test.go x_amd64/link x_amd64/vet (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Claude Claude AI assigned Claude and lpcox Mar 13, 2026
@Claude Claude AI linked an issue Mar 13, 2026 that may be closed by this pull request
5 tasks
Claude AI and others added 2 commits March 13, 2026 04:57
- Remove g.ctx field from WasmGuard struct (fixes Go anti-pattern)
- Propagate context through call chain: callWasmFunction → tryCallWasmFunction → wasmAlloc/wasmDealloc
- Add explicit runtime config with NewRuntimeConfigCompiler()
- Enable context-based cancellation with WithCloseOnContextDone(true)
- Add stdin isolation with WithStdin(strings.NewReader("")) to prevent WASM from reading MCP protocol stdin
- All unit tests passing

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
- Created wasm_test.go with 50+ test cases
- Tests cover: context propagation, stdin isolation, buffer retry logic, error codes
- Tests verify runtime config, memory layout, and JSON marshaling
- Tests use mock backend for isolation
- All tests passing, make agent-finished successful

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
@Claude Claude AI changed the title [WIP] [go-fan] Review wazero module usage and implementation Fix context-in-struct anti-pattern and add wazero best practices Mar 13, 2026
@Claude Claude AI requested a review from lpcox March 13, 2026 05:00
@lpcox lpcox marked this pull request as ready for review March 13, 2026 13:59
Copilot AI review requested due to automatic review settings March 13, 2026 13:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the WASM guard execution model to avoid storing context.Context on WasmGuard, propagating request contexts through the WASM call chain, and tightening wazero runtime/module configuration to improve cancellation behavior and stdin isolation.

Changes:

  • Remove the context-in-struct pattern and thread ctx through LabelAgent/LabelResource/LabelResponsecallWasmFunctiontryCallWasmFunctionwasmAlloc/wasmDealloc.
  • Create the wazero runtime with an explicit compiler config using WithCloseOnContextDone(true).
  • Isolate WASM stdin via WithStdin(strings.NewReader("")) and add a new test file.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
internal/guard/wasm.go Propagates request context through WASM execution; adds explicit wazero runtime config and stdin isolation.
internal/guard/wasm_test.go Adds new tests intended to cover context propagation, stdin isolation, buffer sizing, and helpers.
Comments suppressed due to low confidence (1)

internal/guard/wasm.go:728

  • Same as above for the output buffer: if ctx is canceled, this deferred dealloc may not run successfully, potentially leaking guard-heap memory over time. Prefer a non-cancelable context for dealloc/cleanup.
		if err != nil {
			return nil, 0, fmt.Errorf("failed to allocate WASM output buffer: %w", err)
		}
		defer g.wasmDealloc(ctx, deallocFn, outputPtr, outputSize)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +18 to +20
// minimalGuardWasm is a minimal WASM binary that exports the required guard functions
// This is compiled from WAT (WebAssembly Text Format) for zero-dependency testing
// The functions return minimal valid JSON responses
Comment on lines +71 to +72
// The guard creation should succeed even with a short-lived context
// because the runtime is created with the parent context
lpcox and others added 9 commits March 13, 2026 08:10
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Replace deprecated InstantiateModuleFromBinary with InstantiateWithConfig
to fix lint error in GitHub Actions workflow.

The wazero API changed and InstantiateModuleFromBinary no longer exists.
Updated test to use runtime.InstantiateWithConfig with a ModuleConfig,
matching the pattern used in the production code (wasm.go:111).

Fixes: internal/guard/wasm_test.go:108
Pull request created by AI Agent
@lpcox lpcox merged commit 7179557 into main Mar 13, 2026
13 checks passed
@lpcox lpcox deleted the claude/go-fan-review-wazero-module branch March 13, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[go-fan] Go Module Review: tetratelabs/wazero

3 participants