> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.hoop.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Guardrails Configuration

> Create and manage pattern-based rules to block dangerous queries

export const KillCommandDemo = () => {
  const COMMANDS = [{
    cmd: "SELECT count(*) FROM orders;",
    blocked: false,
    rule: null,
    type: "SELECT"
  }, {
    cmd: "kubectl get pods -n payments",
    blocked: false,
    rule: null,
    type: "READ"
  }, {
    cmd: "DROP TABLE customers;",
    blocked: true,
    rule: "Destructive DDL blocked",
    type: "DROP"
  }, {
    cmd: "DELETE FROM users WHERE 1=1;",
    blocked: true,
    rule: "Missing WHERE clause",
    type: "DELETE"
  }, {
    cmd: "rm -rf /var/data/prod",
    blocked: true,
    rule: "Destructive exec blocked",
    type: "EXEC"
  }];
  const animationStyles = `
    @keyframes slideIn {
      from { opacity: 0; transform: translateX(-40px); }
      to { opacity: 1; transform: translateX(0); }
    }
    @keyframes pulseShield {
      0%, 100% { transform: scale(1); filter: drop-shadow(0 0 0px rgba(var(--bronze-rgb),0)); }
      50% { transform: scale(1.08); filter: drop-shadow(0 0 12px rgba(var(--bronze-rgb),0.4)); }
    }
    @keyframes pulseShieldBlock {
      0% { transform: scale(1); filter: drop-shadow(0 0 0px rgba(180,60,60,0)); }
      30% { transform: scale(1.15); filter: drop-shadow(0 0 16px rgba(180,60,60,0.5)); }
      100% { transform: scale(1); filter: drop-shadow(0 0 0px rgba(180,60,60,0)); }
    }
    @keyframes resultSlide {
      from { opacity: 0; transform: translateY(8px); }
      to { opacity: 1; transform: translateY(0); }
    }
    @keyframes fadeInUp {
      from { opacity: 0; transform: translateY(12px); }
      to { opacity: 1; transform: translateY(0); }
    }
    @keyframes scanLine {
      0% { top: 0%; opacity: 0; }
      10% { opacity: 1; }
      90% { opacity: 1; }
      100% { top: 100%; opacity: 0; }
    }
  `;
  const ShieldIcon = ({state, size = 56}) => {
    const color = state === "block" ? "#B43C3C" : state === "pass" ? "#4A7C59" : "var(--bronze)";
    const anim = state === "block" ? "pulseShieldBlock 0.5s ease-out" : state === "pass" ? "pulseShield 0.6s ease-out" : "none";
    return <svg width={size} height={size} viewBox="0 0 48 48" style={{
      animation: anim
    }}>
        <path d="M24 4L6 12v12c0 11.1 7.7 21.5 18 24 10.3-2.5 18-12.9 18-24V12L24 4z" fill="none" stroke={color} strokeWidth="2.5" strokeLinejoin="round" />
        <path d="M24 8L10 14.5v9.5c0 9.2 6.4 17.8 14 20 7.6-2.2 14-10.8 14-20v-9.5L24 8z" fill={color} fillOpacity="0.08" />
        {state === "block" && <g stroke="#B43C3C" strokeWidth="3" strokeLinecap="round">
            <line x1="18" y1="18" x2="30" y2="30" />
            <line x1="30" y1="18" x2="18" y2="30" />
          </g>}
        {state === "pass" && <polyline points="16,24 22,30 32,18" fill="none" stroke="#4A7C59" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />}
        {state === "idle" && <g>
            <rect x="19" y="15" width="10" height="3" rx="1.5" fill="var(--bronze)" fillOpacity="0.5" />
            <rect x="17" y="21" width="14" height="3" rx="1.5" fill="var(--bronze)" fillOpacity="0.35" />
            <rect x="19" y="27" width="10" height="3" rx="1.5" fill="var(--bronze)" fillOpacity="0.2" />
          </g>}
      </svg>;
  };
  const CommandTag = ({type}) => {
    const colors = {
      SELECT: {
        bg: "rgba(var(--bronze-rgb),0.08)",
        text: "var(--bronze)"
      },
      READ: {
        bg: "rgba(var(--bronze-rgb),0.08)",
        text: "var(--bronze)"
      },
      DELETE: {
        bg: "rgba(180,60,60,0.08)",
        text: "#B43C3C"
      },
      DROP: {
        bg: "rgba(180,60,60,0.08)",
        text: "#B43C3C"
      },
      EXEC: {
        bg: "rgba(180,60,60,0.08)",
        text: "#B43C3C"
      }
    };
    const c = colors[type] || colors.SELECT;
    return <span style={{
      fontFamily: "'JetBrains Mono', monospace",
      fontSize: 10,
      fontWeight: 500,
      color: c.text,
      background: c.bg,
      padding: "2px 8px",
      borderRadius: 4,
      letterSpacing: "0.04em",
      textTransform: "uppercase",
      whiteSpace: "nowrap"
    }}>{type}</span>;
  };
  const [activeIndex, setActiveIndex] = useState(-1);
  const [phase, setPhase] = useState("idle");
  const [results, setResults] = useState([]);
  const [stats, setStats] = useState({
    blocked: 0,
    allowed: 0
  });
  const timerRef = useRef(null);
  const indexRef = useRef(0);
  const processNext = useCallback(() => {
    const idx = indexRef.current % COMMANDS.length;
    const q = COMMANDS[idx];
    indexRef.current += 1;
    setActiveIndex(idx);
    setPhase("scanning");
    timerRef.current = setTimeout(() => {
      setPhase("result");
      setResults(prev => {
        const next = [{
          ...q,
          ts: Date.now()
        }, ...prev];
        return next.slice(0, 6);
      });
      setStats(prev => ({
        blocked: prev.blocked + (q.blocked ? 1 : 0),
        allowed: prev.allowed + (q.blocked ? 0 : 1)
      }));
      timerRef.current = setTimeout(() => {
        setPhase("idle");
        timerRef.current = setTimeout(() => {
          processNext();
        }, 600);
      }, 1400);
    }, 900);
  }, []);
  useEffect(() => {
    timerRef.current = setTimeout(() => processNext(), 800);
    return () => clearTimeout(timerRef.current);
  }, []);
  const currentCommand = activeIndex >= 0 ? COMMANDS[activeIndex] : null;
  const shieldState = phase === "result" && currentCommand ? currentCommand.blocked ? "block" : "pass" : phase === "scanning" ? "idle" : "idle";
  return <div style={{
    fontFamily: "'Inter', system-ui, sans-serif",
    borderRadius: 12,
    padding: "20px 24px 16px",
    position: "relative",
    overflow: "hidden",
    width: "100%",
    color: "var(--sand-100)"
  }}>
      <style>{animationStyles}</style>

      {}
      <div style={{
    position: "absolute",
    top: "-30%",
    right: "-10%",
    width: "60%",
    height: "160%",
    background: "radial-gradient(ellipse at center, rgba(var(--warm-gold-rgb),0.12) 0%, transparent 70%)",
    pointerEvents: "none"
  }} />

      {}
      <div style={{
    display: "grid",
    gridTemplateColumns: "1fr auto 1fr",
    gap: 24,
    alignItems: "start",
    position: "relative",
    height: 320
  }}>
        {}
        <div style={{
    background: "rgba(var(--sand-100-rgb),0.04)",
    border: "1px solid rgba(var(--sand-100-rgb),0.08)",
    borderRadius: 10,
    padding: 20,
    height: 300,
    overflow: "hidden"
  }}>
          <div style={{
    fontSize: 10,
    fontWeight: 600,
    color: "rgba(var(--sand-100-rgb),0.25)",
    textTransform: "uppercase",
    letterSpacing: "0.08em",
    marginBottom: 14
  }}>Incoming Command</div>

          {currentCommand && phase !== "idle" ? <div key={indexRef.current} style={{
    animation: "slideIn 0.35s ease-out"
  }}>
              <div style={{
    display: "flex",
    alignItems: "center",
    gap: 8,
    marginBottom: 10
  }}>
                <CommandTag type={currentCommand.type} />
                <span style={{
    fontSize: 11,
    color: "rgba(var(--sand-100-rgb),0.3)"
  }}>
                  via CLI
                </span>
              </div>
              <div style={{
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: 13,
    lineHeight: 1.7,
    color: "var(--sand-300)",
    background: "rgba(var(--sand-100-rgb),0.03)",
    padding: "14px 16px",
    borderRadius: 8,
    border: "1px solid rgba(var(--sand-100-rgb),0.06)",
    wordBreak: "break-all",
    position: "relative",
    overflow: "hidden"
  }}>
                {currentCommand.cmd}
                {phase === "scanning" && <div style={{
    position: "absolute",
    left: 0,
    width: "100%",
    height: 2,
    background: "linear-gradient(90deg, transparent, var(--warm-gold), transparent)",
    animation: "scanLine 0.8s ease-in-out"
  }} />}
              </div>

              {phase === "scanning" && <div style={{
    marginTop: 14,
    fontSize: 12,
    color: "var(--warm-gold)",
    display: "flex",
    alignItems: "center",
    gap: 6,
    animation: "fadeInUp 0.3s ease-out"
  }}>
                  <span style={{
    width: 6,
    height: 6,
    borderRadius: "50%",
    background: "var(--warm-gold)",
    display: "inline-block",
    animation: "pulseShield 1s ease-in-out infinite"
  }} />
                  Evaluating rules...
                </div>}

              {phase === "result" && <div style={{
    marginTop: 14,
    animation: "fadeInUp 0.3s ease-out",
    display: "flex",
    alignItems: "center",
    gap: 8
  }}>
                  <span style={{
    width: 8,
    height: 8,
    borderRadius: "50%",
    background: currentCommand.blocked ? "#B43C3C" : "#4A7C59",
    display: "inline-block"
  }} />
                  <span style={{
    fontSize: 12,
    fontWeight: 500,
    color: currentCommand.blocked ? "#D4726A" : "#7CB88A"
  }}>
                    {currentCommand.blocked ? "Blocked" : "Allowed"}
                  </span>
                  {currentCommand.rule && <span style={{
    fontSize: 11,
    color: "rgba(var(--sand-100-rgb),0.3)"
  }}>
                      {currentCommand.rule}
                    </span>}
                </div>}
            </div> : <div style={{
    color: "rgba(var(--sand-100-rgb),0.15)",
    fontSize: 13,
    fontStyle: "italic",
    paddingTop: 20
  }}>Waiting for next command...</div>}
        </div>

        {}
        <div style={{
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    paddingTop: 40,
    gap: 12,
    minWidth: 72
  }}>
          <ShieldIcon state={shieldState} size={56} />
          <div style={{
    fontSize: 10,
    fontWeight: 600,
    color: "rgba(var(--sand-100-rgb),0.2)",
    textTransform: "uppercase",
    letterSpacing: "0.08em",
    textAlign: "center"
  }}>
            {phase === "scanning" ? "Checking..." : phase === "result" ? currentCommand?.blocked ? "Denied" : "Clear" : "Ready"}
          </div>
        </div>

        {}
        <div style={{
    background: "rgba(var(--sand-100-rgb),0.04)",
    border: "1px solid rgba(var(--sand-100-rgb),0.08)",
    borderRadius: 10,
    padding: 20,
    height: 300,
    overflow: "hidden"
  }}>
          <div style={{
    fontSize: 10,
    fontWeight: 600,
    color: "rgba(var(--sand-100-rgb),0.25)",
    textTransform: "uppercase",
    letterSpacing: "0.08em",
    marginBottom: 14
  }}>Decision Log</div>

          <div style={{
    display: "flex",
    flexDirection: "column",
    gap: 6
  }}>
            {results.length === 0 && <div style={{
    color: "rgba(var(--sand-100-rgb),0.15)",
    fontSize: 12,
    fontStyle: "italic"
  }}>
                No decisions yet
              </div>}
            {results.map((r, i) => <div key={r.ts} style={{
    display: "flex",
    alignItems: "center",
    gap: 8,
    padding: "8px 10px",
    background: i === 0 ? "rgba(var(--sand-100-rgb),0.03)" : "transparent",
    borderRadius: 6,
    border: i === 0 ? "1px solid rgba(var(--sand-100-rgb),0.06)" : "1px solid transparent",
    animation: i === 0 ? "resultSlide 0.3s ease-out" : "none",
    opacity: 1 - i * 0.12
  }}>
                <span style={{
    width: 6,
    height: 6,
    borderRadius: "50%",
    flexShrink: 0,
    background: r.blocked ? "#B43C3C" : "#4A7C59"
  }} />
                <span style={{
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: 11,
    color: "rgba(var(--sand-100-rgb),0.5)",
    overflow: "hidden",
    textOverflow: "ellipsis",
    whiteSpace: "nowrap",
    flex: 1
  }}>
                  {r.cmd.length > 32 ? r.cmd.slice(0, 32) + "..." : r.cmd}
                </span>
                <span style={{
    fontSize: 10,
    fontWeight: 500,
    flexShrink: 0,
    color: r.blocked ? "#D4726A" : "#7CB88A"
  }}>{r.blocked ? "BLOCKED" : "OK"}</span>
              </div>)}
          </div>
        </div>
      </div>

      {}
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: 20,
    marginTop: 16,
    paddingTop: 12,
    borderTop: "1px solid rgba(var(--sand-100-rgb),0.06)",
    position: "relative"
  }}>
        <span style={{
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: 11,
    color: "rgba(var(--sand-100-rgb),0.25)"
  }}>
          {stats.blocked} blocked
        </span>
        <span style={{
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: 11,
    color: "rgba(var(--sand-100-rgb),0.25)"
  }}>
          {stats.allowed} allowed
        </span>
        <span style={{
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: 11,
    color: "var(--warm-gold)"
  }}>
          &lt;5ms latency
        </span>
      </div>
    </div>;
};

<div style={{background: 'linear-gradient(135deg, #111111 0%, #1A1A1A 35%, #2A2A2A 70%, #3A3A3A 100%)', borderRadius: 14, overflow: 'hidden', padding: 24}}>
  <KillCommandDemo />
</div>

Guardrails use pattern matching to evaluate queries and block dangerous operations before they execute. This page covers configuration options and rule syntax.

<Note>
  For an introduction to what Guardrails do and common use cases, see [Guardrails Overview](/learn/features/guardrails).
</Note>

***

## Prerequisites

Guardrails are evaluated by the **Microsoft Presidio Analyzer** — patterns and word lists are sent to Presidio as ad-hoc recognizers, and matching happens inside Presidio.

<Warning>
  **Presidio is required.** There is no fallback engine. If a resource role has a guardrail assigned and Presidio is not deployed or the gateway cannot reach it, queries on that resource role will fail.
</Warning>

Before configuring guardrails, deploy Presidio and point the gateway at it:

<CardGroup cols={2}>
  <Card title="Deploy Presidio" icon="dharmachakra" href="/setup/deployment/presidio">
    Helm chart, sizing, and autoscaling for the Analyzer, Anonymizer, and Envoy Proxy.
  </Card>

  <Card title="Microsoft Presidio Integration" icon="shield-check" href="/integrations/ms-presidio">
    Required gateway environment variables and integration overview.
  </Card>
</CardGroup>

***

## Creating a Guardrail

<Steps>
  <Step title="Navigate to Guardrails">
    In the Web App, open the **Discover** section in the sidebar and select **Guardrails**
  </Step>

  <Step title="Create New Guardrail">
    Click **Create New Guardrail** in the top-right corner
  </Step>

  <Step title="Set Basic Information">
    * **Name:** A short identifier (e.g., `block-ddl`, `read-only-mode`)
    * **Description:** Explain what this guardrail protects against
  </Step>

  <Step title="Add Rules">
    Configure Input Rules and/or Output Rules (see below)
  </Step>

  <Step title="Assign Resource Roles">
    Select which resource roles this guardrail applies to
  </Step>

  <Step title="Save">
    Click **Save** to activate the guardrail
  </Step>
</Steps>

***

## Rule Configuration

### Input Rules

Input rules evaluate queries **before** they execute. Use these to block dangerous commands.

| Field       | Description                     | Example                       |
| ----------- | ------------------------------- | ----------------------------- |
| **Pattern** | Regex pattern to match          | `(?i)DROP\s+TABLE`            |
| **Action**  | What to do when pattern matches | Block, Warn, Require Approval |
| **Message** | Error message shown to user     | `DDL commands are blocked`    |

### Output Rules

Output rules evaluate query results **after** execution. Use these to filter or redact output.

| Field           | Description                      | Example                       |
| --------------- | -------------------------------- | ----------------------------- |
| **Pattern**     | Regex pattern to match in output | `\b\d{3}-\d{2}-\d{4}\b` (SSN) |
| **Action**      | What to do when pattern matches  | Redact, Block, Warn           |
| **Replacement** | Text to replace matches with     | `[REDACTED]`                  |

<Note>
  For data masking that automatically detects PII, see [Live Data Masking](/learn/features/live-data-masking) instead.
</Note>

***

## Pattern Syntax

Guardrail patterns are compiled by **Microsoft Presidio**, which uses Python's `re` module. Write patterns using **Python regex syntax** — not JavaScript/ECMAScript and not Go's RE2.

### Basic Syntax

| Syntax    | Meaning                 | Example                                     |
| --------- | ----------------------- | ------------------------------------------- |
| `(?i)`    | Case-insensitive        | `(?i)drop` matches `DROP`, `Drop`, `drop`   |
| `\s+`     | One or more whitespace  | `DROP\s+TABLE` matches `DROP TABLE`         |
| `\s*`     | Zero or more whitespace | `DROP\s*TABLE` matches `DROPTABLE` too      |
| `\b`      | Word boundary           | `\bDROP\b` won't match `BACKDROP`           |
| `^`       | Start of string         | `^SELECT` only matches SELECT at start      |
| `$`       | End of string           | `;\s*$` matches trailing semicolon          |
| `.*`      | Any characters          | `SELECT.*FROM` matches anything between     |
| `(?!...)` | Negative lookahead      | `(?!.*WHERE)` means "not followed by WHERE" |

### Common Patterns

**Block UPDATE without WHERE:**

```regex theme={"dark"}
(?i)^\s*UPDATE\s+\w+\s+SET\s+(?!.*WHERE)
```

**Block DELETE without WHERE:**

```regex theme={"dark"}
(?i)^\s*DELETE\s+FROM\s+\w+(?!.*WHERE)
```

**Block all DDL:**

```regex theme={"dark"}
(?i)^\s*(DROP|CREATE|ALTER|TRUNCATE)\s+(TABLE|DATABASE|INDEX|SCHEMA|VIEW)
```

**Block SELECT \* on specific tables:**

```regex theme={"dark"}
(?i)SELECT\s+\*\s+FROM\s+(users|orders|transactions)
```

**Require LIMIT clause:**

```regex theme={"dark"}
(?i)SELECT\s+(?!.*\bLIMIT\b).*FROM
```

**Enforce read-only access** (create separate rules for each):

| Pattern                 | Blocks            |             |              |
| ----------------------- | ----------------- | ----------- | ------------ |
| `(?i)^\s*INSERT\s+INTO` | INSERT statements |             |              |
| `(?i)^\s*UPDATE\s+`     | UPDATE statements |             |              |
| `(?i)^\s*DELETE\s+FROM` | DELETE statements |             |              |
| \`(?i)^\s\*(CREATE      | DROP              | ALTER)\s+\` | DDL commands |

<Tip>
  Apply read-only patterns only to resource roles used by read-only groups, not to admin resource roles.
</Tip>

**Prevent credential access** — block queries that might expose passwords or secrets:

```regex theme={"dark"}
(?i)SELECT\s+.*\bFROM\s+\w*users\w*.*\b(password|secret|token|api_key)\b
```

**Block specific table access** — restrict sensitive tables like `salaries` or `api_keys`:

```regex theme={"dark"}
(?i)\b(FROM|JOIN|INTO|UPDATE)\s+(salaries|api_keys|credentials|secrets)\b
```

### Testing Patterns

Before deploying a pattern, test it at [regex101.com](https://regex101.com):

1. Select **Flavor: Python**
2. Paste your pattern in the **Regular Expression** field
3. Enter test queries in the **Test String** field
4. Verify matches highlight correctly

<Note>
  Inline flags (`(?i)`, `(?m)`, `(?s)`), lookaheads (`(?!...)`), lookbehinds (`(?<=...)`), and word boundaries (`\b`) are all supported by Python's `re`. Avoid JavaScript-only constructs — for example, Python's named groups use `(?P<name>...)`, not `(?<name>...)`.
</Note>

***

## Actions

### Block

Prevents the query from executing and returns an error.

**Use when:** The operation should never be allowed (e.g., `DROP TABLE` in production)

**User sees:**

```
Error: Guardrail violation
Rule: block-ddl
Message: DDL commands are blocked in production
```

### Warn

Allows the query but shows a warning message.

**Use when:** You want to educate users without blocking work (e.g., missing LIMIT)

**User sees:**

```
Warning: Consider adding a LIMIT clause to prevent large result sets
Query executed successfully.
```

### Require Approval

Blocks the query until an approver approves it.

**Use when:** Some queries need human review before execution (e.g., bulk updates)

**User sees:**

```
This query requires approval.
Waiting for approval at https://use.hoop.dev/access-requests/abc123...
```

<Note>
  Require Approval uses the same workflow as [Action Access Requests](/learn/features/access-requests/action).
</Note>

***

## Resource Role Assignment

Each guardrail can be assigned to multiple resource roles. You can also have multiple guardrails on a single resource role.

### Assignment Options

| Option                      | Description                                       |
| --------------------------- | ------------------------------------------------- |
| **Specific resource roles** | Select individual resource roles from the list    |
| **All resource roles**      | Apply to every resource role in your organization |
| **Resource role tags**      | Apply to resource roles matching specific tags    |

### Evaluation Order

When multiple guardrails apply to a resource role, they are evaluated in order of priority:

1. **Priority 1** (highest) evaluated first
2. First matching rule determines the action
3. If no rules match, query is allowed

To set priority:

1. Open **Discover > Guardrails** in the sidebar
2. Drag guardrails to reorder them
3. Higher position = higher priority

***

## Environment Variables

Guardrails run inside Microsoft Presidio, so they share the same gateway environment variables as Live Data Masking. Configure these on the gateway — guardrails will not evaluate without them:

| Variable                    | Description                                               | Example                         |
| --------------------------- | --------------------------------------------------------- | ------------------------------- |
| `DLP_PROVIDER`              | Must be set to enable Presidio-backed guardrails          | `mspresidio`                    |
| `MSPRESIDIO_ANALYZER_URL`   | URL of the Presidio Analyzer service                      | `http://presidio-envoy-lb:3010` |
| `MSPRESIDIO_ANONYMIZER_URL` | URL of the Presidio Anonymizer service                    | `http://presidio-envoy-lb:3010` |
| `DLP_MODE`                  | `best-effort` or `strict` (shared with Live Data Masking) | `best-effort`                   |

For deployment details (workers, autoscaling, models), see [Microsoft Presidio Deployment](/setup/deployment/presidio).

***

## Testing Guardrails Safely

<Warning>
  Always test guardrails before applying them to production resource roles.
</Warning>

### Testing Process

<Steps>
  <Step title="Create a Test Resource Role">
    Create a separate resource role to the same database (e.g., `prod-db-test`)
  </Step>

  <Step title="Apply the Guardrail">
    Assign the guardrail only to the test resource role
  </Step>

  <Step title="Run Test Queries">
    Test both queries that should be blocked and queries that should pass
  </Step>

  <Step title="Verify Results">
    Confirm the guardrail blocks what it should and allows what it should
  </Step>

  <Step title="Apply to Production">
    Once verified, add production resource roles to the guardrail
  </Step>
</Steps>

### Worked Example

Try running a query that should be blocked:

```bash theme={"dark"}
hoop exec prod-db -i "UPDATE users SET status = 'inactive'"
```

Expected output:

```
Error: Guardrail violation
Rule: block-unsafe-updates
Message: Blocked: UPDATE/DELETE requires a WHERE clause
```

Now run a query that should pass:

```bash theme={"dark"}
hoop exec prod-db -i "UPDATE users SET status = 'inactive' WHERE id = 123"
```

This query executes normally because it includes a WHERE clause.

For each guardrail, test:

1. **Should block:** A query that matches the pattern exactly
2. **Should allow:** A similar query that doesn't match
3. **Edge cases:** Queries with different casing, extra whitespace, or variations

***

## Monitoring Guardrails

### Viewing Blocked Queries

1. Go to **Sessions** in the sidebar
2. Filter by **Status: Blocked**
3. Click a session to see details

Each blocked session shows:

* The query that was blocked
* Which guardrail and rule triggered
* The error message
* User and timestamp

### Audit Log

All guardrail evaluations are logged:

* **Blocked queries** - Logged with full query text
* **Warnings** - Logged with warning message
* **Approval requests** - Logged with request status

Access audit logs in **Sessions** or export via the API.

***

## Emergency Bypass

If a legitimate query is blocked and needs to run immediately:

### Option 1: Temporarily Disable the Guardrail

1. Open **Discover > Guardrails** in the sidebar
2. Find the blocking guardrail
3. Toggle it to **Disabled**
4. Run your query
5. Re-enable the guardrail immediately after

<Warning>
  Document any emergency bypass in your incident log. Re-enable the guardrail as soon as possible.
</Warning>

### Option 2: Refine the Pattern

If the guardrail is catching legitimate queries, update the pattern:

1. Open **Discover > Guardrails** and select the guardrail
2. Edit the rule that's causing issues
3. Refine the regex to be more specific
4. Save and test

### Option 3: Add an Exception

For specific users or groups that need to bypass certain rules:

1. Create a new resource role without the guardrail
2. Restrict access to that resource role to specific groups
3. Use this "elevated" resource role for exceptional cases

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Start with Warn" icon="triangle-exclamation">
    Use Warn mode first to understand impact before blocking
  </Card>

  <Card title="Test in Dev First" icon="flask">
    Apply guardrails to test resource roles before production
  </Card>

  <Card title="Be Specific" icon="crosshairs">
    Use precise patterns to avoid false positives
  </Card>

  <Card title="Document Rules" icon="file-lines">
    Write clear descriptions explaining why each rule exists
  </Card>
</CardGroup>

### Pattern Guidelines

1. **Always use `(?i)`** for case-insensitive matching
2. **Use `\b` for word boundaries** to avoid partial matches
3. **Use `^\s*`** to allow leading whitespace
4. **Test edge cases** like multi-line queries and comments
5. **Keep patterns simple** - complex regex is hard to maintain

***

## Troubleshooting

### Pattern Not Matching

**Check:**

1. Test the pattern at [regex101.com](https://regex101.com) with the exact query
2. Verify case sensitivity (add `(?i)` if needed)
3. Check for leading/trailing whitespace in the query

**Common pattern mistakes:**

| Problem                  | Bad Pattern  | Fixed Pattern                          |
| ------------------------ | ------------ | -------------------------------------- |
| Missing case-insensitive | `DROP TABLE` | `(?i)DROP TABLE`                       |
| Missing word boundaries  | `DELETE`     | `\bDELETE\b`                           |
| Anchoring too strict     | `^DROP`      | `^\s*DROP` (allows leading whitespace) |

### Too Many False Positives

**Fix:**

1. Make the pattern more specific
2. Add word boundaries (`\b`)
3. Use negative lookahead for exceptions

**Example:** Pattern `DROP` blocks `DROP_SHIPPED_ITEMS` table name

**Fix:** `(?i)^\s*DROP\s+(TABLE|DATABASE)` only matches DDL commands

### Performance Issues

If queries are slow:

1. Reduce the number of rules per resource role
2. Simplify complex regex patterns
3. Avoid patterns with excessive backtracking (e.g., `.*.*.*`)

***

## Related

<CardGroup cols={2}>
  <Card title="Guardrails Overview" icon="shield" href="/learn/features/guardrails">
    Learn what guardrails do and see common recipes
  </Card>

  <Card title="Live Data Masking" icon="mask" href="/setup/configuration/live-data-masking/get-started">
    Configure automatic PII detection and masking
  </Card>

  <Card title="Action Access Requests" icon="clock" href="/setup/configuration/access-requests/action-configuration">
    Configure the "Require Approval" action
  </Card>

  <Card title="Access Control" icon="lock" href="/setup/configuration/access-control-configuration">
    Control who can access which resource roles
  </Card>
</CardGroup>
