Skip to content

Your First Blocked Action

This walkthrough shows what enforcement looks like end-to-end: a policy blocks a dangerous tool call before it reaches the tool.

Setup

Create policies/demo.yaml:

deny:
  - capability: shell.execute
    contains: "rm -rf"

allow:
  - capability: shell.execute

Code

from shadowaudit.core.gate import Gate

gate = Gate()

# This call is safe — it passes
result = gate.evaluate(
    agent_id="demo-agent",
    task_context="shell",
    risk_category="shell_execution",
    capability="shell.execute",
    policy_path="policies/demo.yaml",
    payload={"command": "ls -la /tmp"}
)
print(result.passed)   # True

# This call is dangerous — it is blocked before execution
result = gate.evaluate(
    agent_id="demo-agent",
    task_context="shell",
    risk_category="shell_execution",
    capability="shell.execute",
    policy_path="policies/demo.yaml",
    payload={"command": "rm -rf /var/lib/postgresql"}
)
print(result.passed)   # False
print(result.reason)   # destructive_command_detected

What happens at the framework layer

With a LangChain wrapper, blocked calls raise an exception so the agent cannot proceed:

from shadowaudit import ShadowAuditTool
from langchain.tools import ShellTool

safe_shell = ShadowAuditTool(
    tool=ShellTool(),
    agent_id="demo-agent",
    capability="shell.execute",
    policy_path="policies/demo.yaml"
)

# This raises AgentActionBlocked — the shell never runs
safe_shell.run("rm -rf /var/lib/postgresql")
AgentActionBlocked: capability=shell.execute decision=denied reason=destructive_command_detected

Checking the audit log

Both the allowed and denied decisions are recorded:

shadowaudit logs
timestamp            agent_id      capability      decision  reason
2024-01-15 10:23:01  demo-agent    shell.execute   allow     —
2024-01-15 10:23:02  demo-agent    shell.execute   deny      destructive_command_detected

Verifying log integrity

shadowaudit verify --audit-log ./audit.db
✓ Audit chain intact. 2 entries verified.

Next steps