Skip to Content
ConceptsYAML Policy Engine

YAML Policy Engine

Govrix Scout includes a declarative policy engine that evaluates YAML rules against every request and response that flows through the proxy. Rules combine field conditions using boolean operators and trigger one of three actions: block, tag, or log.

Rule structure

A policy rule has three parts:

rules: - name: <human-readable rule name> conditions: - field: <field> operator: <operator> value: <value> # additional conditions are ANDed together action: <action> message: "<optional message for block responses>"

All conditions within a single rule are evaluated with logical AND — every condition must match for the action to fire. To express OR logic, write multiple rules.

Fields

FieldTypeDescription
agent_idstringThe agent identifier from the X-Agent-ID header
modelstringThe model name requested (e.g. gpt-4o, claude-3-5-sonnet-20241022)
token_countintegerTotal tokens in the request + response
cost_usdfloatEstimated cost of the request in USD
pii_detectedbooleanWhether the PII scanner found any PII in the payload

Operators

OperatorApplies toDescription
eqstring, boolean, integer, floatEquals
neqstring, boolean, integer, floatNot equals
gtinteger, floatGreater than
ltinteger, floatLess than
containsstringString contains substring (case-sensitive)
regexstringFull regex match against the field value

Actions

ActionHTTP effectDescription
blockRequest rejected with HTTP 403 before forwardingStops the request; returns the rule’s message field in the response body
tagRequest forwarded normallyAdds a tag to the event record; visible in the audit log
logRequest forwarded normallyEmits a structured log line at WARN level; no effect on the event

block is evaluated before the request is forwarded to the upstream LLM. tag and log are evaluated on the response path. A block action consumes zero LLM tokens.

Implementation

FileRole
crates/govrix-policy/src/engine.rsRule evaluator — 6 operators, 5 fields, 3 actions, 16 unit tests

Full example policy

policy: rules: # Block any request that contains PII - name: block-pii conditions: - field: pii_detected operator: eq value: true action: block message: "Request blocked: PII detected in payload." # Block expensive models for agents that aren't whitelisted - name: block-gpt4-for-standard-agents conditions: - field: model operator: contains value: "gpt-4" - field: agent_id operator: neq value: "premium-agent" action: block message: "GPT-4 class models are restricted to premium agents." # Tag any request that uses more than 50k tokens - name: tag-high-token-usage conditions: - field: token_count operator: gt value: 50000 action: tag message: "high-token-usage" # Block any single request that would cost more than $1 - name: block-expensive-requests conditions: - field: cost_usd operator: gt value: 1.00 action: block message: "Single request cost exceeds $1.00 limit." # Log any agent whose name matches an internal pattern - name: log-internal-agents conditions: - field: agent_id operator: regex value: "^internal-.*" action: log

Applying policy configuration

Policy rules live in govrix.toml under the [policy] key:

[policy] rules = [ { name = "block-pii", conditions = [{ field = "pii_detected", operator = "eq", value = true }], action = "block", message = "PII detected." } ]

Alternatively, point to an external YAML file:

[policy] rules_file = "/etc/govrix/policy.yaml"

Inline rules in govrix.toml use TOML array-of-table syntax. They are loaded once at startup. To reload, restart the proxy.

[[policy.rules]] name = "block-pii" action = "block" message = "PII detected in payload." [[policy.rules.conditions]] field = "pii_detected" operator = "eq" value = true

Execution order

Rules are evaluated in the order they are defined. The first matching block rule short-circuits evaluation — subsequent rules are not checked. For tag and log rules, all matching rules are executed (no short-circuit).

Put block rules before tag and log rules that cover the same conditions. If a log rule fires first, the event is logged before the block rule gets a chance to prevent the upstream call.

Actually: block rules run on the request path (pre-upstream); tag and log rules run on the response path (post-upstream). So a block rule always fires before any tag/log rule for the same request — ordering only matters within the same action type.

Last updated on