Shadow → Enforce Rollout

Safely roll out NjiraAI from observe-only to active enforcement.

Overview

NjiraAI supports a shadow mode that logs verdicts without blocking traffic. This lets you validate policies against real traffic before turning on enforcement.

Recommended rollout: Shadow (observe) → Review traces → Enable enforcement → Monitor


Step 1 — Start in shadow mode

Set the environment variable before starting the Gateway:

# In your .env or docker-compose override:
SHADOW_MODE=true
FAIL_CLOSED=true

Or via docker-compose.yml:

services:
  gateway:
    environment:
      - SHADOW_MODE=true
      - FAIL_CLOSED=true

Restart the Gateway:

make up-all

What happens in shadow mode

  • All requests are forwarded regardless of verdict
  • Verdicts are logged to the audit trail
  • Response headers include shadow verdict info:
    • X-Njira-Shadow-Verdict: BLOCK
    • X-Njira-Shadow-Reason: PII_DETECTED

Step 2 — Review traces

Open the NjiraAI Console at http://localhost:3100/traces to review:

  • Which requests would have been blocked
  • Reason codes and confidence scores
  • Policy pack and rule that triggered
# Or query via API:
curl -s http://localhost:8081/v1/traces \
  -H "Authorization: Bearer nj_live_dev_key_12345" | jq '.traces[] | {action, reason_code, tool_name}'

Expected output

{
  "action": "BLOCK",
  "reason_code": "PII_DETECTED",
  "tool_name": "chat_interface"
}

Look for:

  • False positives — safe requests marked BLOCK (tune policies)
  • Missed risks — unsafe requests marked ALLOW (add rules)

Step 3 — Enable enforcement

Once satisfied with shadow results, switch to enforce mode:

# In your .env or docker-compose override:
SHADOW_MODE=false
FAIL_CLOSED=true   # recommended: deny when Intelligence is unavailable

Restart the Gateway:

make up-all

Verify enforcement is active

# This should now return 403 (not 200 with shadow headers):
curl -s -w "\nHTTP %{http_code}\n" \
  http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer nj_live_dev_key_12345" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"My SSN is 123-45-6789"}]}'

Expected output

{"blocked":true,"reason":"SSN pattern (XXX-XX-XXXX) detected","reason_code":"PII_DETECTED",...}
HTTP 403

Step 4 — Rollback (if needed)

To revert to shadow mode:

SHADOW_MODE=true

Restart the Gateway. No data is lost — all previous traces remain in the audit log.


Configuration reference

Variable Values Default Description
SHADOW_MODE true/false false Log verdicts without enforcing
FAIL_CLOSED true/false true Deny when Intelligence/Redis unavailable

Success criteria

Check Expected
Shadow mode: PII request returns 200 with X-Njira-Shadow-Verdict: BLOCK
Enforce mode: PII request returns 403
Traces appear in Console at /traces
Rollback to shadow mode restores 200 for all requests

Next steps