@consiliency/agent-board-schema 1.56.0 → 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fixtures/already-applied.json +8 -0
- package/migrations/20261007000100_agent_board_onboard_requests.sql +139 -0
- package/migrations/20261008000100_agent_board_hosted_delegates.sql +3152 -0
- package/package.json +1 -1
- package/schema-manifest.json +21 -3
- package/src/tooling.test.mjs +8 -2
- package/tests/agent_board_atomic_fleet_onboarding.test.sql +13 -0
- package/tests/agent_board_consent_emission.test.sql +4 -2
- package/tests/agent_board_delegate_role_class.test.sql +736 -0
- package/tests/agent_board_federated_identity_injective_slug.test.sql +5 -2
- package/tests/agent_board_fedsession_stored_identity_gate.test.sql +71 -14
- package/tests/agent_board_fk_lock_edges.test.sql +9 -0
- package/tests/agent_board_hosted_delegates.test.sql +1134 -0
- package/tests/agent_board_ledger_authority.test.sql +34 -5
- package/tests/agent_board_membership_current_row_class.test.sql +3 -1
- package/tests/agent_board_onboard_requests.test.sql +353 -0
- package/tests/agent_board_rowid.test.sql +18 -5
- package/tests/agent_board_signer_lifecycle.test.sql +3 -0
- package/tests/agent_board_write_enforcement_class.test.sql +8 -3
- package/tests/catalog/function_execute_privileges.json +278 -2
- package/tests/catalog/p_metadata_parameters.json +48 -0
- package/tests/isolation/expected/hosted_delegate_exchange_race.out +93 -0
- package/tests/isolation/expected/hosted_delegate_first_exchange_race.out +129 -0
- package/tests/isolation/expected/hosted_delegate_owner_provisioning_race.out +91 -0
- package/tests/isolation/expected/hosted_delegate_owner_revoke_race.out +137 -0
- package/tests/isolation/expected/hosted_delegate_revoke_race.out +87 -0
- package/tests/isolation/expected/hosted_delegate_withdraw_evict_race.out +235 -0
- package/tests/isolation/specs/hosted_delegate_exchange_race.spec +64 -0
- package/tests/isolation/specs/hosted_delegate_first_exchange_race.spec +72 -0
- package/tests/isolation/specs/hosted_delegate_owner_provisioning_race.spec +73 -0
- package/tests/isolation/specs/hosted_delegate_owner_revoke_race.spec +93 -0
- package/tests/isolation/specs/hosted_delegate_revoke_race.spec +59 -0
- package/tests/isolation/specs/hosted_delegate_withdraw_evict_race.spec +145 -0
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
-- HOSTED (v11) SL-2 pgTAP: the agent_board_delegate role, as CLASSES derived from the catalog
|
|
2
|
+
-- (specs/agent-client-contract.md, HOSTED, "Class assertions SL-2 must write" and "What stays
|
|
3
|
+
-- refused for a delegate"). Nothing here is a hand list of the population: each class is read
|
|
4
|
+
-- from pg_proc / pg_class / pg_policy / pg_depend or from agent_board.delegate_allowed_operations,
|
|
5
|
+
-- so a new function, relation, grant or policy fails AND NAMES ITSELF.
|
|
6
|
+
--
|
|
7
|
+
-- Where an expected value is written here, it is the frozen contract value (the policy
|
|
8
|
+
-- predicates, the eight agents columns, a derived population named positively so a new member
|
|
9
|
+
-- shows up as a diff), never the population an assertion iterates over.
|
|
10
|
+
--
|
|
11
|
+
-- The zero-rows matrix (section 9) SWITCHES ROLE to agent_board_delegate. Every negative case
|
|
12
|
+
-- is paired with the same kind of row on a board where the delegate is active, so a predicate
|
|
13
|
+
-- that returns false everywhere fails too.
|
|
14
|
+
create extension if not exists pgtap with schema extensions;
|
|
15
|
+
set search_path = extensions, public, agent_board;
|
|
16
|
+
|
|
17
|
+
begin;
|
|
18
|
+
|
|
19
|
+
select plan(43);
|
|
20
|
+
|
|
21
|
+
-- ===========================================================================
|
|
22
|
+
-- 1. The role itself
|
|
23
|
+
-- ===========================================================================
|
|
24
|
+
-- 1
|
|
25
|
+
select is(
|
|
26
|
+
(select rolcanlogin::text || '/' || rolsuper::text || '/' || rolbypassrls::text || '/' || rolinherit::text
|
|
27
|
+
|| '/' || rolcreaterole::text || '/' || rolcreatedb::text
|
|
28
|
+
from pg_roles where rolname = 'agent_board_delegate'),
|
|
29
|
+
'false/false/false/false/false/false',
|
|
30
|
+
'agent_board_delegate: NOLOGIN, not a superuser, no BYPASSRLS, NOINHERIT, no CREATEROLE/CREATEDB');
|
|
31
|
+
-- 2
|
|
32
|
+
select is(
|
|
33
|
+
(select count(*)::int from pg_auth_members where member = 'agent_board_delegate'::regrole),
|
|
34
|
+
0,
|
|
35
|
+
'agent_board_delegate is a member of NO role (never authenticated, which would inherit every authenticated grant)');
|
|
36
|
+
-- 3 -- who can BECOME it: only authenticator (where it exists). The PostgreSQL 16+ creator
|
|
37
|
+
-- grant (ADMIN only, no SET and no INHERIT) cannot switch to it and is not counted.
|
|
38
|
+
select is(
|
|
39
|
+
(select coalesce(string_agg(m.rolname, ',' order by m.rolname), '(none)')
|
|
40
|
+
from pg_auth_members am join pg_roles m on m.oid = am.member
|
|
41
|
+
where am.roleid = 'agent_board_delegate'::regrole and (am.set_option or am.inherit_option)),
|
|
42
|
+
case when exists (select 1 from pg_roles where rolname = 'authenticator') then 'authenticator' else '(none)' end,
|
|
43
|
+
'only authenticator can switch to agent_board_delegate');
|
|
44
|
+
-- 4
|
|
45
|
+
select ok(has_schema_privilege('agent_board_delegate', 'agent_board', 'USAGE'),
|
|
46
|
+
'agent_board_delegate has USAGE on schema agent_board');
|
|
47
|
+
|
|
48
|
+
-- ===========================================================================
|
|
49
|
+
-- 2. Function deny-by-default, over SECURITY DEFINER functions (IF-0-HOSTED-5)
|
|
50
|
+
-- ===========================================================================
|
|
51
|
+
create temp view _fn as
|
|
52
|
+
select p.oid, p.proname::text as name, p.proname || '(' || oidvectortypes(p.proargtypes) || ')' as signature, p.prosecdef
|
|
53
|
+
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
|
|
54
|
+
where n.nspname = 'agent_board';
|
|
55
|
+
-- 5 -- every listed function names exactly one function
|
|
56
|
+
select is(
|
|
57
|
+
(select coalesce(string_agg(o.kind || ':' || o.signature, ', ' order by o.signature), '(none)')
|
|
58
|
+
from agent_board.delegate_allowed_operations o
|
|
59
|
+
where o.kind in ('rpc', 'ambient_rpc', 'predicate')
|
|
60
|
+
and (select count(*) from _fn f where f.signature = o.signature) <> 1),
|
|
61
|
+
'(none)',
|
|
62
|
+
'every rpc/ambient_rpc/predicate entry of the allow set names exactly one agent_board function');
|
|
63
|
+
-- 6 -- THE CLASS: has_function_privilege iff listed, over every definer
|
|
64
|
+
select is(
|
|
65
|
+
(select coalesce(string_agg(f.signature || ' => ' ||
|
|
66
|
+
case when has_function_privilege('agent_board_delegate', f.oid, 'EXECUTE') then 'GRANTED, NOT LISTED' else 'LISTED, NOT GRANTED' end,
|
|
67
|
+
'; ' order by f.signature), '')
|
|
68
|
+
from _fn f
|
|
69
|
+
where f.prosecdef
|
|
70
|
+
and has_function_privilege('agent_board_delegate', f.oid, 'EXECUTE')
|
|
71
|
+
<> exists (select 1 from agent_board.delegate_allowed_operations o
|
|
72
|
+
where o.kind in ('rpc', 'ambient_rpc', 'predicate') and o.signature = f.signature)),
|
|
73
|
+
'',
|
|
74
|
+
'CLASS: agent_board_delegate can EXECUTE a SECURITY DEFINER function iff it is in delegate_allowed_operations');
|
|
75
|
+
-- 7 -- every listed function is a definer (a non-definer runs with the caller's rights and
|
|
76
|
+
-- needs no grant; listing one would hide what the role can really reach)
|
|
77
|
+
select is(
|
|
78
|
+
(select coalesce(string_agg(f.signature, ', ' order by f.signature), '(none)')
|
|
79
|
+
from _fn f join agent_board.delegate_allowed_operations o on o.signature = f.signature
|
|
80
|
+
where o.kind in ('rpc', 'ambient_rpc', 'predicate') and not f.prosecdef),
|
|
81
|
+
'(none)',
|
|
82
|
+
'every function in the allow set is SECURITY DEFINER');
|
|
83
|
+
-- 8 -- the allow set's function membership, named: the contract's first membership with the
|
|
84
|
+
-- three per-row board predicates replaced by _delegate_visible_board_ids() (InitPlan form,
|
|
85
|
+
-- authorised by the team lead; SL-8 amends the contract)
|
|
86
|
+
select is(
|
|
87
|
+
(select string_agg(kind || ':' || signature, ' | ' order by kind, signature)
|
|
88
|
+
from agent_board.delegate_allowed_operations where kind in ('rpc', 'ambient_rpc', 'predicate')),
|
|
89
|
+
'ambient_rpc:get_schema_version() | predicate:_delegate_visible_agent(uuid) | predicate:_delegate_visible_board_ids() | predicate:current_agent_id() | rpc:create_or_find_thread(uuid, text, text, text, jsonb) | rpc:post_board_message(uuid, uuid, text, text, text, text, text, text, text, jsonb) | rpc:post_board_message(uuid, uuid, uuid, text, text, text, text, text, jsonb) | rpc:post_message(uuid, uuid, text, text, uuid, jsonb)',
|
|
90
|
+
'the allow set''s functions are exactly the contract''s first membership (D4): read and post, nothing else');
|
|
91
|
+
|
|
92
|
+
-- ===========================================================================
|
|
93
|
+
-- 3. Read-grant completeness
|
|
94
|
+
-- ===========================================================================
|
|
95
|
+
create temp view _rel as
|
|
96
|
+
select c.oid, c.relname::text as name, c.relkind, c.reloptions
|
|
97
|
+
from pg_class c join pg_namespace n on n.oid = c.relnamespace
|
|
98
|
+
where n.nspname = 'agent_board' and c.relkind in ('r', 'v', 'm', 'p', 'f');
|
|
99
|
+
-- 9 -- SELECT iff listed as read_view / read_table (has_any_column_privilege for column grants)
|
|
100
|
+
select is(
|
|
101
|
+
(select coalesce(string_agg(r.name || ' => ' ||
|
|
102
|
+
case when has_any_column_privilege('agent_board_delegate', r.oid, 'SELECT') then 'GRANTED, NOT LISTED' else 'LISTED, NOT GRANTED' end,
|
|
103
|
+
'; ' order by r.name), '')
|
|
104
|
+
from _rel r
|
|
105
|
+
where has_any_column_privilege('agent_board_delegate', r.oid, 'SELECT')
|
|
106
|
+
<> exists (select 1 from agent_board.delegate_allowed_operations o
|
|
107
|
+
where o.kind in ('read_view', 'read_table') and o.name = r.name
|
|
108
|
+
and o.kind = case when r.relkind in ('v', 'm') then 'read_view' else 'read_table' end)),
|
|
109
|
+
'',
|
|
110
|
+
'CLASS: agent_board_delegate can SELECT a relation iff it is listed as read_view or read_table, of its own relkind');
|
|
111
|
+
-- 10 -- the read closure, named: 5 views and 13 tables
|
|
112
|
+
select is(
|
|
113
|
+
(select string_agg(kind || ':' || name, ' ' order by kind, name)
|
|
114
|
+
from agent_board.delegate_allowed_operations where kind in ('read_view', 'read_table')),
|
|
115
|
+
'read_table:agent_signing_keys read_table:agents read_table:board_memberships read_table:boards read_table:claims read_table:delivery_recipients read_table:escalations read_table:inbox_items read_table:messages read_table:presence read_table:signature_evidence read_table:task_events read_table:tasks read_view:v_agent_dashboard read_view:v_agent_inbox read_view:v_board_feed read_view:v_board_memberships read_view:v_thread_feed',
|
|
116
|
+
'the read closure is the five views and the thirteen tables the contract freezes');
|
|
117
|
+
-- 11 -- the closure is CLOSED: every relation a granted view reads is itself granted
|
|
118
|
+
select is(
|
|
119
|
+
(select coalesce(string_agg(distinct v.relname || ' -> ' || t.relname, ', '), '(none)')
|
|
120
|
+
from pg_rewrite rw
|
|
121
|
+
join pg_class v on v.oid = rw.ev_class
|
|
122
|
+
join pg_depend d on d.classid = 'pg_rewrite'::regclass and d.objid = rw.oid and d.refclassid = 'pg_class'::regclass
|
|
123
|
+
join pg_class t on t.oid = d.refobjid and t.oid <> v.oid
|
|
124
|
+
where has_table_privilege('agent_board_delegate', v.oid, 'SELECT')
|
|
125
|
+
and v.relkind = 'v' and v.relnamespace = 'agent_board'::regnamespace
|
|
126
|
+
and not has_any_column_privilege('agent_board_delegate', t.oid, 'SELECT')),
|
|
127
|
+
'(none)',
|
|
128
|
+
'the read closure is closed: every relation a granted view reads is granted too (else the view raises)');
|
|
129
|
+
-- 12 -- every granted view is security_invoker
|
|
130
|
+
select is(
|
|
131
|
+
(select coalesce(string_agg(r.name, ', ' order by r.name), '(none)')
|
|
132
|
+
from _rel r
|
|
133
|
+
where r.relkind in ('v', 'm')
|
|
134
|
+
and has_table_privilege('agent_board_delegate', r.oid, 'SELECT')
|
|
135
|
+
and not coalesce('security_invoker=true' = any(r.reloptions), false)),
|
|
136
|
+
'(none)',
|
|
137
|
+
'every view agent_board_delegate can SELECT is security_invoker = true');
|
|
138
|
+
-- 13 -- agents: exactly the eight columns authenticated holds, never auth_user_id or owner_user_id
|
|
139
|
+
select is(
|
|
140
|
+
(select string_agg(a.attname, ',' order by a.attname)
|
|
141
|
+
from pg_attribute a
|
|
142
|
+
where a.attrelid = 'agent_board.agents'::regclass and a.attnum > 0 and not a.attisdropped
|
|
143
|
+
and has_column_privilege('agent_board_delegate', a.attrelid, a.attnum, 'SELECT')),
|
|
144
|
+
'agent_type,created_at,display_name,handle,id,kind,status,updated_at',
|
|
145
|
+
'agents: SELECT on exactly the eight authenticated columns (never auth_user_id, owner_user_id or is_delegate)');
|
|
146
|
+
-- 14 -- no write privilege anywhere, no sequence privilege
|
|
147
|
+
select is(
|
|
148
|
+
(select coalesce(string_agg(x, ', ' order by x), '(none)') from (
|
|
149
|
+
select r.name || ':' || p as x
|
|
150
|
+
from _rel r cross join unnest(array['INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER']) p
|
|
151
|
+
where has_table_privilege('agent_board_delegate', r.oid, p)
|
|
152
|
+
union all
|
|
153
|
+
select c.relname || ':' || p
|
|
154
|
+
from pg_class c join pg_namespace n on n.oid = c.relnamespace
|
|
155
|
+
cross join unnest(array['USAGE', 'SELECT', 'UPDATE']) p
|
|
156
|
+
where n.nspname = 'agent_board' and c.relkind = 'S'
|
|
157
|
+
and has_sequence_privilege('agent_board_delegate', c.oid, p)) z),
|
|
158
|
+
'(none)',
|
|
159
|
+
'agent_board_delegate holds no INSERT/UPDATE/DELETE/TRUNCATE/REFERENCES/TRIGGER and no sequence privilege');
|
|
160
|
+
|
|
161
|
+
-- ===========================================================================
|
|
162
|
+
-- 4. Policy completeness
|
|
163
|
+
-- ===========================================================================
|
|
164
|
+
create temp view _pol as
|
|
165
|
+
select c.relname::text as relname, p.polname::text as polname, p.polcmd, p.polpermissive,
|
|
166
|
+
array(select r.rolname::text from pg_roles r where r.oid = any(p.polroles) order by 1) as roles,
|
|
167
|
+
0 = any(p.polroles) as is_public, p.oid as poloid, p.polrelid,
|
|
168
|
+
-- newlines and indentation in the deparse collapsed to single spaces
|
|
169
|
+
replace(replace(replace(replace(pg_get_expr(p.polqual, p.polrelid), E'\n', ' '), ' ', ' '), ' ', ' '), ' ', ' ') as qual,
|
|
170
|
+
pg_get_expr(p.polwithcheck, p.polrelid) as withcheck
|
|
171
|
+
from pg_policy p join pg_class c on c.oid = p.polrelid join pg_namespace n on n.oid = c.relnamespace
|
|
172
|
+
where n.nspname = 'agent_board'
|
|
173
|
+
and ((select r.oid from pg_roles r where r.rolname = 'agent_board_delegate') = any(p.polroles) or 0 = any(p.polroles));
|
|
174
|
+
-- 15 -- a PUBLIC policy applies to the role too; allowed only where the role has no SELECT
|
|
175
|
+
select is(
|
|
176
|
+
(select coalesce(string_agg(relname || ':' || polname || ':' ||
|
|
177
|
+
case when has_table_privilege('agent_board_delegate', polrelid, 'SELECT') then 'ROLE HAS SELECT' else 'inert' end,
|
|
178
|
+
', ' order by relname, polname), '(none)')
|
|
179
|
+
from _pol where is_public),
|
|
180
|
+
'schema_version:agent_board_select_schema_version:inert',
|
|
181
|
+
'the one PUBLIC policy (schema_version) is on a relation the role cannot SELECT, so it grants the role nothing');
|
|
182
|
+
-- 16 -- exactly one delegate policy per read_table: SELECT, permissive, the role only
|
|
183
|
+
select is(
|
|
184
|
+
(select coalesce(string_agg(x, '; ' order by x), '(none)') from (
|
|
185
|
+
select o.name || ' => ' || count(p.polname)::text || ' policies' as x
|
|
186
|
+
from agent_board.delegate_allowed_operations o
|
|
187
|
+
left join _pol p on p.relname = o.name and not p.is_public
|
|
188
|
+
where o.kind = 'read_table'
|
|
189
|
+
group by o.name having count(p.polname) <> 1
|
|
190
|
+
union all
|
|
191
|
+
select relname || ':' || polname || ' is not a permissive SELECT policy for the role alone'
|
|
192
|
+
from _pol
|
|
193
|
+
where not is_public and (polcmd <> 'r' or not polpermissive or roles <> array['agent_board_delegate'] or withcheck is not null)
|
|
194
|
+
union all
|
|
195
|
+
select relname || ':' || polname || ' is on a relation outside the read closure'
|
|
196
|
+
from _pol
|
|
197
|
+
where not is_public and relname not in (select name from agent_board.delegate_allowed_operations where kind = 'read_table')) z),
|
|
198
|
+
'(none)',
|
|
199
|
+
'policy completeness: one permissive SELECT policy TO agent_board_delegate on each read_table, and none elsewhere');
|
|
200
|
+
-- 17 -- each predicate is the one the contract freezes (deparsed, whitespace-normalised). The
|
|
201
|
+
-- deparse qualifies names by the search_path, so agent_board is taken off it for this read.
|
|
202
|
+
set local search_path = extensions, public;
|
|
203
|
+
select is(
|
|
204
|
+
(select string_agg(relname || ' :: ' || qual, E'\n' order by relname) from _pol where not is_public),
|
|
205
|
+
'agent_signing_keys :: false' || E'\n' ||
|
|
206
|
+
'agents :: agent_board._delegate_visible_agent(id)' || E'\n' ||
|
|
207
|
+
'board_memberships :: ((agent_id = ( SELECT agent_board.current_agent_id() AS current_agent_id)) AND (membership_state = ANY (ARRAY[''joined''::text, ''subscribed''::text])))' || E'\n' ||
|
|
208
|
+
'boards :: (id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[])))' || E'\n' ||
|
|
209
|
+
'claims :: ((task_id IS NOT NULL) AND (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE ((dr.source_task_id = claims.task_id) AND (dr.board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[])))))))' || E'\n' ||
|
|
210
|
+
'delivery_recipients :: (board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[])))' || E'\n' ||
|
|
211
|
+
'escalations :: ((task_id IS NOT NULL) AND (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE ((dr.source_task_id = escalations.task_id) AND (dr.board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[])))))))' || E'\n' ||
|
|
212
|
+
'inbox_items :: ((board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[]))) AND ((recipient_agent_id = ( SELECT agent_board.current_agent_id() AS current_agent_id)) OR visible_in_board_feed))' || E'\n' ||
|
|
213
|
+
'messages :: (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE ((dr.source_message_id = messages.id) AND (dr.board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[]))))))' || E'\n' ||
|
|
214
|
+
'presence :: false' || E'\n' ||
|
|
215
|
+
'signature_evidence :: (((source_message_id IS NOT NULL) OR (source_task_event_id IS NOT NULL) OR (source_delivery_recipient_id IS NOT NULL)) AND (source_artifact_id IS NULL) AND ((source_message_id IS NULL) OR (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE ((dr.source_message_id = signature_evidence.source_message_id) AND (dr.board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[]))))))) AND ((source_task_event_id IS NULL) OR (EXISTS ( SELECT 1 FROM agent_board.task_events te WHERE (te.id = signature_evidence.source_task_event_id)))) AND ((source_delivery_recipient_id IS NULL) OR (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE (dr.id = signature_evidence.source_delivery_recipient_id)))))' || E'\n' ||
|
|
216
|
+
'task_events :: (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE ((dr.source_task_id = task_events.task_id) AND (dr.board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[]))))))' || E'\n' ||
|
|
217
|
+
'tasks :: (EXISTS ( SELECT 1 FROM agent_board.delivery_recipients dr WHERE ((dr.source_task_id = tasks.id) AND (dr.board_id = ANY (COALESCE(( SELECT agent_board._delegate_visible_board_ids() AS _delegate_visible_board_ids), ''{}''::uuid[]))))))',
|
|
218
|
+
'each delegate policy''s USING is exactly the D14 predicate stated once in the migration (InitPlan form)');
|
|
219
|
+
set local search_path = extensions, public, agent_board;
|
|
220
|
+
|
|
221
|
+
-- ===========================================================================
|
|
222
|
+
-- 5. Predicates are IN the set, not exempt
|
|
223
|
+
-- ===========================================================================
|
|
224
|
+
-- 18 -- every function a delegate-applicable policy or a granted view invokes is listed as a predicate
|
|
225
|
+
select is(
|
|
226
|
+
(select coalesce(string_agg(distinct f.signature, ', '), '(none)')
|
|
227
|
+
from (
|
|
228
|
+
select d.refobjid as fn
|
|
229
|
+
from pg_depend d join _pol p on d.classid = 'pg_policy'::regclass and d.objid = p.poloid
|
|
230
|
+
where d.refclassid = 'pg_proc'::regclass
|
|
231
|
+
and has_table_privilege('agent_board_delegate', p.polrelid, 'SELECT')
|
|
232
|
+
union
|
|
233
|
+
select d.refobjid
|
|
234
|
+
from pg_rewrite rw
|
|
235
|
+
join pg_depend d on d.classid = 'pg_rewrite'::regclass and d.objid = rw.oid
|
|
236
|
+
where d.refclassid = 'pg_proc'::regclass
|
|
237
|
+
and has_table_privilege('agent_board_delegate', rw.ev_class, 'SELECT')
|
|
238
|
+
) used
|
|
239
|
+
join _fn f on f.oid = used.fn -- agent_board functions; builtins are not predicates
|
|
240
|
+
where not exists (select 1 from agent_board.delegate_allowed_operations o
|
|
241
|
+
where o.kind = 'predicate' and o.signature = f.signature)),
|
|
242
|
+
'(none)',
|
|
243
|
+
'every function a delegate policy or granted view invokes is in the allow set as a predicate (no exemption list)');
|
|
244
|
+
-- 19 -- ...and every listed predicate IS invoked by one (a predicate nothing reaches is a stray grant)
|
|
245
|
+
select is(
|
|
246
|
+
(select coalesce(string_agg(o.signature, ', ' order by o.signature), '(none)')
|
|
247
|
+
from agent_board.delegate_allowed_operations o
|
|
248
|
+
join _fn f on f.signature = o.signature
|
|
249
|
+
where o.kind = 'predicate'
|
|
250
|
+
and not exists (
|
|
251
|
+
select 1 from pg_depend d join _pol p on d.classid = 'pg_policy'::regclass and d.objid = p.poloid
|
|
252
|
+
where d.refclassid = 'pg_proc'::regclass and d.refobjid = f.oid)),
|
|
253
|
+
'(none)',
|
|
254
|
+
'every listed predicate is invoked by a delegate policy');
|
|
255
|
+
-- 20 -- no granted view invokes an agent_board function (the views add no predicate)
|
|
256
|
+
select is(
|
|
257
|
+
(select count(*)::int
|
|
258
|
+
from pg_rewrite rw join pg_depend d on d.classid = 'pg_rewrite'::regclass and d.objid = rw.oid
|
|
259
|
+
join _fn f on f.oid = d.refobjid
|
|
260
|
+
where d.refclassid = 'pg_proc'::regclass and has_table_privilege('agent_board_delegate', rw.ev_class, 'SELECT')),
|
|
261
|
+
0,
|
|
262
|
+
'none of the granted views calls an agent_board function');
|
|
263
|
+
|
|
264
|
+
-- ===========================================================================
|
|
265
|
+
-- 6. D15 -- the admission flag has one setter; the sink reads it
|
|
266
|
+
-- ===========================================================================
|
|
267
|
+
-- 21 -- every function that names the flag at all, derived (a second setter -- or any new
|
|
268
|
+
-- reader -- names itself here)
|
|
269
|
+
select is(
|
|
270
|
+
(select coalesce(string_agg(f.name, ',' order by f.name), '(none)')
|
|
271
|
+
from _fn f
|
|
272
|
+
where strpos(agent_board_test.stripped_body(f.oid, true), 'agent_board.delegate_admission') > 0),
|
|
273
|
+
'_upsert_board_membership_state,add_delegate_to_board',
|
|
274
|
+
'D15: exactly two functions name agent_board.delegate_admission: its setter and the sink that reads it');
|
|
275
|
+
-- 22 -- the setter sets it to the target, and clears it
|
|
276
|
+
-- source-scan: loud-literal one body, named by regprocedure; a miss fails
|
|
277
|
+
select ok(
|
|
278
|
+
agent_board_test.stripped_body('agent_board.add_delegate_to_board(uuid,uuid)'::regprocedure, true)
|
|
279
|
+
~ 'set_config\(''agent_board\.delegate_admission'', p_agent_id::text, true\).*set_config\(''agent_board\.delegate_admission'', '''', true\)',
|
|
280
|
+
'D15: add_delegate_to_board sets the flag to the target and clears it again');
|
|
281
|
+
-- 23 -- the sink only reads it
|
|
282
|
+
-- source-scan: loud-literal one body, named by regprocedure; a miss fails
|
|
283
|
+
select ok(
|
|
284
|
+
agent_board_test.stripped_body('agent_board._upsert_board_membership_state(uuid,uuid,text,uuid,jsonb,uuid,text)'::regprocedure, true)
|
|
285
|
+
~ 'current_setting\(''agent_board\.delegate_admission'', true\)',
|
|
286
|
+
'D15: the sink reads the flag with current_setting');
|
|
287
|
+
|
|
288
|
+
-- ===========================================================================
|
|
289
|
+
-- 7. Placement and role-writer classes (§What stays refused for a delegate)
|
|
290
|
+
-- ===========================================================================
|
|
291
|
+
-- Every direct writer of board_memberships (any INSERT, UPDATE, MERGE or DELETE on it, the
|
|
292
|
+
-- ledger_authority role-writer derivation widened to every column) other than the sink must
|
|
293
|
+
-- call the shared refusal, schema-qualified. The sink carries the D15 rule instead.
|
|
294
|
+
create temp view _bm_writers as
|
|
295
|
+
select f.oid, f.name,
|
|
296
|
+
agent_board_test.stripped_body(f.oid) ~ agent_board_test.call_re('_refuse_delegate_membership_target', false) as refuses,
|
|
297
|
+
agent_board_test.stripped_body(f.oid) ~ agent_board_test.col_write_re('board_memberships', 'role') as writes_role
|
|
298
|
+
from _fn f
|
|
299
|
+
where f.name <> '_upsert_board_membership_state'
|
|
300
|
+
and agent_board_test.stripped_body(f.oid) ~ agent_board_test.write_re('board_memberships');
|
|
301
|
+
-- 24
|
|
302
|
+
select is(
|
|
303
|
+
(select string_agg(name || case when writes_role then '[role]' else '' end, ',' order by name) from _bm_writers),
|
|
304
|
+
'_fedsession_autojoin_default_board[role],_redeem_unbounded_invite_for_agent[role],bootstrap_board_owner_memberships[role],create_board[role],grant_board_role[role]',
|
|
305
|
+
'the direct board_memberships writers outside the sink, derived (a new one names itself)');
|
|
306
|
+
-- 25
|
|
307
|
+
select is(
|
|
308
|
+
(select coalesce(string_agg(name, ',' order by name), '') from _bm_writers where not refuses),
|
|
309
|
+
'',
|
|
310
|
+
'CLASS: every direct board_memberships writer outside the sink refuses a delegate target (grant_board_role included)');
|
|
311
|
+
-- 26 -- and every entrypoint that reaches board_memberships at all reaches it through one of
|
|
312
|
+
-- them or the sink: a function that writes it directly is in the set above by construction, so
|
|
313
|
+
-- this pins the sink's own rule is present
|
|
314
|
+
select ok(
|
|
315
|
+
agent_board_test.stripped_body('agent_board._upsert_board_membership_state(uuid,uuid,text,uuid,jsonb,uuid,text)'::regprocedure)
|
|
316
|
+
~ agent_board_test.call_re('_delegate_principal_agent_id', false)
|
|
317
|
+
and agent_board_test.stripped_body('agent_board._upsert_board_membership_state(uuid,uuid,text,uuid,jsonb,uuid,text)'::regprocedure, true)
|
|
318
|
+
~* 'is\s+distinct\s+from\s+''member''',
|
|
319
|
+
'D15: the sink compares the session with the delegate''s principal and asserts member after the write');
|
|
320
|
+
|
|
321
|
+
-- ===========================================================================
|
|
322
|
+
-- 8. D16 -- the addressing class
|
|
323
|
+
-- ===========================================================================
|
|
324
|
+
create temp view _addr as
|
|
325
|
+
select distinct f.oid, f.name,
|
|
326
|
+
agent_board_test.stripped_body(f.oid) ~ agent_board_test.call_re('_refuse_delegate_addressee', false) as refuses
|
|
327
|
+
from _fn f
|
|
328
|
+
cross join (values ('tasks', 'assigned_agent_id'), ('escalations', 'assigned_agent_id'),
|
|
329
|
+
('delegations', 'delegated_to_agent_id'), ('delivery_recipients', 'recipient_agent_id'),
|
|
330
|
+
('inbox_items', 'recipient_agent_id')) x(rel, col)
|
|
331
|
+
where agent_board_test.stripped_body(f.oid) ~ agent_board_test.col_write_re(x.rel, x.col);
|
|
332
|
+
-- 27
|
|
333
|
+
select is(
|
|
334
|
+
(select string_agg(name, ',' order by name) from _addr),
|
|
335
|
+
'_append_task_event,_upsert_delivery_recipient,_upsert_inbox_item,create_task,delegate_task,raise_escalation',
|
|
336
|
+
'the writers of an addressee column, derived (a new one names itself)');
|
|
337
|
+
-- 28
|
|
338
|
+
select is(
|
|
339
|
+
(select coalesce(string_agg(name, ',' order by name), '') from _addr where not refuses),
|
|
340
|
+
'',
|
|
341
|
+
'CLASS (D16): every writer of an addressee column calls the delegate-addressee refusal');
|
|
342
|
+
-- 29 -- update_inbox_item_state changes state and never the recipient (asserted positively)
|
|
343
|
+
select is(
|
|
344
|
+
(agent_board_test.stripped_body('agent_board.update_inbox_item_state(uuid,uuid,text,jsonb)'::regprocedure)
|
|
345
|
+
~ agent_board_test.re(agent_board_test.col_assign_frag('inbox_items', 'action_state', true)))::text
|
|
346
|
+
|| '/' ||
|
|
347
|
+
(agent_board_test.stripped_body('agent_board.update_inbox_item_state(uuid,uuid,text,jsonb)'::regprocedure)
|
|
348
|
+
~ agent_board_test.re(agent_board_test.col_assign_frag('inbox_items', 'recipient_agent_id', true)))::text,
|
|
349
|
+
'true/false',
|
|
350
|
+
'update_inbox_item_state assigns action_state and never recipient_agent_id');
|
|
351
|
+
|
|
352
|
+
-- ===========================================================================
|
|
353
|
+
-- 9. The provenance vocabulary readers (§principal-authored, exactly)
|
|
354
|
+
-- ===========================================================================
|
|
355
|
+
-- Every function naming a provenance value in its source, derived, each given a POSITIVE
|
|
356
|
+
-- disposition for principal-authored. An undisposed reader names itself.
|
|
357
|
+
-- 30
|
|
358
|
+
select is(
|
|
359
|
+
(select string_agg(f.name || ':' || case
|
|
360
|
+
when f.name = '_emit_membership_event'
|
|
361
|
+
and agent_board_test.stripped_body(f.oid, true) ~ 'v_prov\s*:=\s*''principal-authored''' then 'derives it'
|
|
362
|
+
when f.name = '_board_membership_events_provenance_guard'
|
|
363
|
+
and agent_board_test.stripped_body(f.oid, true) ~ 'provenance\s*=\s*''principal-authored''' then 'guards it'
|
|
364
|
+
when f.name in ('_membership_consent_present', '_membership_consent_kind')
|
|
365
|
+
and (select count(*) from regexp_matches(agent_board_test.stripped_body(f.oid, true), 'provenance\s*=\s*''principal-authored''', 'g')) = 2
|
|
366
|
+
then 'reads it in case and filter'
|
|
367
|
+
when f.name = '_upsert_board_membership_state'
|
|
368
|
+
and agent_board_test.stripped_body(f.oid) ~ agent_board_test.call_re('_emit_membership_event', false) then 'emits only through the emitter'
|
|
369
|
+
when f.name in ('create_board', 'bootstrap_board_owner_memberships', '_redeem_unbounded_invite_for_agent')
|
|
370
|
+
and agent_board_test.stripped_body(f.oid) ~ agent_board_test.call_re('_refuse_delegate_membership_target', false) then 'never a delegate target'
|
|
371
|
+
when f.name = 'resolve_board_request'
|
|
372
|
+
and exists (select 1 from agent_board_test.fn_call_closure() c
|
|
373
|
+
where c.root_oid = f.oid and c.reached_name = '_upsert_board_membership_state') then 'admits only through the sink (D15)'
|
|
374
|
+
when f.name = 'list_my_board_requests'
|
|
375
|
+
and not has_function_privilege('agent_board_delegate', f.oid, 'EXECUTE') then 'not callable by a delegate'
|
|
376
|
+
else 'UNDISPOSED' end, ', ' order by f.name)
|
|
377
|
+
from _fn f
|
|
378
|
+
where f.name in (select p.proname from pg_proc p join pg_namespace n on n.oid = p.pronamespace
|
|
379
|
+
where n.nspname = 'agent_board'
|
|
380
|
+
-- source-scan: raw-subject the contract derives this set from prosrc on purpose: a comment naming a value widens the set and only adds a disposition
|
|
381
|
+
and p.prosrc ~* '(operator-designated|target-authored|board-authored)')),
|
|
382
|
+
'_board_membership_events_provenance_guard:guards it, _emit_membership_event:derives it, _membership_consent_kind:reads it in case and filter, _membership_consent_present:reads it in case and filter, _redeem_unbounded_invite_for_agent:never a delegate target, _upsert_board_membership_state:emits only through the emitter, bootstrap_board_owner_memberships:never a delegate target, create_board:never a delegate target, list_my_board_requests:not callable by a delegate, resolve_board_request:admits only through the sink (D15)',
|
|
383
|
+
'every reader of the provenance vocabulary has a positive disposition for principal-authored');
|
|
384
|
+
-- 31 -- post_message is the only function that inserts into messages (the attribution mark is complete)
|
|
385
|
+
select is(
|
|
386
|
+
(select string_agg(f.name, ',' order by f.name) from _fn f
|
|
387
|
+
where agent_board_test.stripped_body(f.oid) ~ agent_board_test.stmt_re('insert into', 'messages')),
|
|
388
|
+
'post_message',
|
|
389
|
+
'post_message is the only writer of messages, so its delegate mark covers every message');
|
|
390
|
+
-- 32 -- the delegate fact is written only by the exchange's first-use insert
|
|
391
|
+
select is(
|
|
392
|
+
(select string_agg(f.name, ',' order by f.name) from _fn f
|
|
393
|
+
where agent_board_test.stripped_body(f.oid) ~ agent_board_test.col_write_re('agents', 'is_delegate')),
|
|
394
|
+
'exchange_delegate_credential',
|
|
395
|
+
'agents.is_delegate is written by exchange_delegate_credential alone');
|
|
396
|
+
|
|
397
|
+
-- ===========================================================================
|
|
398
|
+
-- 10. Zero rows elsewhere (D14) -- AS the delegate, over every listed relation
|
|
399
|
+
-- ===========================================================================
|
|
400
|
+
do $$
|
|
401
|
+
begin
|
|
402
|
+
if not (select rolsuper from pg_roles where rolname = current_user) then
|
|
403
|
+
execute format('grant agent_board_delegate to %I with set true', current_user);
|
|
404
|
+
end if;
|
|
405
|
+
end $$;
|
|
406
|
+
|
|
407
|
+
create temp table _z(k text primary key, v text);
|
|
408
|
+
create function pg_temp.v(p_k text) returns text language sql as $$ select v from _z where k = p_k $$;
|
|
409
|
+
create function pg_temp.u(p_k text) returns uuid language sql as $$ select v::uuid from _z where k = p_k $$;
|
|
410
|
+
create function pg_temp.put(p_k text, p_v text) returns void language sql as $$
|
|
411
|
+
insert into _z values (p_k, p_v) on conflict (k) do update set v = excluded.v $$;
|
|
412
|
+
create function pg_temp.svc() returns void language plpgsql as $$
|
|
413
|
+
begin perform set_config('request.jwt.claims', '', true); end $$;
|
|
414
|
+
create function pg_temp.authn(p_sub uuid) returns void language plpgsql as $$
|
|
415
|
+
begin perform set_config('request.jwt.claims', json_build_object('role', 'authenticated', 'sub', p_sub)::text, true); end $$;
|
|
416
|
+
create function pg_temp.as_d_val(p_sql text) returns text language plpgsql as $$
|
|
417
|
+
declare v text;
|
|
418
|
+
begin
|
|
419
|
+
perform set_config('request.jwt.claims',
|
|
420
|
+
json_build_object('role', 'agent_board_delegate', 'sub', pg_temp.v('D.auth'), 'agent_credential_id', pg_temp.v('D.cred'))::text, true);
|
|
421
|
+
set local role agent_board_delegate;
|
|
422
|
+
begin
|
|
423
|
+
execute p_sql into v;
|
|
424
|
+
exception when others then
|
|
425
|
+
v := 'ERR ' || sqlstate || ':' || sqlerrm;
|
|
426
|
+
end;
|
|
427
|
+
reset role;
|
|
428
|
+
return v;
|
|
429
|
+
end $$;
|
|
430
|
+
|
|
431
|
+
-- Fixtures: an owner (real enrollment), keyed agents, four boards, and an exclusive member per
|
|
432
|
+
-- board so `agents` has a row that belongs to exactly one board.
|
|
433
|
+
insert into agent_board.identity_providers
|
|
434
|
+
(issuer, audience, supported, policy_approved, allowed_scopes, allowed_board_scopes, allowed_agent_kinds)
|
|
435
|
+
values ('https://portal.zrows.test', 'message-board', true, true, '{}', '{}', '{agent,human}');
|
|
436
|
+
do $$
|
|
437
|
+
declare r record;
|
|
438
|
+
begin
|
|
439
|
+
perform set_config('request.jwt.claims', '', true);
|
|
440
|
+
select * into r from agent_board.enroll_federated_human('https://portal.zrows.test', 'message-board', 'zrows-owner',
|
|
441
|
+
'{"sub": "zrows-owner", "email": "zrows@t.test", "email_verified": true}'::jsonb, 'Z Owner');
|
|
442
|
+
perform pg_temp.put('O', r.agent_id::text);
|
|
443
|
+
perform pg_temp.put('O.auth', r.auth_user_id::text);
|
|
444
|
+
select * into r from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
445
|
+
'iss', 'https://portal.zrows.test', 'sub', 'zrows-owner', 'slot_resource', null,
|
|
446
|
+
'agent_board_delegate_instance', jsonb_build_object('instance_id', 'zrows_instance_000001', 'grant_id', 'zrows_grant_00000001',
|
|
447
|
+
'generation', 1, 'owner_sub', 'zrows-owner', 'client_id', 'zrows-client', 'status', 'active', 'client_change', null)));
|
|
448
|
+
perform pg_temp.put('D', r.agent_id::text);
|
|
449
|
+
perform pg_temp.put('D.auth', r.auth_user_id::text);
|
|
450
|
+
perform pg_temp.put('D.cred', r.credential_id::text);
|
|
451
|
+
end $$;
|
|
452
|
+
|
|
453
|
+
insert into auth.users(id, instance_id, aud, role, email)
|
|
454
|
+
select ('7a000000-0000-4000-8000-' || lpad(n::text, 12, '0'))::uuid, '00000000-0000-0000-0000-000000000000',
|
|
455
|
+
'authenticated', 'authenticated', 'zrows' || n || '@t.test'
|
|
456
|
+
from generate_series(1, 6) n;
|
|
457
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status, auth_user_id)
|
|
458
|
+
select ('7a100000-0000-4000-8000-' || lpad(n::text, 12, '0'))::uuid, 'agent', 'agent', 'zrows-keyed-' || n, 'Z ' || n, 'active',
|
|
459
|
+
('7a000000-0000-4000-8000-' || lpad(n::text, 12, '0'))::uuid
|
|
460
|
+
from generate_series(1, 6) n;
|
|
461
|
+
-- K = 1 (owner of every board), K2 = 2 (member of BA and BN), exclusive members 3..6 of BA, BN, BR, BL.
|
|
462
|
+
select pg_temp.put('K', '7a100000-0000-4000-8000-000000000001'), pg_temp.put('K.auth', '7a000000-0000-4000-8000-000000000001'),
|
|
463
|
+
pg_temp.put('K2', '7a100000-0000-4000-8000-000000000002'), pg_temp.put('K2.auth', '7a000000-0000-4000-8000-000000000002');
|
|
464
|
+
insert into agent_board.boards(id, slug, name, created_by_agent_id, visibility, status)
|
|
465
|
+
select ('7a200000-0000-4000-8000-' || lpad(n::text, 12, '0'))::uuid, 'zrows-' || b, 'Z ' || b, pg_temp.u('K'), 'private', 'active'
|
|
466
|
+
from unnest(array['ba', 'bn', 'br', 'bl']) with ordinality as t(b, n);
|
|
467
|
+
select pg_temp.put('B' || upper(b), ('7a200000-0000-4000-8000-' || lpad(n::text, 12, '0')))
|
|
468
|
+
from unnest(array['a', 'n', 'r', 'l']) with ordinality as t(b, n);
|
|
469
|
+
select pg_temp.put('X' || upper(b), ('7a100000-0000-4000-8000-' || lpad((n + 2)::text, 12, '0')))
|
|
470
|
+
from unnest(array['a', 'n', 'r', 'l']) with ordinality as t(b, n);
|
|
471
|
+
insert into agent_board.board_memberships(board_id, agent_id, role, membership_state, created_by_agent_id)
|
|
472
|
+
select pg_temp.u('B' || b), pg_temp.u('K'), 'owner', 'joined', pg_temp.u('K') from unnest(array['A', 'N', 'R', 'L']) b
|
|
473
|
+
union all
|
|
474
|
+
select pg_temp.u('B' || b), pg_temp.u('X' || b), 'member', 'joined', pg_temp.u('K') from unnest(array['A', 'N', 'R', 'L']) b
|
|
475
|
+
union all
|
|
476
|
+
select pg_temp.u('B' || b), pg_temp.u('O'), 'member', 'joined', pg_temp.u('K') from unnest(array['A', 'R', 'L']) b
|
|
477
|
+
union all
|
|
478
|
+
select pg_temp.u('B' || b), pg_temp.u('K2'), 'member', 'joined', pg_temp.u('K') from unnest(array['A', 'N']) b;
|
|
479
|
+
|
|
480
|
+
-- The owner places its delegate on BA, BR and BL (not BN).
|
|
481
|
+
select pg_temp.authn(pg_temp.u('O.auth'));
|
|
482
|
+
select agent_board.add_delegate_to_board(pg_temp.u('D'), pg_temp.u('B' || b)) from unnest(array['A', 'R', 'L']) b;
|
|
483
|
+
|
|
484
|
+
-- On each board: a keyed post (thread T<b>), the delegate's own post (BA/BR/BL), a task
|
|
485
|
+
-- ASSIGNED TO THE DELEGATE with its event, a claim and an escalation, a tasking delivery to
|
|
486
|
+
-- the board, signature evidence over the keyed post, and a co-member's per-recipient inbox item.
|
|
487
|
+
do $$
|
|
488
|
+
declare b text; v_thread uuid; v_msg uuid; v_task uuid; v_dr uuid; v_ev uuid;
|
|
489
|
+
begin
|
|
490
|
+
foreach b in array array['A', 'N', 'R', 'L'] loop
|
|
491
|
+
perform pg_temp.authn(pg_temp.u('K.auth'));
|
|
492
|
+
select thread_id into v_thread from agent_board.create_or_find_thread(pg_temp.u('K'), 'zrows ' || b, 'zrows-' || b);
|
|
493
|
+
perform pg_temp.put('T' || b, v_thread::text);
|
|
494
|
+
select message_id into v_msg from agent_board.post_board_message(v_thread, pg_temp.u('K'), pg_temp.u('B' || b), 's', 'keyed on ' || b);
|
|
495
|
+
perform pg_temp.put('M' || b, v_msg::text);
|
|
496
|
+
if b <> 'N' then
|
|
497
|
+
perform set_config('request.jwt.claims', json_build_object('role', 'agent_board_delegate', 'sub', pg_temp.v('D.auth'),
|
|
498
|
+
'agent_credential_id', pg_temp.v('D.cred'))::text, true);
|
|
499
|
+
perform agent_board.post_board_message(v_thread, null, pg_temp.u('B' || b), 's', 'delegate on ' || b);
|
|
500
|
+
end if;
|
|
501
|
+
-- seeded as the table owner, so the row exists whatever the writers refuse
|
|
502
|
+
insert into agent_board.tasks(thread_id, created_by_agent_id, assigned_agent_id, title, metadata)
|
|
503
|
+
values (v_thread, pg_temp.u('K'), pg_temp.u('D'), 'task on ' || b, jsonb_build_object('zrowsBoard', b))
|
|
504
|
+
returning id into v_task;
|
|
505
|
+
perform pg_temp.put('TK' || b, v_task::text);
|
|
506
|
+
insert into agent_board.task_events(task_id, thread_id, actor_agent_id, event_sequence, event_type, origin_posture)
|
|
507
|
+
values (v_task, v_thread, pg_temp.u('K'), 1, 'created', 'unattested:preexisting') returning id into v_ev;
|
|
508
|
+
insert into agent_board.claims(task_id, thread_id, agent_id, resource_kind, resource_key, lease_expires_at)
|
|
509
|
+
values (v_task, v_thread, pg_temp.u('K2'), 'task', 'zrows-' || b, now() + interval '1 hour');
|
|
510
|
+
insert into agent_board.escalations(thread_id, task_id, raised_by_agent_id, assigned_agent_id, summary)
|
|
511
|
+
values (v_thread, v_task, pg_temp.u('K'), pg_temp.u('D'), 'esc on ' || b);
|
|
512
|
+
insert into agent_board.delivery_recipients(delivery_mode, recipient_agent_id, source_kind, source_task_id, board_id, board_membership_id)
|
|
513
|
+
values ('tasking', pg_temp.u('K'), 'task', v_task, pg_temp.u('B' || b),
|
|
514
|
+
(select bm.id from agent_board.board_memberships bm
|
|
515
|
+
where bm.board_id = pg_temp.u('B' || b) and bm.agent_id = pg_temp.u('K') and bm.membership_state = 'joined'))
|
|
516
|
+
returning id into v_dr;
|
|
517
|
+
-- the co-member's (K's) per-recipient tasking row: a board, but NOT feed-visible
|
|
518
|
+
insert into agent_board.inbox_items(delivery_recipient_id, recipient_agent_id, board_id, delivery_mode, source_kind,
|
|
519
|
+
source_task_id, subject, visible_in_inbox, visible_in_board_feed)
|
|
520
|
+
values (v_dr, pg_temp.u('K'), pg_temp.u('B' || b), 'tasking', 'task', v_task, 'tasking on ' || b, true, false);
|
|
521
|
+
perform pg_temp.put('II' || b, (select id::text from agent_board.inbox_items where delivery_recipient_id = v_dr));
|
|
522
|
+
insert into agent_board.signature_evidence(agent_id, source_kind, source_message_id, operation, payload_digest, verification_status)
|
|
523
|
+
values (pg_temp.u('K'), 'message', v_msg, 'post_board_message', 'sha256:zrows', 'unsigned');
|
|
524
|
+
insert into agent_board.signature_evidence(agent_id, source_kind, source_task_event_id, operation, payload_digest, verification_status)
|
|
525
|
+
values (pg_temp.u('K'), 'task_event', v_ev, 'append_task_event', 'sha256:zrows', 'unsigned');
|
|
526
|
+
end loop;
|
|
527
|
+
end $$;
|
|
528
|
+
|
|
529
|
+
-- Then the delegate is REMOVED from BR (an admin) and LEFT on BL (its owner withdraws it).
|
|
530
|
+
select pg_temp.authn(pg_temp.u('K.auth'));
|
|
531
|
+
select agent_board.update_board_membership(pg_temp.u('BR'), pg_temp.u('D'), 'removed');
|
|
532
|
+
select pg_temp.authn(pg_temp.u('O.auth'));
|
|
533
|
+
select agent_board.update_board_membership(pg_temp.u('BL'), pg_temp.u('D'), 'left');
|
|
534
|
+
|
|
535
|
+
-- The count of rows of `rel` that belong to board `b`, AS the delegate. Each relation's notion
|
|
536
|
+
-- of "belongs to a board" is stated here; the SET of relations comes from the allow set, and a
|
|
537
|
+
-- relation with no statement is reported UNMAPPED (it fails, naming itself).
|
|
538
|
+
create function pg_temp.rows_of(p_rel text, p_b text) returns text language plpgsql as $$
|
|
539
|
+
declare q text;
|
|
540
|
+
begin
|
|
541
|
+
q := case p_rel
|
|
542
|
+
when 'boards' then format('select count(*) from agent_board.boards where id = %L', pg_temp.v('B' || p_b))
|
|
543
|
+
when 'board_memberships' then format('select count(*) from agent_board.board_memberships where board_id = %L', pg_temp.v('B' || p_b))
|
|
544
|
+
when 'agents' then format('select count(*) from agent_board.agents where id = %L', pg_temp.v('X' || p_b))
|
|
545
|
+
when 'messages' then format('select count(*) from agent_board.messages where thread_id = %L', pg_temp.v('T' || p_b))
|
|
546
|
+
when 'delivery_recipients' then format('select count(*) from agent_board.delivery_recipients where board_id = %L', pg_temp.v('B' || p_b))
|
|
547
|
+
when 'inbox_items' then format('select count(*) from agent_board.inbox_items where board_id = %L', pg_temp.v('B' || p_b))
|
|
548
|
+
when 'tasks' then format('select count(*) from agent_board.tasks where id = %L', pg_temp.v('TK' || p_b))
|
|
549
|
+
when 'task_events' then format('select count(*) from agent_board.task_events where task_id = %L', pg_temp.v('TK' || p_b))
|
|
550
|
+
when 'claims' then format('select count(*) from agent_board.claims where task_id = %L', pg_temp.v('TK' || p_b))
|
|
551
|
+
when 'escalations' then format('select count(*) from agent_board.escalations where task_id = %L', pg_temp.v('TK' || p_b))
|
|
552
|
+
when 'signature_evidence' then format('select count(*) from agent_board.signature_evidence se where se.source_message_id = %L
|
|
553
|
+
or se.source_task_event_id in (select te.id from agent_board.task_events te where te.task_id = %L)',
|
|
554
|
+
pg_temp.v('M' || p_b), pg_temp.v('TK' || p_b))
|
|
555
|
+
when 'presence' then 'select count(*) from agent_board.presence'
|
|
556
|
+
when 'agent_signing_keys' then 'select count(*) from agent_board.agent_signing_keys'
|
|
557
|
+
when 'v_board_feed' then format('select count(*) from agent_board.v_board_feed where board_id = %L', pg_temp.v('B' || p_b))
|
|
558
|
+
when 'v_thread_feed' then format('select count(*) from agent_board.v_thread_feed where thread_id = %L', pg_temp.v('T' || p_b))
|
|
559
|
+
when 'v_agent_inbox' then format('select count(*) from agent_board.v_agent_inbox where board_id = %L', pg_temp.v('B' || p_b))
|
|
560
|
+
when 'v_board_memberships' then format('select count(*) from agent_board.v_board_memberships where board_id = %L', pg_temp.v('B' || p_b))
|
|
561
|
+
when 'v_agent_dashboard' then format('select count(*) from agent_board.v_agent_dashboard where agent_id = %L', pg_temp.v('X' || p_b))
|
|
562
|
+
else null end;
|
|
563
|
+
if q is null then
|
|
564
|
+
return 'UNMAPPED';
|
|
565
|
+
end if;
|
|
566
|
+
return pg_temp.as_d_val(q);
|
|
567
|
+
end $$;
|
|
568
|
+
|
|
569
|
+
-- presence and agent_signing_keys have the frozen predicate `false`: a board-scoped positive
|
|
570
|
+
-- pair cannot exist for them, which assertion 17 pins (their qual IS `false`). Every other
|
|
571
|
+
-- relation must show the row on the active board.
|
|
572
|
+
create temp view _matrix as
|
|
573
|
+
select o.name,
|
|
574
|
+
pg_temp.rows_of(o.name, 'A') as on_active,
|
|
575
|
+
pg_temp.rows_of(o.name, 'N') as on_never,
|
|
576
|
+
pg_temp.rows_of(o.name, 'R') as on_removed,
|
|
577
|
+
pg_temp.rows_of(o.name, 'L') as on_left,
|
|
578
|
+
o.name in ('presence', 'agent_signing_keys') as no_positive
|
|
579
|
+
from agent_board.delegate_allowed_operations o
|
|
580
|
+
where o.kind in ('read_view', 'read_table');
|
|
581
|
+
create temp table _m as select * from _matrix;
|
|
582
|
+
-- The matrix, printed, so a reader sees the counts the four assertions below judge.
|
|
583
|
+
select diag('matrix (active/never/removed/left): ' || string_agg(name || '=' || on_active || '/' || on_never || '/' || on_removed || '/' || on_left, ' ' order by name)) from _m;
|
|
584
|
+
-- 33 -- the positive pair: every relation shows its row on the board the delegate is active on
|
|
585
|
+
select is(
|
|
586
|
+
(select coalesce(string_agg(name || '=' || on_active, ', ' order by name), '(none)')
|
|
587
|
+
from _m where not no_positive and not (on_active ~ '^[0-9]+$' and on_active::int > 0)),
|
|
588
|
+
'(none)',
|
|
589
|
+
'D14 positive pair: every read relation shows the row on a board where the delegate is active');
|
|
590
|
+
-- 34
|
|
591
|
+
select is(
|
|
592
|
+
(select coalesce(string_agg(name || '=' || on_never, ', ' order by name), '(none)') from _m where on_never <> '0'),
|
|
593
|
+
'(none)',
|
|
594
|
+
'D14: on a board the delegate was never on, every read relation shows ZERO rows (incl. a task ASSIGNED to it)');
|
|
595
|
+
-- 35
|
|
596
|
+
select is(
|
|
597
|
+
(select coalesce(string_agg(name || '=' || on_removed, ', ' order by name), '(none)') from _m where on_removed <> '0'),
|
|
598
|
+
'(none)',
|
|
599
|
+
'D14: after its REMOVAL from a board, zero rows of that board -- even what it authored, received or was assigned');
|
|
600
|
+
-- 36
|
|
601
|
+
select is(
|
|
602
|
+
(select coalesce(string_agg(name || '=' || on_left, ', ' order by name), '(none)') from _m where on_left <> '0'),
|
|
603
|
+
'(none)',
|
|
604
|
+
'D14: after it moves to LEFT on a board, zero rows of that board');
|
|
605
|
+
|
|
606
|
+
-- 37 -- boardless rows addressed to / authored by the delegate (seeded directly) are invisible
|
|
607
|
+
do $$
|
|
608
|
+
declare v_thread uuid; v_msg uuid; v_dr uuid;
|
|
609
|
+
begin
|
|
610
|
+
insert into agent_board.threads(thread_type, created_by_agent_id, subject) values ('coordination', pg_temp.u('D'), 'boardless')
|
|
611
|
+
returning id into v_thread;
|
|
612
|
+
insert into agent_board.messages(thread_id, author_agent_id, message_sequence, body)
|
|
613
|
+
values (v_thread, pg_temp.u('D'), 1, 'boardless by the delegate') returning id into v_msg;
|
|
614
|
+
insert into agent_board.delivery_recipients(delivery_mode, recipient_agent_id, source_kind, source_message_id, board_id)
|
|
615
|
+
values ('direct', pg_temp.u('D'), 'message', v_msg, null) returning id into v_dr;
|
|
616
|
+
insert into agent_board.inbox_items(delivery_recipient_id, recipient_agent_id, board_id, delivery_mode, source_kind, source_message_id, subject)
|
|
617
|
+
values (v_dr, pg_temp.u('D'), null, 'direct', 'message', v_msg, 'boardless');
|
|
618
|
+
insert into agent_board.presence(agent_id, availability) values (pg_temp.u('D'), 'ready');
|
|
619
|
+
perform pg_temp.put('BLM', v_msg::text);
|
|
620
|
+
end $$;
|
|
621
|
+
select is(
|
|
622
|
+
pg_temp.as_d_val(format($$ select concat_ws('/',
|
|
623
|
+
(select count(*) from agent_board.messages where id = %L),
|
|
624
|
+
(select count(*) from agent_board.delivery_recipients where source_message_id = %L),
|
|
625
|
+
(select count(*) from agent_board.inbox_items where source_message_id = %L),
|
|
626
|
+
(select count(*) from agent_board.presence)) $$, pg_temp.v('BLM'), pg_temp.v('BLM'), pg_temp.v('BLM'))),
|
|
627
|
+
'0/0/0/0',
|
|
628
|
+
'D14: a boardless message it AUTHORED, a boardless delivery and inbox item ADDRESSED to it, and its own presence: invisible');
|
|
629
|
+
|
|
630
|
+
-- 38, 39 -- CROSS-BOARD POST: a message delivered only to BN, in a thread stamped BA
|
|
631
|
+
select pg_temp.authn(pg_temp.u('K.auth'));
|
|
632
|
+
select pg_temp.put('XB', (select message_id::text from agent_board.post_board_message(pg_temp.u('TA'), pg_temp.u('K'), pg_temp.u('BN'), 's', 'cross-board to BN')));
|
|
633
|
+
select is(
|
|
634
|
+
(select board_id::text from agent_board.threads where id = pg_temp.u('TA')) || ' ' ||
|
|
635
|
+
pg_temp.as_d_val(format($$ select count(*) from agent_board.messages where id = %L $$, pg_temp.v('XB'))),
|
|
636
|
+
pg_temp.v('BA') || ' 0',
|
|
637
|
+
'D14 cross-board post: in a thread stamped BA, a message delivered only to BN is invisible to a delegate on BA');
|
|
638
|
+
select is(
|
|
639
|
+
pg_temp.as_d_val(format($$ select count(*) from agent_board.messages where id = %L $$, pg_temp.v('MA'))),
|
|
640
|
+
'1',
|
|
641
|
+
'D14 cross-board post, paired: the BA post in the same thread is visible');
|
|
642
|
+
|
|
643
|
+
-- 40 -- REUSED DM THREAD: boardless DMs in a thread later stamped BA by a board post
|
|
644
|
+
do $$
|
|
645
|
+
declare v_thread uuid;
|
|
646
|
+
begin
|
|
647
|
+
perform pg_temp.authn(pg_temp.u('K.auth'));
|
|
648
|
+
select thread_id into v_thread from agent_board.create_or_find_thread(pg_temp.u('K'), 'dm then board', 'zrows-dm');
|
|
649
|
+
perform agent_board.send_direct_message(v_thread, pg_temp.u('K'), pg_temp.u('K2'), 's', 'the dm before');
|
|
650
|
+
perform pg_temp.put('DMT', v_thread::text);
|
|
651
|
+
perform agent_board.post_board_message(v_thread, pg_temp.u('K'), pg_temp.u('BA'), 's', 'the board post after');
|
|
652
|
+
end $$;
|
|
653
|
+
select is(
|
|
654
|
+
pg_temp.as_d_val(format($$ select string_agg(body, ',' order by body) from agent_board.messages where thread_id = %L $$, pg_temp.v('DMT'))),
|
|
655
|
+
'the board post after',
|
|
656
|
+
'D14 reused DM thread: the boardless DM in a thread later stamped BA is invisible; the board post is visible');
|
|
657
|
+
|
|
658
|
+
-- 41 -- A CO-MEMBER'S INBOX: K2's per-recipient item on BA is invisible; v_agent_inbox shows
|
|
659
|
+
-- only the delegate's own rows or feed-visible ones, and shows some
|
|
660
|
+
select is(
|
|
661
|
+
pg_temp.as_d_val(format($$ select concat_ws('/',
|
|
662
|
+
(select count(*) from agent_board.inbox_items where id = %L),
|
|
663
|
+
(select count(*) from agent_board.v_agent_inbox where not (recipient_agent_id = %L or visible_in_board_feed)),
|
|
664
|
+
(select (count(*) > 0)::text from agent_board.v_agent_inbox)) $$, pg_temp.v('IIA'), pg_temp.v('D'))),
|
|
665
|
+
'0/0/true',
|
|
666
|
+
'D14 co-member inbox: a co-member''s (non-feed) per-recipient item is invisible; v_agent_inbox returns only own or feed-visible rows (and some)');
|
|
667
|
+
|
|
668
|
+
-- ===========================================================================
|
|
669
|
+
-- 11. DIFFERENTIAL: the shipped (InitPlan) policies show EXACTLY the contract's rows
|
|
670
|
+
-- ===========================================================================
|
|
671
|
+
-- The contract froze the D14 read rule as per-row predicates; the migration ships the same
|
|
672
|
+
-- rule with the caller's board set computed once per query. This compares, for every
|
|
673
|
+
-- read_table in the allow set (the list is read from the table, not written here), the row
|
|
674
|
+
-- ids the delegate SEES with the row ids the contract's predicates ADMIT, computed here as
|
|
675
|
+
-- the table owner from the rule itself. The fixture above holds every case the contract
|
|
676
|
+
-- names: active, never-member, removed and left boards; boardless rows addressed to and
|
|
677
|
+
-- authored by the delegate; a task assigned to it off-board; a cross-board post; a DM thread
|
|
678
|
+
-- later stamped by a board post; and a co-member's non-feed inbox row. A relation with no
|
|
679
|
+
-- reference rule here is reported UNMAPPED and fails.
|
|
680
|
+
create function pg_temp.oracle(p_rel text, p_d uuid) returns text language plpgsql as $$
|
|
681
|
+
declare q text; v text;
|
|
682
|
+
a text := format('(select bm.board_id from agent_board.board_memberships bm where bm.agent_id = %L and bm.membership_state in (''joined'', ''subscribed''))', p_d);
|
|
683
|
+
msg_vis text; task_vis text;
|
|
684
|
+
begin
|
|
685
|
+
msg_vis := 'exists (select 1 from agent_board.delivery_recipients d2 where d2.source_message_id = %s and d2.board_id is not null and d2.board_id in ' || a || ')';
|
|
686
|
+
task_vis := 'exists (select 1 from agent_board.delivery_recipients d3 where d3.source_task_id = %s and d3.board_id is not null and d3.board_id in ' || a || ')';
|
|
687
|
+
q := case p_rel
|
|
688
|
+
when 'boards' then 'select id from agent_board.boards where id in ' || a
|
|
689
|
+
when 'board_memberships' then format('select id from agent_board.board_memberships where agent_id = %L and membership_state in (''joined'', ''subscribed'')', p_d)
|
|
690
|
+
when 'agents' then format('select x.id from agent_board.agents x where x.id = %L
|
|
691
|
+
or exists (select 1 from agent_board.board_memberships o where o.agent_id = x.id and o.membership_state in (''joined'', ''subscribed'') and o.board_id in %s)
|
|
692
|
+
or exists (select 1 from agent_board.messages m where m.author_agent_id = x.id and %s)', p_d, a, format(msg_vis, 'm.id'))
|
|
693
|
+
when 'messages' then 'select m.id from agent_board.messages m where ' || format(msg_vis, 'm.id')
|
|
694
|
+
when 'delivery_recipients' then 'select id from agent_board.delivery_recipients where board_id is not null and board_id in ' || a
|
|
695
|
+
when 'inbox_items' then format('select id from agent_board.inbox_items where board_id is not null and board_id in %s and (recipient_agent_id = %L or visible_in_board_feed)', a, p_d)
|
|
696
|
+
when 'tasks' then 'select t.id from agent_board.tasks t where ' || format(task_vis, 't.id')
|
|
697
|
+
when 'task_events' then 'select te.id from agent_board.task_events te where ' || format(task_vis, 'te.task_id')
|
|
698
|
+
when 'claims' then 'select c.id from agent_board.claims c where c.task_id is not null and ' || format(task_vis, 'c.task_id')
|
|
699
|
+
when 'escalations' then 'select e.id from agent_board.escalations e where e.task_id is not null and ' || format(task_vis, 'e.task_id')
|
|
700
|
+
when 'signature_evidence' then 'select se.id from agent_board.signature_evidence se
|
|
701
|
+
where (se.source_message_id is not null or se.source_task_event_id is not null or se.source_delivery_recipient_id is not null)
|
|
702
|
+
and se.source_artifact_id is null
|
|
703
|
+
and (se.source_message_id is null or ' || format(msg_vis, 'se.source_message_id') || ')
|
|
704
|
+
and (se.source_task_event_id is null or exists (select 1 from agent_board.task_events te where te.id = se.source_task_event_id and ' || format(task_vis, 'te.task_id') || '))
|
|
705
|
+
and (se.source_delivery_recipient_id is null or exists (select 1 from agent_board.delivery_recipients dr where dr.id = se.source_delivery_recipient_id and dr.board_id is not null and dr.board_id in ' || a || '))'
|
|
706
|
+
when 'presence' then 'select agent_id from agent_board.presence where false'
|
|
707
|
+
when 'agent_signing_keys' then 'select id from agent_board.agent_signing_keys where false'
|
|
708
|
+
else null end;
|
|
709
|
+
if q is null then return 'UNMAPPED'; end if;
|
|
710
|
+
execute 'select coalesce(string_agg(z::text, '','' order by z::text), '''') from (' || q || ') s(z)' into v;
|
|
711
|
+
return v;
|
|
712
|
+
end $$;
|
|
713
|
+
create function pg_temp.seen(p_rel text) returns text language plpgsql as $$
|
|
714
|
+
begin
|
|
715
|
+
return coalesce(pg_temp.as_d_val(format('select coalesce(string_agg(%s::text, '','' order by %s::text), '''') from agent_board.%I',
|
|
716
|
+
case p_rel when 'presence' then 'agent_id' else 'id' end, case p_rel when 'presence' then 'agent_id' else 'id' end, p_rel)), '');
|
|
717
|
+
end $$;
|
|
718
|
+
create temp table _eq as
|
|
719
|
+
select o.name, pg_temp.oracle(o.name, pg_temp.u('D')) as contract_rows, pg_temp.seen(o.name) as seen_rows
|
|
720
|
+
from agent_board.delegate_allowed_operations o where o.kind = 'read_table';
|
|
721
|
+
select diag('differential (rows admitted by the contract rule / rows seen): ' || string_agg(name || '=' ||
|
|
722
|
+
(case when contract_rows = '' then 0 else array_length(string_to_array(contract_rows, ','), 1) end)::text || '/' ||
|
|
723
|
+
(case when seen_rows = '' then 0 else array_length(string_to_array(seen_rows, ','), 1) end)::text, ' ' order by name)) from _eq;
|
|
724
|
+
-- 42
|
|
725
|
+
select is(
|
|
726
|
+
(select coalesce(string_agg(name, ', ' order by name), '(none)') from _eq where contract_rows is distinct from seen_rows),
|
|
727
|
+
'(none)',
|
|
728
|
+
'DIFFERENTIAL: for every read_table the delegate sees exactly the rows the contract''s per-row rule admits');
|
|
729
|
+
-- 43 -- not vacuous: the rule admits rows in every relation whose predicate is not `false`
|
|
730
|
+
select is(
|
|
731
|
+
(select count(*)::int from _eq where contract_rows <> '' and contract_rows <> 'UNMAPPED'),
|
|
732
|
+
11,
|
|
733
|
+
'DIFFERENTIAL is not vacuous: 11 of the 13 tables have admitted rows (presence and agent_signing_keys are `false` by contract)');
|
|
734
|
+
|
|
735
|
+
select * from finish();
|
|
736
|
+
rollback;
|