Contents
- PostgreSQL Extension Feasibility: Policy Languages & “Custom Syntax”
PostgreSQL Extension Feasibility: Policy Languages & “Custom Syntax”
Status: living research
Last updated: 2026-08-10
1. What an extension can and cannot do
Cannot
- Add new keywords or productions to
gram.y/parser.c. The SQL parser is compiled into the server binary; there is no supported extension hook for grammar plugins. - Rely on
ProcessUtility_hookorraw_parser_hookto accept unknown syntax. By the time hooks run, parse must already have succeeded.
Can
| Capability | Hook / API | Policy use |
|---|---|---|
| Intercept DDL/utility | ProcessUtility_hook |
Block dangerous DDL; augment CREATE POLICY workflows; require agent tags |
| Intercept planning/execution | planner / executor hooks | Statement firewalls; rewrite; audit |
| Background workers | BGWorker API | Session-budget reapers; async policy sync |
| Custom types & operators | PGXS / pgrx | agent_id, policy decision types |
| Functions / procedures | SQL, C, Rust | pg_policy.evaluate(...) |
| GUCs | DefineCustom*Variable |
pg_policy.enforcement_mode |
| Shared preload | _PG_init |
Register hooks early |
| Catalog tables | extension scripts | Policy store, event log, obligations |
2. Patterns used by successful extensions
2.1 Function-first DSL (always ship this)
SELECT pg_policy.upsert($apl$ ... $apl$);
SELECT pg_policy.evaluate(
principal := 'agent:research',
action := 'tool:execute_sql',
resource := 'table:public.orders',
context := '{"statement_type":"SELECT"}'::jsonb
);
Precedents: vast majority of PGXN extensions; pg_durable graph DSL via operators/functions.
2.2 Dollar-quoted language documents
Store Cedar-/Dogwood-/APL-shaped text; compile to JSON IR; validate against schema; evaluate in C/Rust/PL/pgSQL.
Pros: Real language UX; versionable in Git; independent of Postgres parser.
Cons: No psql syntax highlighting unless editor plugins ship.
2.3 Reuse existing DDL shapes (ProcessUtility_hook)
TimescaleDB continuous aggregates pattern:
CREATE MATERIALIZED VIEW ... WITH (timescaledb.continuous) AS ...
For policy:
-- Conceptual (hook-augmented) — options on known statements
CREATE POLICY ...; -- still native RLS
-- Plus extension catalog via functions:
SELECT pg_policy.attach_agent_guard('orders_select', 'agent:research');
Cannot invent CREATE AGENT POLICY as a core token without a fork.
2.4 Procedural language embedding
PL/V8 / PL/Python policies are flexible but expand the attack surface. Prefer a total / sandboxable evaluator (CEL-like or Cedar-like) over general-purpose scripting for guardrails.
3. Implementation technology choices
| Stack | Pros | Cons |
|---|---|---|
| Pure SQL + PL/pgSQL | Zero compile deps; easy PGXN; works everywhere | Slower; limited sandboxing; harder temporal engine |
| C + PGXS | Classic Postgres style; maximal control | Memory safety; slower iteration |
| Rust + pgrx | Memory safety; easy to embed Cedar/CEL crates | Build matrix per PG major; packaging complexity |
| Hybrid | SQL catalog + Rust evaluator | Best balance for v1→v2 |
Recommendation: Ship v0.1 as SQL/PL/pgSQL for correct semantics, tests, and docs; plan v0.2 pgrx evaluator for Cedar/CEL-class performance and sandboxing. This matches how serious extensions often mature and keeps early PGXN installs trivial.
4. Enforcement planes inside Postgres
┌─────────────────────────────────────────────────────────────┐
│ Client / Agent runtime / MCP gateway │
└───────────────────────────┬─────────────────────────────────┘
│ SQL / protocol
┌───────────────────────────▼─────────────────────────────────┐
│ pg_policy.evaluate / check / guide │
│ • catalog policies │
│ • session event log │
│ • obligations (rate limit remaining, advice) │
└───────────────┬─────────────────────────────┬───────────────┘
│ │
soft/guide path hard path
│ │
▼ ▼
return advice JSON RLS + GRANT + hooks
(data & DDL firewall)
Agents that speak SQL should still face RLS. Agents that speak tools should call pg_policy before side effects. Gateways should do both.
5. Security considerations for in-DB policy
- Policy authors ≠ policy subjects. Separate roles:
pg_policy_adminvs agent runtime roles. - No
SECURITY DEFINERfootguns withoutsearch_pathpinning. - Default deny for agent actions when any applicable restrictive policy exists.
- Audit every decision (allow, deny, guide) with request id / session id.
- Log-only mode for rollout (Dogwood/AgentCore pattern).
- Do not evaluate untrusted code as policy; APL must be data, not PL/Python blobs.
- Superuser bypass is a Postgres fact of life—document it like RLS docs do.
6. Packaging & distribution feasibility
| Channel | Requirement | Status for pg_policy |
|---|---|---|
| GitHub | Excellent README, LICENSE, CI, docs | Design goal |
| PGXN | META.json, semantic version, open license |
Design goal |
| apt/yum / Postgres.app | Later; often via packaging volunteers | Roadmap |
| OCI extension images | PGXN v2 / CloudNativePG direction | Watch |
| DBPaaS (Neon, Supabase, RDS, Crunchy, AlloyDB, Aurora) | Vendor allowlists | Partner after OSS traction |
PostgreSQL License or Apache-2.0 are both acceptable; PostgreSQL License signals community alignment for core-adjacent extensions.
7. Conclusion
A marketplace-grade policy extension is feasible if we:
- Accept dollar-quoted APL + SQL APIs as “additional syntax.”
- Optionally add hook-based enforcement for statement firewalls.
- Co-locate policies, events, and RLS.
- Publish to PGXN with classic PGXS layout and outstanding documentation.
True parser-level CREATE AGENT POLICY would require a Postgres core patch or fork—out of scope for an extension, but the UX can closely approximate it.