-
Notifications
You must be signed in to change notification settings - Fork 4.5k
[model-gateway] Add WASM support for middleware #12471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
slin1237
merged 48 commits into
sgl-project:main
from
openanolis:tonyluj/sgl-router-wasm-latest
Dec 5, 2025
Merged
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
3307448
[model-gateway] wasm: add wasm module and module manager (#12471)
tonyluj 65a39e2
[model-gateway] wasm: add wasm runtime and config (#12471)
tonyluj 082e754
[model-gateway] wasm: runtime add thread pool (#12471)
tonyluj 4f3cefb
[model-gateway] wasm: using wasm module manager as top level executor…
tonyluj 890a999
[model-gateway] wasm: add basic metrics (#12471)
tonyluj 92c6a76
[model-gateway] wasm: add runtime tests (#12471)
tonyluj 66c9541
[model-gateway] wasm: add config unit tests (#12471)
tonyluj d4aef4f
[model-gateway] wasm: code format (#12471)
tonyluj 0ffdde0
[model-gateway] wasm: drain all task when drop (#12471)
tonyluj 2f838a6
[model-gateway] wasm: fix timeout when drop (#12471)
tonyluj 1930935
[model-gateway] wasm: code format (#12471)
tonyluj 808ce48
[model-gateway] wasm: add middleware attach type (#12471)
tonyluj 3d59f00
[model-gateway] wasm: add errors (#12471)
tonyluj bd31f84
[model-gateway] wasm: code format (#12471)
tonyluj bc654fb
[model-gateway] wasm: add api to manage wasm modules (#12471)
tonyluj 91f291e
[model-gateway] wasm: introduce wit interface (#12471)
tonyluj 507224b
[model-gateway] wasm: add wit executor (#12471)
tonyluj cca52ee
[model-gateway] wasm: add middleware logic (#12471)
tonyluj 99ae390
[model-gateway] wasm: fix conflicts (#12471)
tonyluj 4e86de8
[model-gateway] wasm: remote unused executors (#12471)
tonyluj 288bdbb
[model-gateway] wasm: add docs and examples (#12471)
tonyluj b31b7f3
[model-gateway] wasm: add myself to wasm CODEOWNERS (#12471)
tonyluj 2c006c1
[model-gateway] wasm: code format (#12471)
tonyluj 13f0bf1
[model-gateway] wasm: move functions to wasm module to make middlewar…
tonyluj e64d30b
[model-gateway] wasm: update examples for more safe access of RATE_LI…
tonyluj c6aa48e
[model-gateway] wasm: replace unwarp with error handling (#12471)
tonyluj 95b5ae0
[model-gateway] wasm: remove unwrap in middleware (#12471)
tonyluj cbba663
[model-gateway] wasm: some minor improvements (#12471)
tonyluj b95479e
[model-gateway] wasm: simplify auth logic (#12471)
tonyluj 2ba58ba
[model-gateway] wasm: remove unused code (#12471)
tonyluj 543093b
[model-gateway] wasm: fix compile error for missing crates (#12471)
tonyluj 42df7e8
[model-gateway] wasm: using workflow to add and remove wasm modules
tonyluj 54a43bf
[model-gateway] wasm: add tests
tonyluj 21668d5
[model-gateway] wasm: fix minor bugs for testing
tonyluj f48a124
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj c35d750
[model-gateway] wasm: fix cargo clippy warnings
tonyluj 5dc89c7
[model-gateway] wasm: fix end of files
tonyluj 93ccbfe
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj 68d0159
[model-gateway] wasm: fix testing issue
tonyluj 212a5f6
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj 29fe306
[model-gateway] wasm: create wasm tests dynamically
tonyluj a0ce8cc
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj 32b6900
[model-gateway] wasm: fix clippy warnings
tonyluj 7776f46
[model-gateway] wasm: rename wit with interface
tonyluj e34ad98
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj dd9a0e1
[model-gateway] wasm: wit -> wasm interface type
tonyluj 09acf3b
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj 89171d0
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Rust build artifacts | ||
| target/ | ||
| **/target/ | ||
|
|
||
| # Cargo lock files (examples don't need locked dependencies) | ||
| Cargo.lock | ||
| **/Cargo.lock | ||
|
|
||
| # Generated WASM files | ||
| *.wasm | ||
| *.component.wasm | ||
| **/*.wasm | ||
| **/*.component.wasm | ||
|
|
||
| # Build scripts output | ||
| build/ | ||
|
|
||
| # IDE files | ||
| .idea/ | ||
| .vscode/ | ||
| *.swp | ||
| *.swo | ||
| *~ | ||
|
|
||
| # OS files | ||
| .DS_Store | ||
| Thumbs.db |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # WASM Guest Examples for sgl-router | ||
|
|
||
| This directory contains example WASM middleware components demonstrating how to implement custom middleware for sgl-router using the WebAssembly Component Model. | ||
|
|
||
| ## Examples Overview | ||
|
|
||
| ### [wasm-guest-auth](./wasm-guest-auth/) | ||
|
|
||
| API key authentication middleware that validates API keys for requests to `/api` and `/v1` paths. | ||
|
|
||
| **Features:** | ||
| - Validates API keys from `Authorization` header or `x-api-key` header | ||
| - Returns `401 Unauthorized` for missing or invalid keys | ||
| - Attach point: `OnRequest` only | ||
|
|
||
| **Use case:** Protect API endpoints with API key authentication. | ||
|
|
||
| ### [wasm-guest-logging](./wasm-guest-logging/) | ||
|
|
||
| Request tracking and status code conversion middleware. | ||
|
|
||
| **Features:** | ||
| - Adds tracking headers (`x-request-id`, `x-wasm-processed`, `x-processed-at`, `x-api-route`) | ||
| - Converts `500` errors to `503` for better client handling | ||
| - Attach points: `OnRequest` and `OnResponse` | ||
|
|
||
| **Use case:** Request tracing and error status code conversion. | ||
|
|
||
| ### [wasm-guest-ratelimit](./wasm-guest-ratelimit/) | ||
|
|
||
| Rate limiting middleware with configurable limits. | ||
|
|
||
| **Features:** | ||
| - Rate limiting per identifier (API Key, IP, or Request ID) | ||
| - Default: 60 requests per minute | ||
| - Returns `429 Too Many Requests` when limit exceeded | ||
| - Attach point: `OnRequest` only | ||
|
|
||
| **Note:** This is a simplified demonstration with per-instance state. For production, use router-level rate limiting with shared state. | ||
|
|
||
| **Use case:** Protect against request flooding and abuse. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| Each example includes its own README with detailed build and deployment instructions. See individual example directories for: | ||
|
|
||
| - Build instructions | ||
| - Deployment configuration | ||
| - Customization options | ||
| - Testing examples | ||
|
|
||
| ## Common Prerequisites | ||
|
|
||
| All examples require: | ||
|
|
||
| - Rust toolchain (latest stable) | ||
| - `wasm32-wasip2` target: `rustup target add wasm32-wasip2` | ||
| - `wasm-tools`: `cargo install wasm-tools` | ||
| - sgl-router running with WASM enabled (`--enable-wasm`) | ||
|
|
||
| ## Building All Examples | ||
|
|
||
| ```bash | ||
| cd examples/wasm | ||
| for example in wasm-guest-auth wasm-guest-logging wasm-guest-ratelimit; do | ||
| echo "Building $example..." | ||
| cd $example && ./build.sh && cd .. | ||
| done | ||
| ``` | ||
|
|
||
| ## Deploying Multiple Modules | ||
|
|
||
| You can deploy all three modules together: | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:3000/wasm \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "modules": [ | ||
| { | ||
| "name": "auth-middleware", | ||
| "file_path": "/path/to/wasm_guest_auth.component.wasm", | ||
| "module_type": "Middleware", | ||
| "attach_points": [{"Middleware": "OnRequest"}] | ||
| }, | ||
| { | ||
| "name": "logging-middleware", | ||
| "file_path": "/path/to/wasm_guest_logging.component.wasm", | ||
| "module_type": "Middleware", | ||
| "attach_points": [{"Middleware": "OnRequest"}, {"Middleware": "OnResponse"}] | ||
| }, | ||
| { | ||
| "name": "ratelimit-middleware", | ||
| "file_path": "/path/to/wasm_guest_ratelimit.component.wasm", | ||
| "module_type": "Middleware", | ||
| "attach_points": [{"Middleware": "OnRequest"}] | ||
| } | ||
| ] | ||
| }' | ||
| ``` | ||
|
|
||
| Modules execute in the order they are deployed. If a module returns `Reject`, subsequent modules won't execute. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [package] | ||
| name = "wasm-guest-auth" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| [lib] | ||
| crate-type = ["cdylib"] | ||
|
|
||
| [dependencies] | ||
| wit-bindgen = { version = "0.21", features = ["macros"] } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| # WASM Auth Example for sgl-router | ||
|
|
||
| This example demonstrates API key authentication middleware for sgl-router using the WebAssembly Component Model. | ||
|
|
||
| ## Overview | ||
|
|
||
| This middleware validates API keys for requests to `/api` and `/v1` paths: | ||
|
|
||
| - Supports `Authorization: Bearer <key>` header | ||
| - Supports `Authorization: ApiKey <key>` header | ||
| - Supports `x-api-key` header | ||
| - Returns `401 Unauthorized` for missing or invalid keys | ||
|
|
||
| **Default API Key**: `secret-api-key-12345` | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ### Build and Deploy | ||
|
|
||
| ```bash | ||
| # Build | ||
| cd examples/wasm-guest-auth | ||
| ./build.sh | ||
|
|
||
| # Deploy (replace file_path with actual path) | ||
| curl -X POST http://localhost:3000/wasm \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "modules": [{ | ||
| "name": "auth-middleware", | ||
| "file_path": "/absolute/path/to/wasm_guest_auth.component.wasm", | ||
| "module_type": "Middleware", | ||
| "attach_points": [{"Middleware": "OnRequest"}] | ||
| }] | ||
| }' | ||
| ``` | ||
|
|
||
| ### Customization | ||
|
|
||
| Modify `EXPECTED_API_KEY` in `src/lib.rs`: | ||
|
|
||
| ```rust | ||
| const EXPECTED_API_KEY: &str = "your-secret-key"; | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| ```bash | ||
| # Test unauthorized (returns 401) | ||
| curl -v http://localhost:3000/api/test | ||
|
|
||
| # Test authorized (passes) | ||
| curl -v http://localhost:3000/api/test \ | ||
| -H "Authorization: Bearer secret-api-key-12345" | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| - Verify API key matches `EXPECTED_API_KEY` in code | ||
| - Check request header format and path (`/api` or `/v1`) | ||
| - Verify module is attached to `OnRequest` phase | ||
| - Check router logs for errors | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| #!/bin/bash | ||
| # Build script for WASM guest auth example | ||
| # This script simplifies the build process for the WASM middleware component | ||
|
|
||
| set -e | ||
|
|
||
| echo "Building WASM guest auth example..." | ||
|
|
||
| # Check if we're in the right directory | ||
| if [ ! -f "Cargo.toml" ]; then | ||
| echo "Error: Cargo.toml not found. Please run this script from the wasm-guest-auth directory." | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Check for required tools | ||
| command -v cargo >/dev/null 2>&1 || { echo "Error: cargo is required but not installed. Aborting." >&2; exit 1; } | ||
|
|
||
| # Check and install wasm32-wasip2 target | ||
| echo "Checking for wasm32-wasip2 target..." | ||
| if ! rustup target list --installed | grep -q "wasm32-wasip2"; then | ||
| echo "wasm32-wasip2 target not found. Installing..." | ||
| rustup target add wasm32-wasip2 | ||
| echo "✓ wasm32-wasip2 target installed" | ||
| else | ||
| echo "✓ wasm32-wasip2 target already installed" | ||
| fi | ||
|
|
||
| # Check for wasm-tools | ||
| if ! command -v wasm-tools >/dev/null 2>&1; then | ||
| echo "Error: wasm-tools is required but not installed." | ||
| echo "Install it with: cargo install wasm-tools" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Build with cargo (wit-bindgen uses cargo, not wasm-pack) | ||
| echo "Running cargo build..." | ||
| cargo build --target wasm32-wasip2 --release | ||
|
|
||
| # Output locations | ||
| WASM_MODULE="target/wasm32-wasip2/release/wasm_guest_auth.wasm" | ||
| WASM_COMPONENT="target/wasm32-wasip2/release/wasm_guest_auth.component.wasm" | ||
|
|
||
| if [ ! -f "$WASM_MODULE" ]; then | ||
| echo "Error: Build failed - WASM module not found" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Check if the file is already a component | ||
| echo "Checking WASM file format..." | ||
| if wasm-tools print "$WASM_MODULE" 2>/dev/null | grep -q "^(\s*component"; then | ||
| echo "✓ WASM file is already in component format" | ||
| # Copy to component path for consistency | ||
| cp "$WASM_MODULE" "$WASM_COMPONENT" | ||
| else | ||
| # Wrap the WASM module into a component format | ||
| echo "Wrapping WASM module into component format..." | ||
| wasm-tools component new "$WASM_MODULE" -o "$WASM_COMPONENT" | ||
| if [ ! -f "$WASM_COMPONENT" ]; then | ||
| echo "Error: Failed to create component file" | ||
| exit 1 | ||
| fi | ||
| fi | ||
|
|
||
| if [ -f "$WASM_COMPONENT" ]; then | ||
| echo "" | ||
| echo "✓ Build successful!" | ||
| echo " WASM module: $WASM_MODULE" | ||
| echo " WASM component: $WASM_COMPONENT" | ||
| echo "" | ||
| echo "Next steps:" | ||
| echo "1. Use the component file ($WASM_COMPONENT) when adding the module" | ||
| echo "2. Prepare the module configuration (see README.md for JSON format)" | ||
| echo "3. Use the API endpoint to add the module (see README.md for details)" | ||
| else | ||
| echo "Error: Component file not found" | ||
| exit 1 | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| //! WASM Guest Auth Example for sgl-router | ||
| //! | ||
| //! This example demonstrates API key authentication middleware | ||
| //! for sgl-router using the WebAssembly Component Model. | ||
| //! | ||
| //! Features: | ||
| //! - API Key authentication | ||
|
|
||
| wit_bindgen::generate!({ | ||
| path: "../../../src/wasm/interface", | ||
| world: "sgl-router", | ||
| }); | ||
|
|
||
| use exports::sgl::router::{ | ||
| middleware_on_request::Guest as OnRequestGuest, | ||
| middleware_on_response::Guest as OnResponseGuest, | ||
| }; | ||
| use sgl::router::middleware_types::{Action, Request, Response}; | ||
|
|
||
| /// Expected API Key (in production, this should be passed as configuration) | ||
| const EXPECTED_API_KEY: &str = "secret-api-key-12345"; | ||
|
|
||
| /// Main middleware implementation | ||
| struct Middleware; | ||
|
|
||
| // Helper function to find header value | ||
| fn find_header_value( | ||
| headers: &[sgl::router::middleware_types::Header], | ||
| name: &str, | ||
| ) -> Option<String> { | ||
| headers | ||
| .iter() | ||
| .find(|h| h.name.eq_ignore_ascii_case(name)) | ||
| .map(|h| h.value.clone()) | ||
| } | ||
|
|
||
| // Implement on-request interface | ||
| impl OnRequestGuest for Middleware { | ||
| fn on_request(req: Request) -> Action { | ||
| // API Key Authentication | ||
| // Check for API key in Authorization header for /api routes | ||
| if req.path.starts_with("/api") || req.path.starts_with("/v1") { | ||
| let api_key = find_header_value(&req.headers, "authorization") | ||
| .and_then(|h| { | ||
| h.strip_prefix("Bearer ") | ||
| .or_else(|| h.strip_prefix("ApiKey ")) | ||
| .map(|s| s.to_string()) | ||
| }) | ||
| .or_else(|| find_header_value(&req.headers, "x-api-key")); | ||
|
|
||
| // Reject if API key is missing or invalid | ||
| if api_key.as_deref() != Some(EXPECTED_API_KEY) { | ||
| return Action::Reject(401); | ||
| } | ||
| } | ||
|
|
||
| // Authentication passed, continue processing | ||
| Action::Continue | ||
| } | ||
| } | ||
|
|
||
| // Implement on-response interface (empty - not used for auth) | ||
| impl OnResponseGuest for Middleware { | ||
| fn on_response(_resp: Response) -> Action { | ||
| Action::Continue | ||
| } | ||
| } | ||
|
|
||
| // Export the component | ||
| export!(Middleware); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [package] | ||
| name = "wasm-guest-logging" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
|
|
||
| [lib] | ||
| crate-type = ["cdylib"] | ||
|
|
||
| [dependencies] | ||
| wit-bindgen = { version = "0.21", features = ["macros"] } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.