extensibility

Put your own logic
in the request pipeline.

Use CEL for a condition, Lua or JavaScript for a header or body rewrite, and Rego for policies your team already maintains. Package reusable hooks as extension bundles. WASM supports compiled response transforms and bundles with a defined ABI.

configuration
Inline scripts live in sb.yml. Bundles have their own manifest, version, and resource limits.
CEL
HOT PATH
CEL expressions for policy decisions, routing conditions, response headers, and rate-limit keys.
Rego
POLICY
OPA-compatible Rego, evaluated in-process by the Regorus interpreter. No sidecar to run.
Lua
SCRIPT
Fresh Luau state for header modifiers, JSON body transforms, and WAF rules.
JavaScript
HANDLER
QuickJS for inline scripts; ES modules and load-time TypeScript for bundle hooks.
WebAssembly
SANDBOXED
Wasmtime for WASI response transforms, envelope bundles, and Proxy-Wasm HTTP filters.
01 / the five engines

Five engines.
Each solves a different problem.

Start with the hook you need. An expression policy returns a decision; a modifier returns headers; a transform returns a body. The scripting reference lists what each hook receives and what happens if it fails.

01cel

CEL expressions

Use CEL when the decision fits one expression. Compile-time syntax checks catch errors before a new config starts serving requests.

  • + Policy allow/deny, forward-rule conditions, and rate-limit keys
  • + Context bindings depend on the config field
  • + AI policy CEL has a separate ai.* namespace
Read the reference
02rego

Rego policies and modifiers

Regorus evaluates Rego inside the proxy. Reuse a policy module, supply base data separately, and test its decisions with sbproxy rego test.

  • + Inline modules or module_path files
  • + Policy rules return booleans and deny on runtime errors
  • + Rego bundle policy and transform hooks have their own input contracts
Read the reference
03lua

Lua header and body scripts

Each call gets a fresh sandboxed Luau interpreter. A modifier applies the returned set_headers map; lua_json transforms call modify_json on parsed JSON.

  • + json_encode and json_decode helpers
  • + Default 8 MB allocator cap and 100 ms interrupt
  • + Modifiers, transforms, WAF rules, and selected event hooks
Read the reference
04javascript

JavaScript and TypeScript

Inline JavaScript uses QuickJS with a fresh runtime per invocation. Bundle hooks use named ES module exports and can transpile TypeScript at load time.

  • + Inline defaults: 16 MB heap, 1 MB stack, 100 ms watchdog
  • + Raw-body transform(body, ctx) or JSON modify_json(data, ctx)
  • + Bundle outbound HTTP requires matching declarations and grants
Read the reference
05wasm

WASM transforms and bundles

The wasm response transform reads the buffered body from stdin and writes a replacement to stdout. Envelope bundles and Proxy-Wasm filters use different contracts.

  • + Compile once at config load; create a Store per invocation
  • + Memory, fuel, and wall-clock limits
  • + Opt-in request context for the response transform
Read the reference
02 / operating custom code
before deployment

Validate the config and test the script.

sbproxy validate compiles declared CEL expressions and checks typed configuration. Inline Lua and JavaScript syntax errors appear when those scripts run, so exercise their request paths before deployment.

Rego policy modules compile at config load; Rego modifiers compile per invocation. Bundle candidates validate source, exports, digests, and runtime contracts before publication.

  • + sbproxy validate sb.yml
  • + sbproxy rego test for offline policy cases
  • + Runnable examples for each scripting contract
  • + Cedar replay for recorded MCP decisions
during requests

Know what an error does.

A failed expression or Rego policy denies the request. A failed header modifier logs the error and proceeds without its headers. Transform behavior follows the configured failure posture.

Bundle action and authentication hooks fail closed. Other supported hook kinds use their resolved failure posture. The scripting reference lists these outcomes by surface.

  • + Per-engine invocation and duration metrics
  • + Script compile failures in metrics and logs
  • + Bundle inventory at GET /api/extensions
  • + Candidate failures retain the active generation
03 / extension code

Runnable examples.
One per engine.

These configurations come from the runnable examples in the repository. Each tab names the hook contract. Keep request modifiers separate from body transforms when you adapt them to your own origin.

examples/cel-policy/sb.yml
yaml
# yaml-language-server: $schema=../../schemas/sb-config.schema.json
# CEL expression policy.
#
# Allows requests only when the `X-Tenant` header equals `acme`. CEL header
# keys are normalized to lowercase with hyphens preserved,
# so `X-Tenant` is read as `request.headers["x-tenant"]`. Anything else
# gets a 403 before test.sbproxy.dev is contacted. This is the path to take for
# custom access control beyond simple IP or key checks.
#
# Run:
#   make run CONFIG=examples/cel-policy/sb.yml
#
# Test:
#   # 403 - missing or wrong tenant header
#   curl -i -H 'Host: cel.local' http://127.0.0.1:8080/get
#   curl -i -H 'Host: cel.local' -H 'X-Tenant: other' http://127.0.0.1:8080/get
#
#   # 200 - matches the allowed tenant
#   curl -i -H 'Host: cel.local' -H 'X-Tenant: acme' http://127.0.0.1:8080/get

proxy:
  http_bind_port: 8080

origins:
  "cel.local":
    action:
      type: proxy
      url: https://test.sbproxy.dev

    policies:
      - type: expression
        expression: 'request.headers["x-tenant"] == "acme"'
        deny_status: 403
        deny_message: "tenant not allowed"
policyThe expression policy returns a boolean. Header names stay lowercase and retain hyphens.

Inline Lua and JavaScript start a fresh interpreter on each invocation. For code that needs an outbound request, use a JavaScript bundle hook with a declared destination and a matching operator grant.

04 / extension bundles

Package a hook.
Validate the whole bundle.

A bundle directory contains bundle.yaml and an entry file. JavaScript, TypeScript, Rego, envelope WASM, and Proxy-Wasm each support specific hook kinds. The manifest declares those hooks and their limits; SBproxy checks a complete candidate before making it active.

  • Load local bundle directories or fetch a verified Git source.
  • Cover the manifest and entry with a bundle_v1 digest.
  • Grant each JavaScript outbound destination the hook declares.
  • Check the complete candidate and keep the prior generation on failure.

Git sources require a content digest and a full commit SHA, or a reference whose tag or commit Git can verify. Set digest_scope: bundle_v1 to cover the manifest and entry together. The extension bundle guide documents the exact digest calculation and reload behavior.

05 / documentation

The contract for
the code you write.

The guides below cover configuration, examples, failure behavior, and debugging. Cedar has a separate MCP authorization guide because it evaluates tool calls rather than general HTTP scripting hooks.

  • Choose inline scripting, a dynamic bundle, or a linked Rust plugin.
  • Hook context, CEL and Rego expressions, Lua and JavaScript contracts, limits, and errors.
  • Manifest fields, bundle digests, capability grants, event hooks, and reload operations.
  • Rust and TinyGo examples, WASI streams, request context, fuel, and memory.
  • MCP tool-call decisions, RBAC interaction, confirmation approvals, and replay. Read the guide for the current identity and context limits.

The site builds these reference pages from the core repository documentation. The examples link to the configuration and entry files you can run.

in the engine

What's shipping in the runtime.

Limits differ by runtime and hook. Use the reference for the surface you configure.

  • 01
    CELExpressions compile at configuration load. Available bindings vary by policy, matcher, modifier, or log field.
  • 02
    RegoRegorus evaluates policy modules in process. Runtime policy faults and budget overruns deny with the configured status.
  • 03
    LuaLuau via mlua. Every invocation starts a fresh interpreter with allocator and wall-clock limits.
  • 04
    JavaScriptQuickJS via rquickjs. Inline scripts and bundle hooks have separate limits and entrypoint contracts.
  • 05
    WASMWasmtime with memory, fuel, and epoch limits. Response transforms, envelope bundles, and Proxy-Wasm use separate ABIs.
  • 06
    Bundle publicationSBproxy validates the candidate registry before swapping generations. A rejected candidate leaves the previous registry active.
who it's for
You, if
  • A header rewrite needs a condition or a JSON body needs a computed field.
  • Your team maintains Rego policies and wants to test them before deploying.
  • You need to version and distribute an action, policy, auth hook, or transform independently.
  • You want a compiled response transform with a documented WASI contract.
Common uses
Tenant gatesHeader rewritesJSON transformsBundle authenticationHTTP filtersAI event hooks
06 / talk to us

Want to talk
before you install?

The gateway is on GitHub under Apache 2.0 and you can install it right now, so nothing here is gated behind a sales call. Use this form for deployment questions, migration scoping, or anything you would rather not file as a public issue.

01
Share your stack. A few details on providers, scale, and the gateway you might be replacing.
02
Talk to engineering. A real conversation about whether SBproxy fits the deployment shape you have in mind. No demo theatre.
03
Get a straight answer. Including when the answer is that SBproxy is the wrong fit and you should run something else.