Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tilsor/ModSecIntl_wace_lib/llms.txt

Use this file to discover all available pages before exploring further.

WACElib supports three execution modes for model plugins, each with different latency, network, and reliability characteristics. Choosing the right mode depends on whether your model runs in-process alongside WACElib, whether it runs as a remote service reachable over NATS, and whether its result needs to influence the blocking decision for the current request. All three modes are configured per plugin in your YAML configuration and are loaded at startup by Init.

How modes are selected

When Init loads a plugin, it reads two fields from each entry in modelplugins:
  • mode — either "sync" or "async"
  • remotetrue or false (default false)
The combination determines the execution path taken in callPlugins:
moderemoteExecution path
syncfalseplugins.Process() called directly in a goroutine
synctruePayload published to NATS; result awaited on channel
asyncfalsePayload published to NATS; result not awaited
asynctruePayload published to NATS; result not awaited

The three modes

Sync local (mode: sync, remote: false) is the default in-process execution path. When callPlugins encounters a sync, non-remote plugin, it calls plugins.Process(modelID, transactionID, payload, pluginType, modelPluginStatus) in a goroutine. Process calls the plugin’s exported Process(ModelInput) (ModelResults, error) function directly, stores the result in the transaction’s results map, and sends a ModelStatus onto the channel. CheckTransaction waits for this status before calling the decision plugin.This mode has the lowest latency because there is no serialization or network hop — the model executes in the same process as WACElib.Plugin initialization: sync local plugins export InitPlugin(map[string]string, metric.Meter) error and Process(ModelInput) (ModelResults, error).
modelplugins:
  - id: "requestHeadersClassifier"
    plugintype: RequestHeaders
    path: "/opt/wace/plugins/classifier.so"
    weight: 0.8
    mode: sync
    # remote defaults to false — no NATS required
    params:
      threshold: "0.5"
When to use: Your ML model is a compiled Go plugin (.so) that can run inside the WACElib process, and you need the result to influence the current request’s block decision with minimal latency.

NATS connection setup

Both sync remote and async modes require a running NATS server. WACElib’s PluginManager establishes a single connection at startup using the NatsURL field from ConfigStore, which defaults to "localhost:4222" if omitted from the configuration file.
# In your WACE configuration file
natsurl: "nats://nats-server.internal:4222"
The NATS subject conventions are:
  • Inbound (WACElib → model): subject is the model id field (e.g., deepInspect)
  • Outbound (model → WACElib): subject is <modelID>/results (e.g., deepInspect/results)
Each remote or async plugin gets a dedicated ModelResultsHandler goroutine subscribed to its <modelID>/results subject. This goroutine runs for the lifetime of the process.

Plugin function signatures

WACElib uses Go’s plugin package to load .so files. The exported symbols it looks up depend on the mode:
// Sync local plugins must export both of these:
func InitPlugin(params map[string]string, meter metric.Meter) error
func Process(input ModelInput) (ModelResults, error)

// Sync remote and async plugins must export this instead of InitPlugin:
func InitPluginAsync(
    params map[string]string,
    meter metric.Meter,
    register func(func(ModelInput) (ModelResults, error)),
) error
The register callback passed to InitPluginAsync connects the plugin’s process function to ModelProcessHandler, which subscribes to the NATS subject and handles inbound payloads.
Start with sync local plugins during development — they have the simplest deployment story and the fastest feedback loop. Migrate to sync remote when your model outgrows the WACElib process (e.g., requires a GPU or a different runtime), and use async when you want observability data without any impact on request latency.
If the NATS server is unavailable when Init is called, PluginManager.New logs an error but continues loading plugins. However, any sync remote or async plugin will fail silently at runtime when AddToQueue attempts to publish — CheckTransaction will time out waiting on the sync channel for remote plugins. Ensure your NATS server is healthy before starting WACElib in production.

Build docs developers (and LLMs) love