Skip to content
pg_policy

pg_policy

pg_policy : Agentic policy language for PostgreSQL with guardrails, guidance, and session-aware controls

Overview

ID Extension Package Version Category License Language
7440
pg_policy
pg_policy
0.1.0
SEC
PostgreSQL
SQL
Attribute Has Binary Has Library Need Load Has DDL Relocatable Trusted
----d--
No
No
No
Yes
no
no
Relationships
Schemas policy
See Also
pg_command_fw
pgextwlist
set_user
noset
block_copy_command
supautils
anon
pgaudit

PIGSTY patches the reserved upstream schema pg_policy to policy and quotes the reserved check function, so the packaged API is policy.check() rather than pg_policy.check(); pure SQL and PL/pgSQL, no preload.

Packages

Type Repo Version PG Major Compatibility Package Pattern Dependencies
EXT
PIGSTY
0.1.0
18
17
16
15
14
pg_policy -
RPM
PIGSTY
0.1.0
18
17
16
15
14
pg_policy_$v -
DEB
PIGSTY
0.1.0
18
17
16
15
14
postgresql-$v-pg-policy -
Linux / PG PG18 PG17 PG16 PG15 PG14
el8.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
el8.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
el9.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
el9.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
el10.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
el10.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
d12.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
d12.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
d13.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
d13.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
u22.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
u22.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
u24.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
u24.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
u26.x86_64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
u26.aarch64
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
PIGSTY 0.1.0
Package Version OS ORG SIZE File URL
pg_policy_18 0.1.0 el8.x86_64 pigsty 15.9 KiB pg_policy_18-0.1.0-1PIGSTY.el8.noarch.rpm
pg_policy_18 0.1.0 el8.aarch64 pigsty 15.9 KiB pg_policy_18-0.1.0-1PIGSTY.el8.noarch.rpm
pg_policy_18 0.1.0 el9.x86_64 pigsty 15.8 KiB pg_policy_18-0.1.0-1PIGSTY.el9.noarch.rpm
pg_policy_18 0.1.0 el9.aarch64 pigsty 15.8 KiB pg_policy_18-0.1.0-1PIGSTY.el9.noarch.rpm
pg_policy_18 0.1.0 el10.x86_64 pigsty 16.0 KiB pg_policy_18-0.1.0-1PIGSTY.el10.noarch.rpm
pg_policy_18 0.1.0 el10.aarch64 pigsty 15.9 KiB pg_policy_18-0.1.0-1PIGSTY.el10.noarch.rpm
postgresql-18-pg-policy 0.1.0 d12.x86_64 pigsty 10.4 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~bookworm_all.deb
postgresql-18-pg-policy 0.1.0 d12.aarch64 pigsty 10.4 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~bookworm_all.deb
postgresql-18-pg-policy 0.1.0 d13.x86_64 pigsty 10.4 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~trixie_all.deb
postgresql-18-pg-policy 0.1.0 d13.aarch64 pigsty 10.4 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~trixie_all.deb
postgresql-18-pg-policy 0.1.0 u22.x86_64 pigsty 10.3 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~jammy_all.deb
postgresql-18-pg-policy 0.1.0 u22.aarch64 pigsty 10.3 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~jammy_all.deb
postgresql-18-pg-policy 0.1.0 u24.x86_64 pigsty 10.3 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~noble_all.deb
postgresql-18-pg-policy 0.1.0 u24.aarch64 pigsty 10.3 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~noble_all.deb
postgresql-18-pg-policy 0.1.0 u26.x86_64 pigsty 10.3 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~resolute_all.deb
postgresql-18-pg-policy 0.1.0 u26.aarch64 pigsty 10.3 KiB postgresql-18-pg-policy_0.1.0-1PGSTY~resolute_all.deb

Source

pig build pkg pg_policy;		# build rpm/deb

Install

Make sure PGDG and PIGSTY repo available:

pig repo add pgsql -u   # add both repo and update cache

Install this extension with pig:

pig install pg_policy;		# install via package name, for the active PG version

pig install pg_policy -v 18;   # install for PG 18
pig install pg_policy -v 17;   # install for PG 17
pig install pg_policy -v 16;   # install for PG 16
pig install pg_policy -v 15;   # install for PG 15
pig install pg_policy -v 14;   # install for PG 14

Create this extension with:

CREATE EXTENSION pg_policy;

Usage

Sources:

pg_policy 0.1.0 is an experimental SQL and PL/pgSQL policy evaluator for agent and tool actions. It stores Agent Policy Language rules, evaluates context and session history, records every decision, and returns obligations for a gateway to enforce. It complements PostgreSQL roles and row-level security; it does not intercept SQL or tool calls by itself.

Pigsty Schema Compatibility

Upstream 0.1.0 declares the reserved schema name pg_policy and defines an unquoted function named check. Pigsty packages patch the installed schema to policy, quote the reserved function name as policy."check"(), and fix function search paths. The upstream examples therefore cannot be copied verbatim into a Pigsty installation.

CREATE EXTENSION pg_policy;

SELECT policy.set_setting('enforcement_mode', 'log_only');

The extension is not relocatable, requires PostgreSQL 14 or later, and does not require shared_preload_libraries or a PostgreSQL restart. Current Pigsty packages cover PostgreSQL 14–18.

Define and Evaluate a Guardrail

SELECT policy.upsert_policy('block_ddl', $apl$
forbid
  principal agent "research_bot"
  action tool "execute_sql"
  when { context.statement_type in ["DROP", "TRUNCATE", "ALTER", "CREATE"] }
  reason "Research agents may not run DDL"
$apl$);

SELECT policy.set_setting('enforcement_mode', 'enforce');

SELECT policy.evaluate(
  'agent', 'research_bot',
  'tool', 'execute_sql',
  '*', '*',
  '{"statement_type":"DROP"}'::jsonb,
  NULL
);

SELECT policy."check"(
  'research_bot',
  'execute_sql',
  '{"statement_type":"DROP"}'::jsonb
);

policy.evaluate(...) returns JSON containing decision, allowed, matched_policies, obligations, reasons, and mode. The convenience wrapper policy."check"() returns only a boolean. policy.enforce() requests exception-on-deny behavior when the mode is enforce.

APL Surface

An APL document begins with one effect: permit, forbid, or guide. It can match principal, action, and resource types and identifiers. In 0.1.0, context conditions support only ==, in [...], and and. A temporal clause can count matching session events inside an interval when evaluation receives a session identifier.

forbid overrides matching permit rules. guide allows the action and can return advice, prefer_tool, or max_rows obligations. The caller—not the extension—must interpret and apply those obligations.

Sessions, Temporal Limits, and Audit

SELECT policy.open_session(
  'sess-1',
  'agent',
  'research_bot'
);

SELECT policy.upsert_policy('export_budget', $apl$
forbid
  principal agent "research_bot"
  action tool "export_csv"
  when temporal {
    count(action == "export_csv") within interval '1 hour' >= 3
  }
  reason "Export budget exceeded"
$apl$);

SELECT policy.evaluate(
  'agent', 'research_bot',
  'tool', 'export_csv',
  '*', '*',
  '{}'::jsonb,
  'sess-1'
);

policy.open_session() creates or updates a session. Evaluations with a session identifier append an event and can satisfy temporal predicates. Every evaluation writes policy.decision_log; other important relations are policy.policies, policy.sessions, policy.events, and policy.settings.

Enforcement and Security Boundaries

  • The default enforcement_mode is log_only and the default decision is permit. A matched deny becomes an allow with a shadow_deny obligation.
  • In guide mode, a matched deny becomes an allow with would_deny. Only enforce preserves a deny and allows policy.enforce() to raise an error.
  • A gateway must call the evaluator before the protected action and hard-fail on deny. Calling policy.evaluate(...) after executing a tool is only auditing.
  • Keep PostgreSQL GRANT and REVOKE, row-level security, network controls, and least-privilege credentials as the authoritative data-plane controls. Superusers and roles with BYPASSRLS can bypass row-level controls.
  • The 0.1 line is explicitly an experimental MVP, not a hardened production security boundary. Shadow-test policies, restrict who can change policy.settings or policy.policies, and monitor policy.decision_log before switching to enforce.
Last updated on