Skip to content

feat(nemo-guardrails): add NeMo Guardrails plugin 0.1.0 for Relay 0.11 - #17

Open
tgasser-nv wants to merge 3 commits into
NVIDIA:mainfrom
tgasser-nv:feat/nemo-guardrails-plugin
Open

tgasser-nv wants to merge 3 commits into
NVIDIA:mainfrom
tgasser-nv:feat/nemo-guardrails-plugin

Conversation

@tgasser-nv

@tgasser-nv tgasser-nv commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Add the NeMo Guardrails plugin 0.1.0, a native Relay plugin that checks each tool call with a NeMo Guardrails service before the call runs. The service holds the rails and decides each call: Relay runs an allowed call, blocks a denied call with the service's reason, and reports an error when the check fails.

Register nemo-guardrails-plugin as a remote source for the crates/nemo-guardrails-relay-plugin crate. Track NeMo Guardrails' develop branch and pin commit 537fd774298260261bc4ee15e78d861b9e5814e5, which includes the plugin's CI (NVIDIA-NeMo/Guardrails#2536) and its move to the Relay 0.11 SDK (NVIDIA-NeMo/Guardrails#2538). The plugin sets runtime compatibility to >=0.11.0-rc.1, <1.0; select the published Relay 0.11.0 CLI for tests. Packaging uses the upstream bundle script, which copies the NeMo Guardrails license files, then adds Rust dependency attributions and third-party notices.

The smoke test installs the bundle once, with a local server standing in for the NeMo Guardrails service. It sends Claude Code PreToolUse hooks through nemo-relay hook-forward claude for three results: a denied call, an allowed call, and a failed check (HTTP 500 rail_failed). Each call must reach the server exactly once and return the expected exit code and message.

Extend the shared smoke harness for hook tests, without plugin-specific behavior:

installed_relay_gateway yields the gateway URL with a Relay command runner that shares the gateway's settings, environment, and credentials. Relay 0.11 hook clients need the gateway's client credential and TLS tunnel. installed_gateway wraps the new helper, so Switchyard's smoke test is unchanged.
json_http_fixture accepts a status, and callers can change its response between requests.
Wait until the gateway answers HTTP, not only until it accepts a TCP connection. Relay binds its port before it activates plugins, and hook clients treat a gateway that takes over 500 ms to answer /healthz as an unrelated service.
Update the plugin catalog, documentation, notices, and target counts, and regenerate the Rust attributions. The attributions add 99 entries and leave existing entries unchanged. Git's default diff misaligns repeated license texts; git diff --histogram main -- ATTRIBUTIONS-Rust.md shows 14,730 added lines and no removed lines.

Test Plan

NOTE: The current PR builds the v0.25.0 tag from the NeMo Guardrails repo. For this reason, CI will be red until the new Guardrails release is tagged. The results below were from a specific SHA on the develop branch.

Validate plugins

$ uv run python -m scripts.plugins validate

{
  "valid": [
    "example-python-grpc-worker-plugin",
    "example-rust-grpc-worker-plugin",
    "example-rust-native-plugin",
    "nemo-guardrails-plugin",
    "switchyard-plugin"
  ]
}

Unit-tests

GIT_CONFIG_GLOBAL=/dev/null uv run --group test pytest
============================= test session starts ==============================
platform darwin -- Python 3.11.15, pytest-9.1.1, pluggy-1.6.0
rootdir: /Users/tgasser/projects/NeMo-Relay-Plugins
configfile: pyproject.toml
testpaths: tests
collected 227 items

tests/test_attributions.py ............................                  [ 12%]
tests/test_bundles.py ................                                   [ 19%]
tests/test_catalog.py ...............................                    [ 33%]
tests/test_checks.py ..................                                  [ 40%]
tests/test_dependency_inventory.py ......                                [ 43%]
tests/test_host.py ........................                              [ 54%]
tests/test_license_diff.py .......                                       [ 57%]
tests/test_package_sources.py ......................                     [ 66%]
tests/test_plugin_commands.py ..................                         [ 74%]
tests/test_python_local_attributions.py ....................             [ 83%]
tests/test_releases.py ............                                      [ 88%]
tests/test_smoke.py ............s                                        [ 94%]
tests/test_tasks.py .........                                            [ 98%]
tests/test_workflows.py ...                                              [100%]

======================= 226 passed, 1 skipped in 22.54s ========================

Plugin build test (MacOS laptop)

$ HEAD is now at 537fd77 ci: revert Swatinem/rust-cache to allow-listed v2.9.2 (#2582)
nemo-relay 0.11.0
   Compiling nemo-guardrails-relay-plugin v0.1.0 (/Users/tgasser/projects/NeMo-Relay-Plugins/.cache/runs/nemo-guardrails-plugin/macos-arm64/source/crates/nemo-guardrails-relay-plugin)
    Finished `release` profile [optimized] target(s) in 0.98s
   Compiling nemo-guardrails-relay-plugin v0.1.0 (/Users/tgasser/projects/NeMo-Relay-Plugins/.cache/runs/nemo-guardrails-plugin/macos-arm64/source/crates/nemo-guardrails-relay-plugin)
    Finished `release` profile [optimized] target(s) in 1m 02s
     Running unittests src/lib.rs (/Users/tgasser/projects/NeMo-Relay-Plugins/.cache/targets/nemo-guardrails-plugin/macos-arm64/aarch64-apple-darwin/release/deps/nemo_guardrails_relay_plugin-56c73de69984cacb)

running 12 tests
.....
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/client.rs (/Users/tgasser/projects/NeMo-Relay-Plugins/.cache/targets/nemo-guardrails-plugin/macos-arm64/aarch64-apple-darwin/release/deps/client-1ee25ffcabb4c5ea)

running 15 tests
.....
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s

     Running tests/lifecycle.rs (/Users/tgasser/projects/NeMo-Relay-Plugins/.cache/targets/nemo-guardrails-plugin/macos-arm64/aarch64-apple-darwin/release/deps/lifecycle-bf5af42ea80f107b)

running 8 tests
.....
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.28s

     Running tests/tool_call_check.rs (/Users/tgasser/projects/NeMo-Relay-Plugins/.cache/targets/nemo-guardrails-plugin/macos-arm64/aarch64-apple-darwin/release/deps/tool_call_check-1501fc711b4d2ec0)

running 5 tests
.....
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.91s

   Doc-tests nemo_guardrails_relay_plugin
running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

@tgasser-nv tgasser-nv self-assigned this Nov 9, 2026
…11 upgrade; format smoke test

Signed-off-by: tgasser-nv <200644301+tgasser-nv@users.noreply.github.com>
@tgasser-nv
tgasser-nv marked this pull request as ready for review November 9, 2026 21:18
@tgasser-nv
tgasser-nv requested a review from a team November 9, 2026 21:18
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.

1 participant