teleo-infrastructure/ops/gcp_leoclean_runtime_role.sql

1346 lines
55 KiB
PL/PgSQL

\set ON_ERROR_STOP on
-- One-time GCP staging provisioning for Leo's Cloud SQL identity. Run this
-- only through ops/provision_gcp_leoclean_runtime_role.sh; psql's \password
-- command encrypts the supplied value client-side, so cleartext is never SQL.
--
-- The login can read the canonical allowlist and can stage a pending proposal
-- through one narrowly-scoped SECURITY DEFINER function. It cannot inherit or
-- SET ROLE into another principal, forge the proposer identity, write directly
-- to canonical/staging tables, or inspect the legacy teleo_restore audit schema.
-- Keep the runtime unable to authenticate until both database phases have
-- completed and verified. Any failure before the final transaction therefore
-- leaves a disabled role instead of a partially provisioned login.
select 'create role leoclean_kb_runtime nologin nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls connection limit 8'
where not exists (select 1 from pg_catalog.pg_roles where rolname = 'leoclean_kb_runtime')
\gexec
select 'create role leoclean_kb_stage_owner nologin nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls connection limit -1'
where not exists (select 1 from pg_catalog.pg_roles where rolname = 'leoclean_kb_stage_owner')
\gexec
alter role leoclean_kb_runtime
with nologin nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls connection limit 8;
alter role leoclean_kb_stage_owner
with nologin nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls connection limit -1
password null;
-- Snapshot every non-superuser principal connected to either scoped role before
-- removing the direct membership edges. Existing sessions can retain an
-- already-selected SET ROLE identity after NOLOGIN/revocation, so all other
-- connected sessions must be terminated before password or privilege work.
create temporary table leoclean_fenced_roles (
role_oid oid primary key,
role_name name unique not null
) on commit preserve rows;
with recursive connected(role_oid) as (
values
('leoclean_kb_runtime'::pg_catalog.regrole::oid),
('leoclean_kb_stage_owner'::pg_catalog.regrole::oid)
union
select membership.member
from connected
join pg_catalog.pg_auth_members membership
on membership.roleid = connected.role_oid
)
insert into pg_temp.leoclean_fenced_roles (role_oid, role_name)
select role_row.oid, role_row.rolname
from connected
join pg_catalog.pg_roles role_row on role_row.oid = connected.role_oid
where not role_row.rolsuper;
-- NOINHERIT does not prevent SET ROLE. Remove every direct membership edge in
-- either direction before terminating the snapshotted sessions, closing the
-- race for newly connected membership principals.
select format('revoke %I from %I', granted_role.rolname, member_role.rolname)
from pg_catalog.pg_auth_members membership
join pg_catalog.pg_roles granted_role on granted_role.oid = membership.roleid
join pg_catalog.pg_roles member_role on member_role.oid = membership.member
where granted_role.rolname in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
or member_role.rolname in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
\gexec
do $session_fence$
declare
target record;
remaining text;
begin
for target in
select activity.pid
from pg_catalog.pg_stat_activity activity
join pg_temp.leoclean_fenced_roles fenced on fenced.role_name = activity.usename
where activity.pid <> pg_catalog.pg_backend_pid()
and activity.backend_type = 'client backend'
loop
if not pg_catalog.pg_terminate_backend(target.pid, 5000) then
raise exception 'could not terminate a pre-existing scoped-role session';
end if;
end loop;
select pg_catalog.string_agg(activity.pid::text, ',' order by activity.pid)
into remaining
from pg_catalog.pg_stat_activity activity
join pg_temp.leoclean_fenced_roles fenced on fenced.role_name = activity.usename
where activity.pid <> pg_catalog.pg_backend_pid()
and activity.backend_type = 'client backend';
if remaining is not null then
raise exception 'pre-existing scoped-role sessions remain after termination';
end if;
select pg_catalog.string_agg(prepared.gid, ',' order by prepared.gid)
into remaining
from pg_catalog.pg_prepared_xacts prepared
join pg_temp.leoclean_fenced_roles fenced on fenced.role_name = prepared.owner;
if remaining is not null then
raise exception 'scoped-role prepared transactions must be resolved before provisioning';
end if;
end
$session_fence$;
-- This is deliberately after the autocommitted NOLOGIN/session/membership
-- fence. Interruption can leave a disabled role, never a still-enabled old
-- login or an old connected session. The wrapper supplies the two prompts.
\password leoclean_kb_runtime
alter role leoclean_kb_runtime reset all;
alter role leoclean_kb_stage_owner reset all;
drop table pg_temp.leoclean_fenced_roles;
select pg_catalog.format(
'alter role %I in database %I reset all',
role_row.rolname,
database_row.datname
)
from pg_catalog.pg_db_role_setting setting_row
join pg_catalog.pg_roles role_row on role_row.oid = setting_row.setrole
join pg_catalog.pg_database database_row on database_row.oid = setting_row.setdatabase
where role_row.rolname in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
\gexec
-- PostgreSQL normally grants TEMP to PUBLIC. A role-specific REVOKE cannot
-- override that inherited grant, while REVOKE TEMP FROM PUBLIC would be a
-- database-wide change that could break kb_apply/review or operator workflows.
-- Leave PUBLIC TEMP policy unchanged here and surface it in the final receipt.
-- TEMP cannot shadow this SECURITY DEFINER boundary: pg_catalog is first,
-- pg_temp is explicitly last, and every relation reference is schema-qualified.
-- Database CREATE, direct TEMP grants, and all unexpected direct database ACLs
-- are rejected below. A database-wide TEMP removal requires a separate role-use
-- inventory and explicit grants to every workload that still needs it.
alter role leoclean_kb_runtime in database teleo_canonical reset all;
alter role leoclean_kb_stage_owner in database teleo_canonical reset all;
alter role leoclean_kb_runtime in database teleo_kb reset all;
alter role leoclean_kb_stage_owner in database teleo_kb reset all;
alter role leoclean_kb_runtime in database teleo_canonical
set search_path = pg_catalog, public, kb_stage;
alter role leoclean_kb_runtime in database teleo_canonical
set statement_timeout = '15s';
alter role leoclean_kb_runtime in database teleo_canonical
set lock_timeout = '2s';
\connect teleo_canonical
begin;
-- CONNECT granted to PUBLIC cannot be denied to one role with a role-specific
-- REVOKE. Preserve every existing non-scoped principal's effective CONNECT
-- set as explicit ACLs, remove the cluster-wide PUBLIC grant from every
-- database (including templates), and then grant the runtime its sole target.
-- This runs in the same transaction as every remaining privilege/topology
-- assertion, so a later failure restores the original ACLs atomically.
create temporary table leoclean_preserved_database_connect (
role_name name not null,
database_name name not null,
primary key (role_name, database_name)
) on commit drop;
insert into pg_temp.leoclean_preserved_database_connect (role_name, database_name)
select role_row.rolname, database_row.datname
from pg_catalog.pg_roles role_row
cross join pg_catalog.pg_database database_row
where role_row.rolname not in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
and pg_catalog.has_database_privilege(role_row.oid, database_row.oid, 'CONNECT');
select pg_catalog.format('revoke connect on database %I from public', database_row.datname)
from pg_catalog.pg_database database_row
\gexec
select pg_catalog.format(
'revoke all privileges on database %I from leoclean_kb_runtime, leoclean_kb_stage_owner',
database_row.datname
)
from pg_catalog.pg_database database_row
\gexec
select pg_catalog.format(
'grant connect on database %I to %I',
preserved.database_name,
preserved.role_name
)
from pg_temp.leoclean_preserved_database_connect preserved
order by preserved.database_name, preserved.role_name
\gexec
grant connect on database teleo_canonical to leoclean_kb_runtime;
-- The deploy principal needs temporary ownership authority to replace an
-- existing function on idempotent reruns. This membership is transaction-local
-- and is revoked before verification/commit.
select format('grant leoclean_kb_stage_owner to %I', current_user)
where current_user <> 'leoclean_kb_stage_owner'
\gexec
revoke all on schema public, kb_stage
from leoclean_kb_runtime, leoclean_kb_stage_owner;
revoke all privileges on all tables in schema public, kb_stage
from leoclean_kb_runtime, leoclean_kb_stage_owner;
revoke all privileges on all sequences in schema public, kb_stage
from leoclean_kb_runtime, leoclean_kb_stage_owner;
revoke all privileges on all functions in schema public, kb_stage
from leoclean_kb_runtime, leoclean_kb_stage_owner;
revoke all privileges on all procedures in schema public, kb_stage
from leoclean_kb_runtime, leoclean_kb_stage_owner;
-- Built-in defaults also grant PUBLIC EXECUTE on newly created application
-- routines. Preserve every existing non-scoped role's effective access,
-- remove PUBLIC/scoped execution from the complete application routine set,
-- and restore the inventory explicitly. The reviewed staging function is
-- normalized again after CREATE OR REPLACE below.
create temporary table leoclean_preserved_app_routine_execute (
role_name name not null,
function_oid oid not null,
primary key (role_name, function_oid)
) on commit drop;
insert into pg_temp.leoclean_preserved_app_routine_execute (role_name, function_oid)
select role_row.rolname, function_row.oid
from pg_catalog.pg_roles role_row
cross join pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where role_row.rolname not in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
and namespace.nspname in ('public', 'kb_stage')
and pg_catalog.has_function_privilege(role_row.oid, function_row.oid, 'EXECUTE');
select pg_catalog.format(
'revoke execute on %s %I.%I(%s) from public, leoclean_kb_runtime, leoclean_kb_stage_owner',
case when function_row.prokind = 'p' then 'procedure' else 'function' end,
namespace.nspname,
function_row.proname,
pg_catalog.pg_get_function_identity_arguments(function_row.oid)
)
from pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where namespace.nspname in ('public', 'kb_stage')
\gexec
select pg_catalog.format(
'grant execute on %s %I.%I(%s) to %I',
case when function_row.prokind = 'p' then 'procedure' else 'function' end,
namespace.nspname,
function_row.proname,
pg_catalog.pg_get_function_identity_arguments(function_row.oid),
preserved.role_name
)
from pg_temp.leoclean_preserved_app_routine_execute preserved
join pg_catalog.pg_proc function_row on function_row.oid = preserved.function_oid
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
order by namespace.nspname, function_row.proname, preserved.role_name
\gexec
select pg_catalog.format(
'revoke all privileges on large object %s from leoclean_kb_runtime, leoclean_kb_stage_owner',
metadata.oid
)
from pg_catalog.pg_largeobject_metadata metadata
\gexec
-- Default PostgreSQL grants EXECUTE on built-in large-object mutators to
-- PUBLIC, which would let the runtime persist data despite all relation ACLs.
-- Snapshot and explicitly preserve every existing non-scoped role's effective
-- access, then remove PUBLIC and both scoped roles from every mutator overload.
create temporary table leoclean_preserved_lo_execute (
role_name name not null,
function_oid oid not null,
primary key (role_name, function_oid)
) on commit drop;
insert into pg_temp.leoclean_preserved_lo_execute (role_name, function_oid)
select role_row.rolname, function_row.oid
from pg_catalog.pg_roles role_row
cross join pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where role_row.rolname not in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
and namespace.nspname = 'pg_catalog'
and function_row.proname in (
'lo_creat', 'lo_create', 'lo_export', 'lo_from_bytea', 'lo_import',
'lo_open', 'lo_put', 'lo_truncate', 'lo_truncate64', 'lo_unlink', 'lowrite'
)
and pg_catalog.has_function_privilege(role_row.oid, function_row.oid, 'EXECUTE');
select pg_catalog.format(
'revoke execute on function pg_catalog.%I(%s) from public, leoclean_kb_runtime, leoclean_kb_stage_owner',
function_row.proname,
pg_catalog.pg_get_function_identity_arguments(function_row.oid)
)
from pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where namespace.nspname = 'pg_catalog'
and function_row.proname in (
'lo_creat', 'lo_create', 'lo_export', 'lo_from_bytea', 'lo_import',
'lo_open', 'lo_put', 'lo_truncate', 'lo_truncate64', 'lo_unlink', 'lowrite'
)
\gexec
select pg_catalog.format(
'grant execute on function pg_catalog.%I(%s) to %I',
function_row.proname,
pg_catalog.pg_get_function_identity_arguments(function_row.oid),
preserved.role_name
)
from pg_temp.leoclean_preserved_lo_execute preserved
join pg_catalog.pg_proc function_row on function_row.oid = preserved.function_oid
order by function_row.proname, preserved.role_name
\gexec
select pg_catalog.format(
'revoke all privileges on parameter %I from leoclean_kb_runtime, leoclean_kb_stage_owner',
parameter_acl.parname
)
from pg_catalog.pg_parameter_acl parameter_acl
\gexec
-- Table-level REVOKE does not clear column ACLs. Clear every column ACL for both
-- principals before rebuilding the exact allowlist below.
select format(
'revoke all privileges (%s) on table %I.%I from %I',
pg_catalog.string_agg(pg_catalog.quote_ident(attribute.attname), ', ' order by attribute.attnum),
namespace.nspname,
relation.relname,
target.rolname
)
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_attribute attribute on attribute.attrelid = relation.oid
cross join (
values ('leoclean_kb_runtime'), ('leoclean_kb_stage_owner')
) as target(rolname)
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
group by namespace.nspname, relation.relname, target.rolname
\gexec
grant usage on schema public, kb_stage to leoclean_kb_runtime;
grant select on
public.agents,
public.claims,
public.claim_evidence,
public.claim_edges,
public.sources,
public.personas,
public.strategies,
public.beliefs,
public.blindspots,
public.agent_roles,
public.peer_models,
public.behavioral_rules,
public.contributor_rules,
public.reasoning_tools,
public.governance_gates,
kb_stage.kb_proposals
to leoclean_kb_runtime;
-- The function owner is a dedicated NOLOGIN role. Grant only the columns the
-- function reads/inserts. CREATE is temporary and is revoked immediately after
-- ownership is assigned.
grant usage, create on schema kb_stage to leoclean_kb_stage_owner;
grant usage on schema public to leoclean_kb_stage_owner;
grant select (id, handle) on public.agents to leoclean_kb_stage_owner;
grant select on kb_stage.kb_proposals to leoclean_kb_stage_owner;
grant insert (
proposal_type,
status,
proposed_by_handle,
proposed_by_agent_id,
channel,
source_ref,
rationale,
payload
) on kb_stage.kb_proposals to leoclean_kb_stage_owner;
-- Remove the prior caller-supplied-identity overload before installing the
-- session-bound form. A runtime caller can only stage as canonical agent Leo.
drop function if exists kb_stage.stage_leoclean_proposal(text, text, text, text, text, jsonb);
create or replace function kb_stage.stage_leoclean_proposal(
p_proposal_type text,
p_channel text,
p_source_ref text,
p_rationale text,
p_payload jsonb
) returns jsonb
language plpgsql
security definer
set search_path = pg_catalog, pg_temp
as $function$
declare
staged kb_stage.kb_proposals%rowtype;
proposer_id uuid;
begin
if session_user <> 'leoclean_kb_runtime' then
raise exception 'stage_leoclean_proposal is restricted to leoclean_kb_runtime'
using errcode = '42501';
end if;
if p_proposal_type not in ('revise_claim', 'revise_strategy', 'add_edge') then
raise exception 'unsupported Leo proposal type: %', p_proposal_type using errcode = '22023';
end if;
if nullif(btrim(p_source_ref), '') is null then
raise exception 'source_ref is required' using errcode = '22023';
end if;
if nullif(btrim(p_rationale), '') is null then
raise exception 'rationale is required' using errcode = '22023';
end if;
if p_payload is null or jsonb_typeof(p_payload) <> 'object' then
raise exception 'proposal payload must be a JSON object' using errcode = '22023';
end if;
select agent.id
into proposer_id
from public.agents as agent
where agent.handle = 'leo';
if proposer_id is null then
raise exception 'canonical Leo agent row is required' using errcode = '23503';
end if;
insert into kb_stage.kb_proposals (
proposal_type,
status,
proposed_by_handle,
proposed_by_agent_id,
channel,
source_ref,
rationale,
payload
) values (
p_proposal_type,
'pending_review',
'leo',
proposer_id,
coalesce(nullif(p_channel, ''), 'telegram'),
p_source_ref,
p_rationale,
p_payload
)
returning * into staged;
return to_jsonb(staged);
end
$function$;
alter function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb)
owner to leoclean_kb_stage_owner;
revoke create on schema kb_stage from leoclean_kb_stage_owner;
-- Normalize explicit ACL entries left by CREATE OR REPLACE or an earlier grant.
revoke all on function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb)
from public;
select format(
'revoke all on function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb) from %I',
grantee.rolname
)
from pg_catalog.pg_proc function_row
cross join lateral pg_catalog.aclexplode(
coalesce(
function_row.proacl,
pg_catalog.acldefault('f', function_row.proowner)
)
) as acl
join pg_catalog.pg_roles grantee on grantee.oid = acl.grantee
where function_row.oid = 'kb_stage.stage_leoclean_proposal(text,text,text,text,jsonb)'::pg_catalog.regprocedure
and grantee.rolname <> 'leoclean_kb_stage_owner'
\gexec
grant execute on function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb)
to leoclean_kb_runtime;
select format('revoke leoclean_kb_stage_owner from %I', current_user)
where current_user <> 'leoclean_kb_stage_owner'
\gexec
do $verification$
declare
unexpected text;
runtime_oid oid := 'leoclean_kb_runtime'::pg_catalog.regrole::oid;
owner_oid oid := 'leoclean_kb_stage_owner'::pg_catalog.regrole::oid;
stage_function oid := 'kb_stage.stage_leoclean_proposal(text,text,text,text,jsonb)'::pg_catalog.regprocedure::oid;
begin
if exists (
select 1
from pg_catalog.pg_roles role_row
where role_row.rolname = 'leoclean_kb_runtime'
and (role_row.rolcanlogin
or role_row.rolsuper
or role_row.rolcreatedb
or role_row.rolcreaterole
or role_row.rolinherit
or role_row.rolreplication
or role_row.rolbypassrls
or role_row.rolconnlimit <> 8)
) then
raise exception 'leoclean_kb_runtime has unsafe provisioning role attributes';
end if;
if exists (
select 1
from pg_catalog.pg_roles role_row
where role_row.rolname = 'leoclean_kb_stage_owner'
and (role_row.rolcanlogin
or role_row.rolsuper
or role_row.rolcreatedb
or role_row.rolcreaterole
or role_row.rolinherit
or role_row.rolreplication
or role_row.rolbypassrls
or role_row.rolconnlimit <> -1)
) then
raise exception 'leoclean_kb_stage_owner has unsafe role attributes';
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I->%I', granted_role.rolname, member_role.rolname),
', '
order by granted_role.rolname, member_role.rolname
)
into unexpected
from pg_catalog.pg_auth_members membership
join pg_catalog.pg_roles granted_role on granted_role.oid = membership.roleid
join pg_catalog.pg_roles member_role on member_role.oid = membership.member
where membership.roleid in (runtime_oid, owner_oid)
or membership.member in (runtime_oid, owner_oid);
if unexpected is not null then
raise exception 'scoped Leo roles retain role memberships: %', unexpected;
end if;
if not exists (
select 1
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
where namespace.nspname = 'kb_stage'
and relation.relname = 'kb_proposals'
and relation.relkind = 'r'
and relation.relpersistence = 'p'
and not relation.relrowsecurity
and not relation.relforcerowsecurity
) then
raise exception 'kb_stage.kb_proposals is not the reviewed permanent base table';
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I:%s', namespace.nspname, relation.relname, relation.relkind),
', '
order by namespace.nspname, relation.relname
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
where (namespace.nspname, relation.relname) in (
('public', 'agents'), ('public', 'claims'), ('public', 'claim_evidence'),
('public', 'claim_edges'), ('public', 'sources'), ('public', 'personas'),
('public', 'strategies'), ('public', 'beliefs'), ('public', 'blindspots'),
('public', 'agent_roles'), ('public', 'peer_models'), ('public', 'behavioral_rules'),
('public', 'contributor_rules'), ('public', 'reasoning_tools'),
('public', 'governance_gates'), ('kb_stage', 'kb_proposals')
)
and relation.relkind <> 'r';
if unexpected is not null then
raise exception 'Leo read allowlist contains a non-base relation: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%s->%s', inheritance.inhparent::pg_catalog.regclass, inheritance.inhrelid::pg_catalog.regclass),
', '
)
into unexpected
from pg_catalog.pg_inherits inheritance
where inheritance.inhparent in (
'public.agents'::pg_catalog.regclass, 'public.claims'::pg_catalog.regclass,
'public.claim_evidence'::pg_catalog.regclass, 'public.claim_edges'::pg_catalog.regclass,
'public.sources'::pg_catalog.regclass, 'public.personas'::pg_catalog.regclass,
'public.strategies'::pg_catalog.regclass, 'public.beliefs'::pg_catalog.regclass,
'public.blindspots'::pg_catalog.regclass, 'public.agent_roles'::pg_catalog.regclass,
'public.peer_models'::pg_catalog.regclass, 'public.behavioral_rules'::pg_catalog.regclass,
'public.contributor_rules'::pg_catalog.regclass, 'public.reasoning_tools'::pg_catalog.regclass,
'public.governance_gates'::pg_catalog.regclass, 'kb_stage.kb_proposals'::pg_catalog.regclass
)
or inheritance.inhrelid in (
'public.agents'::pg_catalog.regclass, 'public.claims'::pg_catalog.regclass,
'public.claim_evidence'::pg_catalog.regclass, 'public.claim_edges'::pg_catalog.regclass,
'public.sources'::pg_catalog.regclass, 'public.personas'::pg_catalog.regclass,
'public.strategies'::pg_catalog.regclass, 'public.beliefs'::pg_catalog.regclass,
'public.blindspots'::pg_catalog.regclass, 'public.agent_roles'::pg_catalog.regclass,
'public.peer_models'::pg_catalog.regclass, 'public.behavioral_rules'::pg_catalog.regclass,
'public.contributor_rules'::pg_catalog.regclass, 'public.reasoning_tools'::pg_catalog.regclass,
'public.governance_gates'::pg_catalog.regclass, 'kb_stage.kb_proposals'::pg_catalog.regclass
);
if unexpected is not null then
raise exception 'Leo read allowlist has inheritance edges: %', unexpected;
end if;
with expected(ordinal, attname, typname, not_null, has_default, collated) as (
values
(1, 'id', 'uuid', true, true, false),
(2, 'proposal_type', 'text', true, false, true),
(3, 'status', 'text', true, true, true),
(4, 'proposed_by_handle', 'text', false, false, true),
(5, 'proposed_by_agent_id', 'uuid', false, false, false),
(6, 'channel', 'text', true, true, true),
(7, 'source_ref', 'text', false, false, true),
(8, 'rationale', 'text', true, false, true),
(9, 'payload', 'jsonb', true, false, false),
(10, 'reviewed_by_handle', 'text', false, false, true),
(11, 'reviewed_by_agent_id', 'uuid', false, false, false),
(12, 'reviewed_at', 'timestamptz', false, false, false),
(13, 'review_note', 'text', false, false, true),
(14, 'applied_by_handle', 'text', false, false, true),
(15, 'applied_by_agent_id', 'uuid', false, false, false),
(16, 'applied_at', 'timestamptz', false, false, false),
(17, 'created_at', 'timestamptz', true, true, false),
(18, 'updated_at', 'timestamptz', true, true, false)
), actual as (
select attribute.attnum::int as ordinal,
attribute.attname,
type_row.typname,
attribute.attnotnull as not_null,
attribute.atthasdef as has_default,
attribute.attidentity,
attribute.attgenerated,
attribute.atttypmod,
type_namespace.nspname as type_namespace,
attribute.attcollation = 'pg_catalog.default'::pg_catalog.regcollation as collated
from pg_catalog.pg_attribute attribute
join pg_catalog.pg_type type_row on type_row.oid = attribute.atttypid
join pg_catalog.pg_namespace type_namespace on type_namespace.oid = type_row.typnamespace
where attribute.attrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and attribute.attnum > 0
and not attribute.attisdropped
)
select pg_catalog.string_agg(coalesce(expected.attname, actual.attname), ', ' order by coalesce(expected.ordinal, actual.ordinal))
into unexpected
from expected
full join actual using (ordinal, attname)
where expected.ordinal is null
or actual.ordinal is null
or expected.typname is distinct from actual.typname
or expected.not_null is distinct from actual.not_null
or expected.has_default is distinct from actual.has_default
or expected.collated is distinct from actual.collated
or actual.attidentity <> ''
or actual.attgenerated <> ''
or actual.atttypmod <> -1
or actual.type_namespace <> 'pg_catalog';
if unexpected is not null then
raise exception 'kb_stage.kb_proposals column contract drifted: %', unexpected;
end if;
if exists (
select 1
from pg_catalog.pg_trigger trigger_row
where trigger_row.tgrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and not trigger_row.tgisinternal
) or exists (
select 1
from pg_catalog.pg_rewrite rewrite_row
where rewrite_row.ev_class = 'kb_stage.kb_proposals'::pg_catalog.regclass
) or exists (
select 1
from pg_catalog.pg_policy policy_row
where policy_row.polrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
) or exists (
select 1
from pg_catalog.pg_attribute attribute
where attribute.attrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and attribute.attnum > 0
and not attribute.attisdropped
and attribute.attgenerated <> ''
) then
raise exception 'kb_stage.kb_proposals has unsafe trigger/rule/RLS/generated topology';
end if;
with expected(attname, expression) as (
values
('id', 'gen_random_uuid()'),
('status', '''pending_review''::text'),
('channel', '''cli''::text'),
('created_at', 'now()'),
('updated_at', 'now()')
), actual as (
select attribute.attname,
pg_catalog.pg_get_expr(default_row.adbin, default_row.adrelid) as expression
from pg_catalog.pg_attribute attribute
join pg_catalog.pg_attrdef default_row
on default_row.adrelid = attribute.attrelid
and default_row.adnum = attribute.attnum
where attribute.attrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and attribute.attnum > 0
and not attribute.attisdropped
)
select pg_catalog.string_agg(coalesce(expected.attname, actual.attname), ', ')
into unexpected
from expected
full join actual using (attname)
where expected.expression is distinct from actual.expression;
if unexpected is not null then
raise exception 'kb_stage.kb_proposals default topology drifted: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%s:%s', dependency.refclassid::pg_catalog.regclass, dependency.refobjid),
', '
)
into unexpected
from pg_catalog.pg_attrdef default_row
join pg_catalog.pg_depend dependency
on dependency.classid = 'pg_catalog.pg_attrdef'::pg_catalog.regclass
and dependency.objid = default_row.oid
where default_row.adrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and (
dependency.refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass
and dependency.refobjid not in (
'pg_catalog.gen_random_uuid()'::pg_catalog.regprocedure,
'pg_catalog.now()'::pg_catalog.regprocedure
)
or dependency.refclassid = 'pg_catalog.pg_type'::pg_catalog.regclass
and not exists (
select 1
from pg_catalog.pg_type type_row
join pg_catalog.pg_namespace namespace on namespace.oid = type_row.typnamespace
where type_row.oid = dependency.refobjid
and namespace.nspname = 'pg_catalog'
)
or dependency.refclassid = 'pg_catalog.pg_operator'::pg_catalog.regclass
and not exists (
select 1
from pg_catalog.pg_operator operator_row
join pg_catalog.pg_namespace namespace on namespace.oid = operator_row.oprnamespace
where operator_row.oid = dependency.refobjid
and namespace.nspname = 'pg_catalog'
)
or dependency.refclassid = 'pg_catalog.pg_collation'::pg_catalog.regclass
and not exists (
select 1
from pg_catalog.pg_collation collation_row
join pg_catalog.pg_namespace namespace on namespace.oid = collation_row.collnamespace
where collation_row.oid = dependency.refobjid
and namespace.nspname = 'pg_catalog'
)
);
if unexpected is not null then
raise exception 'kb_stage.kb_proposals defaults depend on unreviewed objects: %', unexpected;
end if;
if (
select pg_catalog.count(*) <> 6
or pg_catalog.count(*) filter (
where (constraint_row.conname, constraint_row.contype) in (
('kb_proposals_pkey', 'p'),
('kb_proposals_proposal_type_check', 'c'),
('kb_proposals_status_check', 'c'),
('kb_proposals_applied_by_agent_id_fkey', 'f'),
('kb_proposals_proposed_by_agent_id_fkey', 'f'),
('kb_proposals_reviewed_by_agent_id_fkey', 'f')
)
) <> 6
from pg_catalog.pg_constraint constraint_row
where constraint_row.conrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
) or exists (
select 1
from pg_catalog.pg_constraint constraint_row
join pg_catalog.pg_depend dependency
on dependency.classid = 'pg_catalog.pg_constraint'::pg_catalog.regclass
and dependency.objid = constraint_row.oid
and dependency.refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass
join pg_catalog.pg_proc function_row on function_row.oid = dependency.refobjid
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where constraint_row.conrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and namespace.nspname <> 'pg_catalog'
) or exists (
select 1
from pg_catalog.pg_index index_row
where index_row.indrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and (
index_row.indexprs is not null
or (
index_row.indpred is not null
and pg_catalog.pg_get_expr(index_row.indpred, index_row.indrelid)
<> '(proposed_by_handle IS NOT NULL)'
)
)
) then
raise exception 'kb_stage.kb_proposals constraint/index topology drifted';
end if;
select pg_catalog.string_agg(
pg_catalog.format(
'%I:%s:%s:grantable=%s',
database_row.datname,
grantee.rolname,
acl.privilege_type,
acl.is_grantable
),
', '
order by database_row.datname, grantee.rolname, acl.privilege_type
)
into unexpected
from pg_catalog.pg_database database_row
cross join lateral pg_catalog.aclexplode(
coalesce(
database_row.datacl,
pg_catalog.acldefault('d', database_row.datdba)
)
) as acl
join pg_catalog.pg_roles grantee on grantee.oid = acl.grantee
where grantee.rolname in ('leoclean_kb_runtime', 'leoclean_kb_stage_owner')
and not (
database_row.datname = 'teleo_canonical'
and grantee.rolname = 'leoclean_kb_runtime'
and acl.privilege_type = 'CONNECT'
and not acl.is_grantable
);
if unexpected is not null then
raise exception 'scoped Leo roles retain unexpected direct database ACLs: %', unexpected;
end if;
select pg_catalog.string_agg(database_row.datname, ', ' order by database_row.datname)
into unexpected
from pg_catalog.pg_database database_row
where database_row.datname <> 'teleo_canonical'
and has_database_privilege('leoclean_kb_runtime', database_row.oid, 'CONNECT');
if unexpected is not null then
raise exception 'runtime CONNECT reaches a noncanonical database: %', unexpected;
end if;
select pg_catalog.string_agg(database_row.datname, ', ' order by database_row.datname)
into unexpected
from pg_catalog.pg_database database_row
where has_database_privilege('leoclean_kb_stage_owner', database_row.oid, 'CONNECT');
if unexpected is not null then
raise exception 'stage owner CONNECT reaches a database: %', unexpected;
end if;
select pg_catalog.string_agg(database_row.datname, ', ' order by database_row.datname)
into unexpected
from pg_catalog.pg_database database_row
cross join lateral pg_catalog.aclexplode(
coalesce(database_row.datacl, pg_catalog.acldefault('d', database_row.datdba))
) acl
where acl.grantee = 0
and acl.privilege_type = 'CONNECT';
if unexpected is not null then
raise exception 'PUBLIC retains database CONNECT: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%s:%s', setting_row.setdatabase, setting_row.setconfig),
', '
)
into unexpected
from pg_catalog.pg_db_role_setting setting_row
where setting_row.setrole in (runtime_oid, owner_oid)
and not (
setting_row.setrole = runtime_oid
and setting_row.setdatabase = (
select database_row.oid
from pg_catalog.pg_database database_row
where database_row.datname = 'teleo_canonical'
)
and pg_catalog.cardinality(setting_row.setconfig) = 3
and setting_row.setconfig @> array[
'search_path=pg_catalog, public, kb_stage',
'statement_timeout=15s',
'lock_timeout=2s'
]::text[]
);
if unexpected is not null or not exists (
select 1
from pg_catalog.pg_db_role_setting setting_row
where setting_row.setrole = runtime_oid
and setting_row.setdatabase = (
select database_row.oid
from pg_catalog.pg_database database_row
where database_row.datname = 'teleo_canonical'
)
and pg_catalog.cardinality(setting_row.setconfig) = 3
and setting_row.setconfig @> array[
'search_path=pg_catalog, public, kb_stage',
'statement_timeout=15s',
'lock_timeout=2s'
]::text[]
) then
raise exception 'scoped Leo role settings differ from the reviewed contract';
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I:%s', database_row.datname, scoped_role.name),
', '
order by database_row.datname, scoped_role.name
)
into unexpected
from pg_catalog.pg_database database_row
cross join (values ('leoclean_kb_runtime'), ('leoclean_kb_stage_owner')) scoped_role(name)
where has_database_privilege(scoped_role.name, database_row.oid, 'CREATE');
if unexpected is not null then
raise exception 'a scoped Leo role unexpectedly has database CREATE: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%s:%s:%s', dependency.classid::pg_catalog.regclass, dependency.objid, dependency.objsubid),
', '
)
into unexpected
from pg_catalog.pg_shdepend dependency
where dependency.refclassid = 'pg_catalog.pg_authid'::pg_catalog.regclass
and dependency.refobjid = runtime_oid
and dependency.deptype = 'o';
if unexpected is not null then
raise exception 'leoclean_kb_runtime unexpectedly owns database objects: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%s:%s:%s', dependency.classid::pg_catalog.regclass, dependency.objid, dependency.objsubid),
', '
)
into unexpected
from pg_catalog.pg_shdepend dependency
where dependency.refclassid = 'pg_catalog.pg_authid'::pg_catalog.regclass
and dependency.refobjid = owner_oid
and dependency.deptype = 'o'
and not (
dependency.dbid = (select database_row.oid from pg_catalog.pg_database database_row where database_row.datname = current_database())
and
dependency.classid = 'pg_catalog.pg_proc'::pg_catalog.regclass
and dependency.objid = stage_function
and dependency.objsubid = 0
);
if unexpected is not null then
raise exception 'leoclean_kb_stage_owner owns unexpected database objects: %', unexpected;
end if;
select pg_catalog.string_agg(metadata.oid::text, ', ' order by metadata.oid)
into unexpected
from pg_catalog.pg_largeobject_metadata metadata
where metadata.lomowner in (runtime_oid, owner_oid)
or exists (
select 1
from pg_catalog.aclexplode(
coalesce(metadata.lomacl, pg_catalog.acldefault('L', metadata.lomowner))
) acl
where acl.grantee in (0, runtime_oid, owner_oid)
and acl.privilege_type in ('SELECT', 'UPDATE')
);
if unexpected is not null then
raise exception 'scoped Leo roles retain large-object ownership or ACL reachability: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I(%s)', function_row.proname, pg_catalog.pg_get_function_identity_arguments(function_row.oid)),
', '
)
into unexpected
from pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where namespace.nspname = 'pg_catalog'
and function_row.proname in (
'lo_creat', 'lo_create', 'lo_export', 'lo_from_bytea', 'lo_import',
'lo_open', 'lo_put', 'lo_truncate', 'lo_truncate64', 'lo_unlink', 'lowrite'
)
and (
has_function_privilege('leoclean_kb_runtime', function_row.oid, 'EXECUTE')
or has_function_privilege('leoclean_kb_stage_owner', function_row.oid, 'EXECUTE')
);
if unexpected is not null then
raise exception 'PUBLIC or inherited large-object mutators remain executable: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I(%s)', function_row.proname, pg_catalog.pg_get_function_identity_arguments(function_row.oid)),
', '
order by function_row.proname, pg_catalog.pg_get_function_identity_arguments(function_row.oid)
)
into unexpected
from pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
cross join lateral pg_catalog.aclexplode(
coalesce(function_row.proacl, pg_catalog.acldefault('f', function_row.proowner))
) acl
where namespace.nspname = 'pg_catalog'
and function_row.proname in (
'lo_creat', 'lo_create', 'lo_export', 'lo_from_bytea', 'lo_import',
'lo_open', 'lo_put', 'lo_truncate', 'lo_truncate64', 'lo_unlink', 'lowrite'
)
and acl.grantee = 0
and acl.privilege_type = 'EXECUTE';
if unexpected is not null then
raise exception 'PUBLIC retains large-object mutator EXECUTE: %', unexpected;
end if;
select pg_catalog.string_agg(parameter_acl.parname, ', ' order by parameter_acl.parname)
into unexpected
from pg_catalog.pg_parameter_acl parameter_acl
where has_parameter_privilege('leoclean_kb_runtime', parameter_acl.parname, 'SET')
or has_parameter_privilege('leoclean_kb_runtime', parameter_acl.parname, 'ALTER SYSTEM')
or has_parameter_privilege('leoclean_kb_stage_owner', parameter_acl.parname, 'SET')
or has_parameter_privilege('leoclean_kb_stage_owner', parameter_acl.parname, 'ALTER SYSTEM');
if unexpected is not null then
raise exception 'scoped Leo roles retain parameter privileges: %', unexpected;
end if;
if has_schema_privilege('leoclean_kb_runtime', 'public', 'CREATE')
or has_schema_privilege('leoclean_kb_runtime', 'kb_stage', 'CREATE')
or has_schema_privilege('leoclean_kb_stage_owner', 'public', 'CREATE')
or has_schema_privilege('leoclean_kb_stage_owner', 'kb_stage', 'CREATE') then
raise exception 'a scoped Leo role unexpectedly has schema CREATE';
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I:%s', namespace.nspname, relation.relname, privilege.name),
', '
order by namespace.nspname, relation.relname, privilege.name
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
cross join (values ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) privilege(name)
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and has_table_privilege('leoclean_kb_runtime', relation.oid, privilege.name);
if unexpected is not null then
raise exception 'leoclean_kb_runtime unexpectedly has table-level DML: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I.%I:%s', namespace.nspname, relation.relname, attribute.attname, privilege.name),
', '
order by namespace.nspname, relation.relname, attribute.attnum, privilege.name
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_attribute attribute on attribute.attrelid = relation.oid
cross join (values ('INSERT'), ('UPDATE'), ('REFERENCES')) privilege(name)
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
and has_column_privilege('leoclean_kb_runtime', relation.oid, attribute.attnum, privilege.name);
if unexpected is not null then
raise exception 'leoclean_kb_runtime unexpectedly has column-level DML: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I', namespace.nspname, relation.relname),
', '
order by namespace.nspname, relation.relname
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and has_table_privilege('leoclean_kb_runtime', relation.oid, 'SELECT')
and (namespace.nspname, relation.relname) not in (
('public', 'agents'),
('public', 'claims'),
('public', 'claim_evidence'),
('public', 'claim_edges'),
('public', 'sources'),
('public', 'personas'),
('public', 'strategies'),
('public', 'beliefs'),
('public', 'blindspots'),
('public', 'agent_roles'),
('public', 'peer_models'),
('public', 'behavioral_rules'),
('public', 'contributor_rules'),
('public', 'reasoning_tools'),
('public', 'governance_gates'),
('kb_stage', 'kb_proposals')
);
if unexpected is not null then
raise exception 'leoclean_kb_runtime can SELECT outside its table allowlist: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I.%I', namespace.nspname, relation.relname, attribute.attname),
', '
order by namespace.nspname, relation.relname, attribute.attnum
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_attribute attribute on attribute.attrelid = relation.oid
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
and has_column_privilege('leoclean_kb_runtime', relation.oid, attribute.attnum, 'SELECT')
and (namespace.nspname, relation.relname) not in (
('public', 'agents'),
('public', 'claims'),
('public', 'claim_evidence'),
('public', 'claim_edges'),
('public', 'sources'),
('public', 'personas'),
('public', 'strategies'),
('public', 'beliefs'),
('public', 'blindspots'),
('public', 'agent_roles'),
('public', 'peer_models'),
('public', 'behavioral_rules'),
('public', 'contributor_rules'),
('public', 'reasoning_tools'),
('public', 'governance_gates'),
('kb_stage', 'kb_proposals')
);
if unexpected is not null then
raise exception 'leoclean_kb_runtime has column SELECT outside its allowlist: %', unexpected;
end if;
if has_table_privilege('leoclean_kb_stage_owner', 'public.agents', 'SELECT')
or not has_column_privilege('leoclean_kb_stage_owner', 'public.agents', 'id', 'SELECT')
or not has_column_privilege('leoclean_kb_stage_owner', 'public.agents', 'handle', 'SELECT')
or not has_table_privilege('leoclean_kb_stage_owner', 'kb_stage.kb_proposals', 'SELECT')
or has_table_privilege('leoclean_kb_stage_owner', 'kb_stage.kb_proposals', 'INSERT') then
raise exception 'leoclean_kb_stage_owner does not have the exact read/insert grant shape';
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I.%I', namespace.nspname, relation.relname, attribute.attname),
', '
order by namespace.nspname, relation.relname, attribute.attnum
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_attribute attribute on attribute.attrelid = relation.oid
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
and has_column_privilege('leoclean_kb_stage_owner', relation.oid, attribute.attnum, 'INSERT')
and not (
namespace.nspname = 'kb_stage'
and relation.relname = 'kb_proposals'
and attribute.attname in (
'proposal_type',
'status',
'proposed_by_handle',
'proposed_by_agent_id',
'channel',
'source_ref',
'rationale',
'payload'
)
);
if unexpected is not null then
raise exception 'leoclean_kb_stage_owner can INSERT unexpected columns: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I:%s', namespace.nspname, relation.relname, privilege.name),
', '
order by namespace.nspname, relation.relname, privilege.name
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
cross join (values ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) privilege(name)
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and has_table_privilege('leoclean_kb_stage_owner', relation.oid, privilege.name);
if unexpected is not null then
raise exception 'leoclean_kb_stage_owner unexpectedly has table-level DML: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I.%I:%s', namespace.nspname, relation.relname, attribute.attname, privilege.name),
', '
order by namespace.nspname, relation.relname, attribute.attnum, privilege.name
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_attribute attribute on attribute.attrelid = relation.oid
cross join (values ('UPDATE'), ('REFERENCES')) privilege(name)
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
and has_column_privilege('leoclean_kb_stage_owner', relation.oid, attribute.attnum, privilege.name);
if unexpected is not null then
raise exception 'leoclean_kb_stage_owner unexpectedly has column-level DML: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I.%I', namespace.nspname, relation.relname, attribute.attname),
', '
order by namespace.nspname, relation.relname, attribute.attnum
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_attribute attribute on attribute.attrelid = relation.oid
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
and has_column_privilege('leoclean_kb_stage_owner', relation.oid, attribute.attnum, 'SELECT')
and not (
(namespace.nspname = 'kb_stage' and relation.relname = 'kb_proposals')
or (
namespace.nspname = 'public'
and relation.relname = 'agents'
and attribute.attname in ('id', 'handle')
)
);
if unexpected is not null then
raise exception 'leoclean_kb_stage_owner can SELECT unexpected columns: %', unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I:%s:%s', namespace.nspname, relation.relname, scoped_role.name, privilege.name),
', '
order by namespace.nspname, relation.relname, scoped_role.name, privilege.name
)
into unexpected
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
cross join (values ('leoclean_kb_runtime'), ('leoclean_kb_stage_owner')) scoped_role(name)
cross join (values ('USAGE'), ('SELECT'), ('UPDATE')) privilege(name)
where namespace.nspname in ('public', 'kb_stage')
and relation.relkind = 'S'
and has_sequence_privilege(scoped_role.name, relation.oid, privilege.name);
if unexpected is not null then
raise exception 'a scoped Leo role unexpectedly has sequence privileges: %', unexpected;
end if;
if exists (
select 1
from pg_catalog.pg_attribute attribute
where attribute.attrelid = 'kb_stage.kb_proposals'::pg_catalog.regclass
and attribute.attname in (
'proposal_type',
'status',
'proposed_by_handle',
'proposed_by_agent_id',
'channel',
'source_ref',
'rationale',
'payload'
)
and not has_column_privilege(
'leoclean_kb_stage_owner',
attribute.attrelid,
attribute.attnum,
'INSERT'
)
) then
raise exception 'leoclean_kb_stage_owner is missing a required INSERT column grant';
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I(%s)', namespace.nspname, function_row.proname, pg_catalog.pg_get_function_identity_arguments(function_row.oid)),
', '
)
into unexpected
from pg_catalog.pg_proc function_row
join pg_catalog.pg_namespace namespace on namespace.oid = function_row.pronamespace
where namespace.nspname in ('public', 'kb_stage')
and function_row.prosecdef
and function_row.oid <> stage_function
and has_function_privilege('leoclean_kb_runtime', function_row.oid, 'EXECUTE');
if unexpected is not null then
raise exception 'leoclean_kb_runtime can execute unexpected SECURITY DEFINER functions: %', unexpected;
end if;
if not exists (
select 1
from pg_catalog.pg_proc function_row
where function_row.oid = stage_function
and function_row.prosecdef
and function_row.proowner = owner_oid
and function_row.proconfig = array['search_path=pg_catalog, pg_temp']::text[]
) then
raise exception 'stage_leoclean_proposal owner/security/search_path contract is invalid';
end if;
select pg_catalog.string_agg(
pg_catalog.format(
'grantee=%s privilege=%s grantable=%s',
acl.grantee,
acl.privilege_type,
acl.is_grantable
),
', '
)
into unexpected
from pg_catalog.pg_proc function_row
cross join lateral pg_catalog.aclexplode(
coalesce(
function_row.proacl,
pg_catalog.acldefault('f', function_row.proowner)
)
) as acl
where function_row.oid = stage_function
and not (
acl.grantee in (runtime_oid, owner_oid)
and acl.privilege_type = 'EXECUTE'
and (acl.grantee = owner_oid or not acl.is_grantable)
);
if unexpected is not null then
raise exception 'stage_leoclean_proposal has unexpected ACL entries: %', unexpected;
end if;
if not has_function_privilege(
'leoclean_kb_runtime',
'kb_stage.stage_leoclean_proposal(text,text,text,text,jsonb)',
'EXECUTE'
) then
raise exception 'leoclean_kb_runtime cannot execute stage_leoclean_proposal';
end if;
end
$verification$;
-- LOGIN is the last state change in the same transaction as every database ACL,
-- canonical privilege, large-object, and topology assertion. Any failure rolls
-- back the complete privilege migration and leaves the role NOLOGIN.
alter role leoclean_kb_runtime
with login nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls connection limit 8;
do $login_verification$
begin
if exists (
select 1
from pg_catalog.pg_roles role_row
where role_row.rolname = 'leoclean_kb_runtime'
and (
not role_row.rolcanlogin
or role_row.rolsuper
or role_row.rolcreatedb
or role_row.rolcreaterole
or role_row.rolinherit
or role_row.rolreplication
or role_row.rolbypassrls
or role_row.rolconnlimit <> 8
)
) then
raise exception 'leoclean_kb_runtime final login attributes are unsafe';
end if;
end
$login_verification$;
commit;