WHERE clause is missing. 500,000 rows change. The statement was valid, the credentials were valid, the permissions were valid — nothing in the database’s own model of correctness had an objection.
Guardrails are the objection. Every statement is decoded and evaluated before it reaches the resource, and a rule that matches refuses it with a message you wrote.
Free tier: one Data Masking rule and one Guardrail per Sidecar are free, forever. Running more than one rule per feature, or managing rules centrally across Sidecars, requires Enterprise.
How a rule set resolves
Three sentences cover the entire semantics:- A rule matches, and by default it denies.
- First match wins among the rules that deny.
- A rule set is an ordered deny list. No match means allowed.
config.yaml
name, message and action in addition to its own fields.
guardrails is Hoop’s own rule engine, evaluated in-process. It was previously spelled policy, which still loads and warns at startup — see Migrating from policy. The separate opa section configures the optional external endpoint a defer hands to.Rule types
operation — deny by effect
operation — deny by effect
operation reads the statement’s worst effect, not its leading verb. A delete hidden in a CTE — WITH d AS (DELETE FROM customers RETURNING *) SELECT count(*) FROM d — reports delete and this rule catches it. EXPLAIN DELETE … reports explain; EXPLAIN ANALYZE DELETE … reports delete, because it runs.Vocabulary: select insert update delete merge create drop alter truncate grant revoke call copy explain show set begin commit rollback, plus other (parsed but unclassified) and unknown (the scanner could not finish). HTTP verbs are their own values: get post put patch head options connect trace.table — deny by relation
table — deny by relation
access is read or write. Add require_table_match: true to also deny when the relations could not be determined — the fail-closed posture for anything genuinely off limits.deny_words_list — deny by substring
deny_words_list — deny by substring
pattern_match — deny by regex
pattern_match — deny by regex
pii — deny sensitive values in the request
pii — deny sensitive values in the request
pii.entities list narrows the set. Once that list exists it is exhaustive, and a rule naming an entity absent from it is refused at startup — otherwise the guardrail would look live while allowing through everything it was written to stop.http_resource and http_status
http_resource and http_status
http_status is response-side, which is why an authorization filter running before the upstream can never ask it.ai_analysis — deny by classified risk
ai_analysis — deny by classified risk
action field, and setting action on it is refused at startup.Actions
action on a regular rule is either empty or defer. That is the whole list.
defer with no opa.url configured is refused at startup — a finding nobody reads forwards every statement while looking like enforcement.
action: warn and require_review are refused at startup. warn exists only as a per-tier action on ai_analysis rules. Human review needs a review backend the current build does not ship — see Agentic Access. For everything else, defer is how a rule stops short of deciding.Inheritance: guardrail rules concatenate
A listener’s rules are evaluated first, then the top-level defaults:config.yaml
opa replaces rather than merges, and mask replaces too.
Roll out without breaking anything
1
Validate the config
Nothing binds and nothing is denied. Startup refusals — a bad regex, a rule naming an entity outside
pii.entities, a defer with no opa.url — surface here rather than in front of users.2
Run the rule set on a staging lane first
Point a listener carrying the new rules at a staging copy of the upstream and send real query shapes through it. This is what replaces an observe-only flag: the rules are live, but on a lane whose denials cost nothing.
3
Read what got denied
violation names the rule that fired and the message the client read, so an over-broad rule is visible by name before it reaches production.4
Defer anything you are not ready to decide
A rule with
action: defer records a finding and hands the call to OPA instead of denying on its own. Rego that returns allow while you watch the findings gives you the same visibility on the production lane.5
Move production traffic to the lane
Nothing changes in the rule set.
/config reports the resolved rules per listener, which is what to compare against the file when a rule you wrote never fires.Looking for guardrails on the Hoop Gateway instead? That is a different implementation — Python regex patterns configured in the web app, with Block, Warn and Require Approval actions. See Guardrails.
Next
Guardrail Rules Reference
Every field of every rule type, deferring to Rego, and the full findings vocabulary.
Data Masking
Control what comes back, not just what goes in.