teleo-infrastructure/ops/gcp_leoclean_runtime_role.sql

847 lines
34 KiB
PL/PgSQL

\set ON_ERROR_STOP on
\getenv runtime_password TELEO_LEOCLEAN_DB_PASSWORD
-- One-time GCP staging provisioning for Leo's Cloud SQL identity. The password
-- is supplied only through the process environment and is never stored here.
--
-- 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.
select 'create role leoclean_kb_runtime login 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
select format('alter role leoclean_kb_runtime password %L', :'runtime_password')
\gexec
alter role leoclean_kb_runtime
with login 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;
alter role leoclean_kb_runtime reset all;
alter role leoclean_kb_stage_owner reset all;
-- NOINHERIT does not prevent SET ROLE. Remove every membership edge in either
-- direction so neither scoped principal can reach, or be reached through, a
-- broader role left behind by an earlier deployment.
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
revoke all privileges on database teleo_canonical from leoclean_kb_runtime;
revoke all privileges on database teleo_canonical from leoclean_kb_stage_owner;
revoke all privileges on database teleo_kb from leoclean_kb_runtime;
revoke all privileges on database teleo_kb from leoclean_kb_stage_owner;
grant connect on database teleo_canonical to leoclean_kb_runtime;
-- 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;
-- 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;
-- 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 (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 has unsafe 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;
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 database_row.datname in ('teleo_canonical', 'teleo_kb')
and 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;
if has_database_privilege('leoclean_kb_runtime', 'teleo_canonical', 'CREATE')
or has_database_privilege('leoclean_kb_runtime', 'teleo_kb', 'CREATE')
or has_database_privilege('leoclean_kb_stage_owner', 'teleo_canonical', 'CREATE')
or has_database_privilege('leoclean_kb_stage_owner', 'teleo_kb', 'CREATE') then
raise exception 'a scoped Leo role unexpectedly has database CREATE';
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;
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$;
commit;
-- The legacy restore database is not an audit fallback for the scoped runtime.
-- Strip direct ACLs from both scoped roles and fail if PUBLIC/group grants still
-- make any teleo_restore relation reachable.
\connect teleo_kb
begin;
select format('revoke all on schema %I from leoclean_kb_runtime, leoclean_kb_stage_owner', namespace.nspname)
from pg_catalog.pg_namespace namespace
where namespace.nspname = 'teleo_restore'
\gexec
select format('revoke all privileges on all tables in schema %I from leoclean_kb_runtime, leoclean_kb_stage_owner', namespace.nspname)
from pg_catalog.pg_namespace namespace
where namespace.nspname = 'teleo_restore'
\gexec
select format('revoke all privileges on all sequences in schema %I from leoclean_kb_runtime, leoclean_kb_stage_owner', namespace.nspname)
from pg_catalog.pg_namespace namespace
where namespace.nspname = 'teleo_restore'
\gexec
select format('revoke all privileges on all functions in schema %I from leoclean_kb_runtime, leoclean_kb_stage_owner', namespace.nspname)
from pg_catalog.pg_namespace namespace
where namespace.nspname = 'teleo_restore'
\gexec
select format('revoke all privileges on all procedures in schema %I from leoclean_kb_runtime, leoclean_kb_stage_owner', namespace.nspname)
from pg_catalog.pg_namespace namespace
where namespace.nspname = 'teleo_restore'
\gexec
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 = 'teleo_restore'
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
do $audit_verification$
declare
unexpected text;
scoped_role text;
begin
foreach scoped_role in array array['leoclean_kb_runtime', 'leoclean_kb_stage_owner'] loop
if to_regnamespace('teleo_restore') is not null
and (has_schema_privilege(scoped_role, 'teleo_restore', 'USAGE')
or has_schema_privilege(scoped_role, 'teleo_restore', 'CREATE')) then
raise exception '% unexpectedly has teleo_restore schema access', scoped_role;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I:%s', namespace.nspname, relation.relname, privilege.name),
', '
order by 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 ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')
) privilege(name)
where namespace.nspname = 'teleo_restore'
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and has_table_privilege(scoped_role, relation.oid, privilege.name);
if unexpected is not null then
raise exception '% unexpectedly has teleo_restore table access: %', scoped_role, 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 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 ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) privilege(name)
where namespace.nspname = 'teleo_restore'
and relation.relkind in ('r', 'p', 'v', 'm', 'f')
and attribute.attnum > 0
and not attribute.attisdropped
and has_column_privilege(scoped_role, relation.oid, attribute.attnum, privilege.name);
if unexpected is not null then
raise exception '% unexpectedly has teleo_restore column access: %', scoped_role, unexpected;
end if;
select pg_catalog.string_agg(
pg_catalog.format('%I.%I:%s', namespace.nspname, relation.relname, privilege.name),
', '
order by 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 ('USAGE'), ('SELECT'), ('UPDATE')) privilege(name)
where namespace.nspname = 'teleo_restore'
and relation.relkind = 'S'
and has_sequence_privilege(scoped_role, relation.oid, privilege.name);
if unexpected is not null then
raise exception '% unexpectedly has teleo_restore sequence access: %', scoped_role, unexpected;
end if;
end loop;
end
$audit_verification$;
commit;
\connect teleo_canonical
select jsonb_build_object(
'role', rolname,
'superuser', rolsuper,
'create_db', rolcreatedb,
'create_role', rolcreaterole,
'inherit', rolinherit,
'replication', rolreplication,
'bypass_rls', rolbypassrls,
'has_role_memberships', exists (
select 1
from pg_catalog.pg_auth_members membership
where membership.roleid = pg_catalog.pg_roles.oid
or membership.member = pg_catalog.pg_roles.oid
),
'can_select_claims', has_table_privilege(rolname, 'public.claims', 'SELECT'),
'can_select_proposals', has_table_privilege(rolname, 'kb_stage.kb_proposals', 'SELECT'),
'can_insert_proposals_directly', has_table_privilege(rolname, 'kb_stage.kb_proposals', 'INSERT'),
'can_create_database_objects', has_database_privilege(rolname, 'teleo_canonical', 'CREATE'),
'can_create_temp_objects', has_database_privilege(rolname, 'teleo_canonical', 'TEMP'),
'can_stage_proposal', has_function_privilege(
rolname,
'kb_stage.stage_leoclean_proposal(text,text,text,text,jsonb)',
'EXECUTE'
)
)::text
from pg_catalog.pg_roles
where rolname = 'leoclean_kb_runtime';