Skip to content

feat(guardrail): apply to request by policy#112

Merged
bzp2010 merged 3 commits into
mainfrom
bzp/feat-guardrail-applyby-policy
May 19, 2026
Merged

feat(guardrail): apply to request by policy#112
bzp2010 merged 3 commits into
mainfrom
bzp/feat-guardrail-applyby-policy

Conversation

@bzp2010
Copy link
Copy Markdown
Collaborator

@bzp2010 bzp2010 commented May 18, 2026

Summary by CodeRabbit

  • Breaking Changes

    • Models no longer accept a guardrail_ids property; model-level guardrail assignments are rejected (400).
  • New Features

    • Guardrails are resolved per-request via CEL-based policies, allowing dynamic input/output guardrail selection based on route, auth, and request content.
  • Tests

    • New/updated tests verify rejection of legacy model-level guardrail fields and validate policy-driven guardrail behavior.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c48b4bcf-f08d-41a7-af00-2cb5ceb5df85

📥 Commits

Reviewing files that changed from the base of the PR and between 9f0df8a and e18522e.

📒 Files selected for processing (1)
  • tests/package.json
✅ Files skipped from review due to trivial changes (1)
  • tests/package.json

📝 Walkthrough

Walkthrough

This PR removes model-level guardrail_ids and replaces them with request-level CEL policies that produce stage-bound ResolvedGuardrail instances; it refactors guardrail runtimes, evaluates policies per request, threads resolved guardrails through format handling and streaming, and updates schema/tests/fixtures.

Changes

Guardrail resolution migration from model-based to policy-driven

Layer / File(s) Summary
Remove model-based guardrail configuration
src/config/entities/models-schema.json, src/config/entities/models.rs, tests/admin/models.test.ts
guardrail_ids removed from model JSON schema and Model struct; schema now rejects guardrail_ids and tests updated/added to assert rejection and legacy ignore-on-deserialize behavior.
Add request route context for policy evaluation
src/proxy/hooks/context.rs, src/proxy/hooks/mod.rs
Add RequestRouteInfo (method/path), insert into request http::Extensions during RequestContext init, and re-export for use by policy evaluation.
Refactor guardrail runtime to stage-aware abstraction
src/proxy/guardrails.rs
Replace ConfiguredGuardrailRuntime with ResolvedGuardrail bound to a GuardrailStage; add RuntimeResolvedGuardrail wrapper and build_resolved_guardrail_for_stage; remove model-level resolution entrypoint and update tests.
Implement policy-driven guardrail selection
src/proxy/policies.rs, src/proxy/mod.rs
Add policies module implementing CEL-based policy evaluation: build PolicyContext, evaluate compiled when programs, collect/sort matches, deduplicate bindings, fetch guardrail configs, and construct stage-specific ResolvedGuardrail instances.
Integrate request-level guardrail resolution in format handler
src/proxy/handlers/format_handler.rs
format_handler now serializes request for policy evaluation, calls resolve_request_guardrails, applies input/output guardrails via ResolvedGuardrail, threads resolved guardrails through streaming replay/unfold state, and requires Serialize on FormatHandlerAdapter::Request.
Update guardrail test fixtures to use policies
tests/proxy/guardrail/shared.ts, tests/package.json
Test fixtures stop sending guardrail_ids in model creation and instead create input/output policies via admin API to attach guardrails to models by name; test packageManager metadata updated.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • api7/aisix#104: Overlaps refactoring of guardrail runtime and model-to-runtime resolution.
  • api7/aisix#107: Related policy resource model and admin API used for request-level policy resolution.
  • api7/aisix#108: Related streaming / whole-response replay work that integrates with streaming guardrail application.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: shifting guardrail application from model-level to request-level policy-based evaluation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
E2e Test Quality Review ✅ Passed E2E tests adequately cover policy-based guardrail flows with multiple scenarios. Error handling properly implemented throughout code.
Security Check ✅ Passed Comprehensive security review of PR #112 (feat(guardrail): apply to request by policy) found no critical or high-severity security vulnerabilities across all 7 security categories.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bzp/feat-guardrail-applyby-policy

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/proxy/handlers/format_handler.rs (1)

345-348: 💤 Low value

Optional: Simplify error conversion.

The Ok(expr?) pattern is redundant here. Since A::Error: From<GatewayError>, the ? operator handles the conversion.

♻️ Suggested simplification
-    let input = input_payload_from_check_payload(payload).map_err(guardrail_bridge_error)?;
-    Ok(input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error)?)
+    let input = input_payload_from_check_payload(payload).map_err(guardrail_bridge_error)?;
+    input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error).map_err(Into::into)

Or, keeping the current style consistently:

-    Ok(input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error)?)
+    input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error).map_err(A::Error::from)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/proxy/handlers/format_handler.rs` around lines 345 - 348, The return uses
the redundant Ok(expr?) pattern: in format_handler.rs replace the final line
returning
Ok(input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error)?) with
a direct propagated result using the ? operator so that
input_payload_from_check_payload(...).map_err(guardrail_bridge_error)? is used
and then return
input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error)? (i.e.,
drop the outer Ok(...) and rely on ? to convert GatewayError into A::Error);
update the function that calls input_payload_from_check_payload and
input_payload_to_chat_messages and remove the unnecessary wrapping to keep error
handling consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/proxy/guardrails.rs`:
- Around line 257-273: Add the #[fastrace::trace] attribute directly above the
pub(crate) function build_resolved_guardrail_for_stage to enable distributed
tracing for this public request-path function; ensure the fastrace attribute
macro is available in scope (use the #[fastrace::trace] path as specified) and
place it immediately above the function signature so tracing covers the entire
function body.

In `@src/proxy/policies.rs`:
- Around line 20-27: The new public(crate) functions need distributed-tracing
annotations: add #[fastrace::trace] above the stable_route_format function and
likewise annotate any other public(crate) functions introduced in this file (the
ones between the stable_route_format declaration and the block covering lines
~29-137) so they are instrumented for fastrace-based request-path observability;
locate functions by name (e.g., stable_route_format and the other public(crate)
function names in src/proxy/policies.rs) and place the attribute directly above
each function signature.

---

Nitpick comments:
In `@src/proxy/handlers/format_handler.rs`:
- Around line 345-348: The return uses the redundant Ok(expr?) pattern: in
format_handler.rs replace the final line returning
Ok(input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error)?) with
a direct propagated result using the ? operator so that
input_payload_from_check_payload(...).map_err(guardrail_bridge_error)? is used
and then return
input_payload_to_chat_messages(&input).map_err(guardrail_bridge_error)? (i.e.,
drop the outer Ok(...) and rely on ? to convert GatewayError into A::Error);
update the function that calls input_payload_from_check_payload and
input_payload_to_chat_messages and remove the unnecessary wrapping to keep error
handling consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3c24ee1c-8a63-485f-a29d-99762ba72043

📥 Commits

Reviewing files that changed from the base of the PR and between bbcf85e and ad48f2f.

📒 Files selected for processing (10)
  • src/config/entities/models-schema.json
  • src/config/entities/models.rs
  • src/proxy/guardrails.rs
  • src/proxy/handlers/format_handler.rs
  • src/proxy/hooks/context.rs
  • src/proxy/hooks/mod.rs
  • src/proxy/mod.rs
  • src/proxy/policies.rs
  • tests/admin/models.test.ts
  • tests/proxy/guardrail/shared.ts
💤 Files with no reviewable changes (1)
  • src/config/entities/models-schema.json

Comment thread src/proxy/guardrails.rs
Comment thread src/proxy/policies.rs
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/proxy/policies.rs`:
- Around line 71-75: The PolicyRouteContext is being constructed with the raw
request.route_format which can vary by provider; call
stable_route_format(request.route_format) and assign that result to the
PolicyRouteContext.format so policies see a normalized, provider-agnostic key.
Update the construction of PolicyRouteContext (where route: PolicyRouteContext {
method: &route.method, path: &route.path, format: request.route_format, }) to
use stable_route_format(...) instead of the raw request.route_format so matching
uses the normalized format.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff3f4cde-a844-4aa2-94ad-3b55a8a3a579

📥 Commits

Reviewing files that changed from the base of the PR and between ad48f2f and 9f0df8a.

📒 Files selected for processing (2)
  • src/proxy/handlers/format_handler.rs
  • src/proxy/policies.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/proxy/handlers/format_handler.rs

Comment thread src/proxy/policies.rs
@bzp2010 bzp2010 merged commit 227938f into main May 19, 2026
3 checks passed
@bzp2010 bzp2010 deleted the bzp/feat-guardrail-applyby-policy branch May 19, 2026 02:03
@coderabbitai coderabbitai Bot mentioned this pull request May 19, 2026
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