Contents
Adapters: make pg_policy work for every agent runtime
One SQL contract, many PEPs. The PEP is whatever actually invokes tools.
evaluate(principal_type, principal_id, action_type, action_id,
resource_type, resource_id, context jsonb, session_id)
→ { decision, allowed, obligations, reasons, mode, matched_policies }
1. Raw SQL / any driver
SELECT pg_policy.evaluate(
'agent',
'langgraph:analytics',
'tool',
'execute_sql',
'table', 'public.orders',
jsonb_build_object(
'statement_type', 'SELECT',
'acting_for', 'user:42',
'tenant_id', 'acme'
),
'thread-abc'
);
Python: examples/integrations/evaluate_middleware.py
2. MCP Postgres servers
Wrap query / execute_sql / explain_query:
- Classify
statement_type(SELECT/INSERT/…; fail closed on unknown). evaluatewithaction_id= MCP tool name.- On deny: return MCP error with
reasons(do not execute). - On
max_rows: inject LIMIT / truncate. - On
prefer_tool: include in error/hint so the model can callexplain_query.
This replaces per-server hardcoded allowlists. Keep BEGIN READ ONLY as defense in depth.
3. LangGraph ToolNode
session_id=config["configurable"]["thread_id"]principal_id= graph/agent name- Wrap each DB tool with the middleware before the SQL runs
- Persist checkpoints with
PostgresSaverand policy in the same cluster when possible
Human-in-the-loop: map interrupt() to a guide/forbid that requires context.approved == "true" after the human resumes.
4. CrewAI / AutoGen / Letta
Assign one principal_id per role (crew:researcher, crew:writer). Load examples/packs/multi-agent.sql. The crew process is not a security boundary; pg_policy is.
5. Cursor / Claude Desktop / IDE MCP
Prod connections: devops.sql + read-only role + enforce.
Personal dev: log_only is acceptable; still load baseline so you see shadow_denies.
6. HTTP / AuthZEN PEP
Map:
| AuthZEN | pg_policy |
|---|---|
| subject.type/id | principal_* |
| action.name | action_id (action_type=tool) |
| resource.type/id | resource_* |
| context | context jsonb |
| decision boolean | allowed |
Obligations travel in your PEP’s extra context until the HTTP sidecar exists (roadmap 0.3).
7. What if the host forbids CREATE EXTENSION?
Until Neon/RDS allowlist you:
- Run pg_policy on a policy sidecar Postgres (evaluate remotely), or
- Load the SQL as a plain schema in a self-hosted replica used as PDP, or
- Use the same APL files in CI against a local PG.
The language and packs stay identical. The extension is the preferred PDP, not the only place APL can be stored during transition.