@consiliency/agent-board-schema 1.68.0 → 1.74.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 +28 -4
- package/migrations/20261026000100_agent_board_thread_association.sql +1287 -0
- package/migrations/20261101000100_agent_board_session_measured_mint.sql +145 -0
- package/migrations/20261104065658_agent_board_reply_delivery.sql +659 -0
- package/migrations/20261104170000_agent_board_tasking_replay_scope.sql +320 -0
- package/migrations/20261104180000_agent_board_delivery_writer_execute.sql +51 -0
- package/migrations/20261104190000_agent_board_message_replay_scope.sql +373 -0
- package/package.json +1 -1
- package/schema-manifest.json +57 -3
- package/src/tooling.test.mjs +8 -2
- package/tests/agent_board_661_reply_delivery.test.sql +185 -0
- package/tests/agent_board_667_boundary.test.sql +162 -0
- package/tests/agent_board_667_conversion_branches.test.sql +91 -0
- package/tests/agent_board_667_conversion_profile.test.sql +112 -0
- package/tests/agent_board_667_history_class.test.sql +785 -0
- package/tests/agent_board_667_native_cast_effect.test.sql +88 -0
- package/tests/agent_board_667_realtime_apply_behavior.test.sql +117 -0
- package/tests/agent_board_667_realtime_apply_controls.test.sql +143 -0
- package/tests/agent_board_667_realtime_apply_profile.test.sql +61 -0
- package/tests/agent_board_667_retention.test.sql +201 -0
- package/tests/agent_board_667_routing.test.sql +294 -0
- package/tests/agent_board_667_sender_effects.test.sql +100 -0
- package/tests/agent_board_667_sender_profile_controls.test.sql +29 -0
- package/tests/agent_board_667_storage_delimiter_behavior.test.sql +84 -0
- package/tests/agent_board_667_storage_delimiter_controls.test.sql +23 -0
- package/tests/agent_board_667_storage_delimiter_profile.test.sql +61 -0
- package/tests/agent_board_667_storage_search_behavior.test.sql +93 -0
- package/tests/agent_board_667_storage_search_controls.test.sql +22 -0
- package/tests/agent_board_667_storage_search_profile.test.sql +60 -0
- package/tests/agent_board_667_storage_timestamp_behavior.test.sql +58 -0
- package/tests/agent_board_667_storage_timestamp_controls.test.sql +22 -0
- package/tests/agent_board_667_storage_timestamp_profile.test.sql +54 -0
- package/tests/agent_board_667_writers.test.sql +281 -0
- package/tests/agent_board_717_message_replay_scope.test.sql +828 -0
- package/tests/agent_board_717_tasking_replay_scope.test.sql +661 -0
- package/tests/agent_board_addressing.test.sql +8 -5
- package/tests/agent_board_claim_subject_gate.test.sql +7 -3
- package/tests/agent_board_claimpolicy_race.test.sql +39 -11
- package/tests/agent_board_delegate_role_class.test.sql +33 -15
- package/tests/agent_board_delivery_writer_execute.test.sql +371 -0
- package/tests/agent_board_fk_lock_edges.test.sql +3 -0
- package/tests/agent_board_hosted_delegates.test.sql +5 -2
- package/tests/agent_board_inbox_rpcs.test.sql +5 -3
- package/tests/agent_board_obsgate.test.sql +8 -4
- package/tests/agent_board_obsgate4.test.sql +2 -2
- package/tests/agent_board_outbox_wake_ordering.test.sql +25 -2
- package/tests/agent_board_own_post_not_delivered.test.sql +11 -9
- package/tests/agent_board_session_identity_behavior_classes.test.sql +2 -2
- package/tests/agent_board_session_identity_limits.test.sql +1 -1
- package/tests/agent_board_session_identity_measured_mint.test.sql +342 -0
- package/tests/agent_board_session_identity_predicate_isolation.test.sql +146 -0
- package/tests/agent_board_sidserver_authority.test.sql +69 -0
- package/tests/agent_board_sidserver_catalog.test.sql +47 -0
- package/tests/agent_board_signed_write_gateway.test.sql +4 -2
- package/tests/agent_board_task_thread_lock_order.test.sql +67 -42
- package/tests/agent_board_v2_invariants.test.sql +5 -2
- package/tests/agent_board_write_enforcement_class.test.sql +3 -3
- package/tests/catalog/function_execute_privileges.json +41 -5
- package/tests/catalog/p_metadata_parameters.json +16 -0
- package/tests/fixtures/agent_board_667_apply_rls_guard.sql +195 -0
- package/tests/fixtures/agent_board_667_apply_rls_provenance.md +125 -0
- package/tests/fixtures/agent_board_667_apply_rls_reference.sql +1903 -0
- package/tests/fixtures/agent_board_667_conversion_guard.sql +162 -0
- package/tests/fixtures/agent_board_667_conversion_reference.md +23 -0
- package/tests/fixtures/agent_board_667_conversion_reference.sql +5325 -0
- package/tests/fixtures/agent_board_667_delimiter_guard.sql +92 -0
- package/tests/fixtures/agent_board_667_delimiter_provenance.md +116 -0
- package/tests/fixtures/agent_board_667_delimiter_reference.sql +10150 -0
- package/tests/fixtures/agent_board_667_search_guard.sql +92 -0
- package/tests/fixtures/agent_board_667_search_provenance.md +141 -0
- package/tests/fixtures/agent_board_667_search_reference.sql +4779 -0
- package/tests/fixtures/agent_board_667_sender_guard.sql +102 -0
- package/tests/fixtures/agent_board_667_sender_reference.md +20 -0
- package/tests/fixtures/agent_board_667_sender_reference.sql +875 -0
- package/tests/fixtures/agent_board_667_timestamp_graph.sql +84 -0
- package/tests/fixtures/agent_board_667_timestamp_guard.sql +94 -0
- package/tests/fixtures/agent_board_667_timestamp_provenance.md +99 -0
- package/tests/fixtures/agent_board_667_timestamp_reference.sql +2938 -0
- package/tests/isolation/expected/association_artifact_anchor_order.out +108 -0
- package/tests/isolation/expected/association_board_vs_board.out +71 -0
- package/tests/isolation/expected/association_post_wait_authority.out +77 -0
- package/tests/isolation/expected/association_strong_history_writers.out +203 -0
- package/tests/isolation/expected/association_strong_isolation.out +185 -0
- package/tests/isolation/expected/association_vs_artifact_claim_escalation.out +199 -0
- package/tests/isolation/expected/association_vs_heartbeat.out +78 -0
- package/tests/isolation/expected/association_vs_multi_anchor_artifact.out +67 -0
- package/tests/isolation/expected/association_vs_private_message.out +67 -0
- package/tests/isolation/expected/association_vs_task_and_conflict.out +133 -0
- package/tests/isolation/expected/association_vs_taskful_cross_thread.out +133 -0
- package/tests/isolation/expected/message_replay_scope.out +209 -0
- package/tests/isolation/expected/tasking_replay_scope.out +125 -0
- package/tests/isolation/specs/association_artifact_anchor_order.spec +46 -0
- package/tests/isolation/specs/association_board_vs_board.spec +37 -0
- package/tests/isolation/specs/association_post_wait_authority.spec +48 -0
- package/tests/isolation/specs/association_strong_history_writers.spec +61 -0
- package/tests/isolation/specs/association_strong_isolation.spec +50 -0
- package/tests/isolation/specs/association_vs_artifact_claim_escalation.spec +41 -0
- package/tests/isolation/specs/association_vs_heartbeat.spec +47 -0
- package/tests/isolation/specs/association_vs_multi_anchor_artifact.spec +38 -0
- package/tests/isolation/specs/association_vs_private_message.spec +33 -0
- package/tests/isolation/specs/association_vs_task_and_conflict.spec +38 -0
- package/tests/isolation/specs/association_vs_taskful_cross_thread.spec +42 -0
- package/tests/isolation/specs/message_replay_scope.spec +77 -0
- package/tests/isolation/specs/tasking_replay_scope.spec +72 -0
- package/tests/mutations/717-f1/M0_prefix_main_acl_and_comments.sql +11 -0
- package/tests/mutations/717-f1/M10_wrapper_stops_delegating.sql +7 -0
- package/tests/mutations/717-f1/M11_transitive_recipient_content.sql +8 -0
- package/tests/mutations/717-f1/M12_transitive_recipient_visibility.sql +8 -0
- package/tests/mutations/717-f1/M13_transitive_worker_content.sql +15 -0
- package/tests/mutations/717-f1/M1a_regrant_upsert_delivery_recipient.sql +1 -0
- package/tests/mutations/717-f1/M1b_regrant_upsert_inbox_item.sql +1 -0
- package/tests/mutations/717-f1/M1c_regrant_queue_inbox_callbacks.sql +1 -0
- package/tests/mutations/717-f1/M1d_regrant_queue_board_post_callbacks.sql +1 -0
- package/tests/mutations/717-f1/M1e_regrant_next_thread_message_sequence.sql +1 -0
- package/tests/mutations/717-f1/M2_blanket_schema_grant.sql +1 -0
- package/tests/mutations/717-f1/M3_new_overload_of_sink.sql +10 -0
- package/tests/mutations/717-f1/M4_new_route_calling_sink.sql +7 -0
- package/tests/mutations/717-f1/M5_actor_trusts_supplied_id.sql +5 -0
- package/tests/mutations/717-f1/M6_signed_route_granted_to_authenticated.sql +1 -0
- package/tests/mutations/717-f1/M7_worker_granted_to_authenticated.sql +1 -0
- package/tests/mutations/717-f1/M8_recipient_state_rewrites_visibility.sql +5 -0
- package/tests/mutations/717-f1/M9_public_route_revoked_from_service_role.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W1_regrant_queue_inbox_callbacks.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W2_revoke_worker_from_service_role.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W3_invoker_caller_of_sink.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W4_public_regrant_board_post_sink.sql +1 -0
- package/tests/mutations/717-f1/run.sh +17 -0
- package/tests/mutations/717-f2b/C1_new_delivery_route.sql +4 -0
- package/tests/mutations/717-f2b/C2_new_replay_lookup.sql +3 -0
- package/tests/mutations/717-f2b/C3_internal_regranted.sql +2 -0
- package/tests/mutations/717-f2b/C4_wrapper_writes_delivery.sql +9 -0
- package/tests/mutations/717-f2b/C5_class_member_dynamic_sql.sql +9 -0
- package/tests/mutations/717-f2b/C6_drop_board_scope_constraint.sql +2 -0
- package/tests/mutations/717-f2b/C7_state_private_helper_content.sql +14 -0
- package/tests/mutations/717-f2b/L1_dm_lock_split_by_recipient.sql +8 -0
- package/tests/mutations/717-f2b/L2_dm_lock_removed.sql +12 -0
- package/tests/mutations/717-f2b/L3_mc_lock_split_by_recipients.sql +8 -0
- package/tests/mutations/717-f2b/L4_mc_lock_removed.sql +12 -0
- package/tests/mutations/717-f2b/M0_prefix_definitions.sql +17 -0
- package/tests/mutations/717-f2b/M10_mc_lookup_any_author.sql +15 -0
- package/tests/mutations/717-f2b/M11_dm_swallow_refusal.sql +8 -0
- package/tests/mutations/717-f2b/M12_mc_swallow_refusal.sql +8 -0
- package/tests/mutations/717-f2b/M13_signed_dm_swallows_refusal.sql +32 -0
- package/tests/mutations/717-f2b/M14_signed_mc_swallows_refusal.sql +20 -0
- package/tests/mutations/717-f2b/M15_mc_any_source.sql +7 -0
- package/tests/mutations/717-f2b/M1_dm_drop_recipient_proof.sql +16 -0
- package/tests/mutations/717-f2b/M2_mc_drop_recipient_proof.sql +16 -0
- package/tests/mutations/717-f2b/M3_dm_metadata_as_proof.sql +12 -0
- package/tests/mutations/717-f2b/M4_mc_metadata_as_proof.sql +16 -0
- package/tests/mutations/717-f2b/M5_dm_any_mode.sql +11 -0
- package/tests/mutations/717-f2b/M6_dm_board_delivery_counts.sql +11 -0
- package/tests/mutations/717-f2b/M7_mc_any_mode.sql +11 -0
- package/tests/mutations/717-f2b/M8_dm_thread_stamp_as_proof.sql +12 -0
- package/tests/mutations/717-f2b/M9_dm_lookup_any_author.sql +15 -0
- package/tests/mutations/717-f2b/run.sh +82 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
-- This is a caller/boundary witness, not an exemption from the opaque-routine
|
|
2
|
+
-- census. A selected domain check can invoke a guarded history writer even
|
|
3
|
+
-- though the native wrapper is IMMUTABLE. Missing platform code gets no credit.
|
|
4
|
+
create extension if not exists pgtap with schema extensions;
|
|
5
|
+
set search_path = extensions, public, agent_board;
|
|
6
|
+
begin;
|
|
7
|
+
select plan(16);
|
|
8
|
+
select set_config('request.jwt.claim.role','service_role',true);
|
|
9
|
+
insert into agent_board.agents(id,agent_type,handle,display_name,status)
|
|
10
|
+
values ('667e0000-0000-4000-8000-000000000001','agent','native-cast-probe','Native cast probe','active');
|
|
11
|
+
insert into agent_board.threads(id,thread_type,created_by_agent_id,subject)
|
|
12
|
+
values ('667e0000-0000-4000-8000-000000000010','coordination','667e0000-0000-4000-8000-000000000001','Private cast probe');
|
|
13
|
+
insert into agent_board.boards(id,slug,name,created_by_agent_id,visibility,status)
|
|
14
|
+
values ('667e0000-0000-4000-8000-000000000020','native-cast-probe-board','Native cast probe','667e0000-0000-4000-8000-000000000001','private','active');
|
|
15
|
+
create schema xb_native_cast_probe;
|
|
16
|
+
create function xb_native_cast_probe.write_guarded_history(p_value integer)
|
|
17
|
+
returns boolean language plpgsql volatile as $$
|
|
18
|
+
begin
|
|
19
|
+
perform agent_board.create_task('667e0000-0000-4000-8000-000000000010','667e0000-0000-4000-8000-000000000001','Written through a domain expression');
|
|
20
|
+
return true;
|
|
21
|
+
end$$;
|
|
22
|
+
create domain xb_native_cast_probe.writing_integer as integer
|
|
23
|
+
check (xb_native_cast_probe.write_guarded_history(value));
|
|
24
|
+
create temp table xb_native_cast_answer(value jsonb) on commit drop;
|
|
25
|
+
select is((select count(*) from agent_board.threads where id='667e0000-0000-4000-8000-000000000010' and board_id is null),
|
|
26
|
+
1::bigint,'XB conversion fixture starts as an unstamped private thread');
|
|
27
|
+
select diag('Native realtime.cast absent: no platform execution or disposition credit')
|
|
28
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is null;
|
|
29
|
+
select * from skip('native realtime.cast absent',7)
|
|
30
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is null;
|
|
31
|
+
select is(md5(pg_get_functiondef(to_regprocedure('realtime."cast"(text,regtype)'))),
|
|
32
|
+
'2d38c9a2b85fe787afe48a12c02839e8','XB native cast definition matches the captured CI body')
|
|
33
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
34
|
+
select lives_ok($$insert into xb_native_cast_answer select realtime."cast"('4','xb_native_cast_probe.writing_integer'::regtype)$$,
|
|
35
|
+
'XB native cast executes the domain conversion')
|
|
36
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
37
|
+
select is((select value from xb_native_cast_answer),'4'::jsonb,'XB native cast returns the converted value')
|
|
38
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
39
|
+
select is((select count(*) from agent_board.tasks where thread_id='667e0000-0000-4000-8000-000000000010'),1::bigint,
|
|
40
|
+
'XB native cast domain check executes the guarded history writer')
|
|
41
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
42
|
+
-- Both equality overloads dynamically cast their operands. These checks are
|
|
43
|
+
-- separately conditional on each full identity; absence is not execution credit.
|
|
44
|
+
select diag('Native four-argument equality absent: no platform execution credit')
|
|
45
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is null;
|
|
46
|
+
select * from skip('native four-argument equality absent',4)
|
|
47
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is null;
|
|
48
|
+
select is(md5(pg_get_functiondef(to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)'))),
|
|
49
|
+
'dc96014b6232b30f11a6465db31bd20a','XB native four-argument equality definition matches CI')
|
|
50
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is not null;
|
|
51
|
+
create temp table xb_equality_answer(arity integer, value boolean) on commit drop;
|
|
52
|
+
select lives_ok($$insert into xb_equality_answer select 4,realtime.check_equality_op('eq','xb_native_cast_probe.writing_integer'::regtype,'4','4')$$,
|
|
53
|
+
'XB native four-argument equality executes selected conversions')
|
|
54
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is not null;
|
|
55
|
+
select is((select value from xb_equality_answer where arity=4),true,'XB native four-argument equality returns true')
|
|
56
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is not null;
|
|
57
|
+
select is((select count(*) from agent_board.tasks where thread_id='667e0000-0000-4000-8000-000000000010'),
|
|
58
|
+
(case when to_regprocedure('realtime."cast"(text,regtype)') is null then 2 else 3 end)::bigint,
|
|
59
|
+
'XB native four-argument equality conversions invoke the guarded writer twice')
|
|
60
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is not null;
|
|
61
|
+
select diag('Native five-argument equality absent: no platform execution credit')
|
|
62
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)') is null;
|
|
63
|
+
select * from skip('native five-argument equality absent',4)
|
|
64
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)') is null;
|
|
65
|
+
select is(md5(pg_get_functiondef(to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)'))),
|
|
66
|
+
'3db26de03f6feab4f7fc8f9a8a48c07e','XB native five-argument equality definition matches CI')
|
|
67
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)') is not null;
|
|
68
|
+
select lives_ok($$insert into xb_equality_answer select 5,realtime.check_equality_op('eq','xb_native_cast_probe.writing_integer'::regtype,'4','4',true)$$,
|
|
69
|
+
'XB native five-argument equality executes selected conversions')
|
|
70
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)') is not null;
|
|
71
|
+
select is((select value from xb_equality_answer where arity=5),false,'XB native five-argument equality negates its result')
|
|
72
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)') is not null;
|
|
73
|
+
select is((select count(*) from agent_board.tasks where thread_id='667e0000-0000-4000-8000-000000000010'),
|
|
74
|
+
(2 + case when to_regprocedure('realtime."cast"(text,regtype)') is null then 0 else 1 end
|
|
75
|
+
+ case when to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text)') is null then 0 else 2 end)::bigint,
|
|
76
|
+
'XB native five-argument equality conversions invoke the guarded writer twice')
|
|
77
|
+
where to_regprocedure('realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)') is not null;
|
|
78
|
+
select throws_ok($$select * from agent_board.post_board_message('667e0000-0000-4000-8000-000000000010','667e0000-0000-4000-8000-000000000001','667e0000-0000-4000-8000-000000000020','subject','body')$$,
|
|
79
|
+
'42501','thread has private history','XB native cast indirect history prevents association')
|
|
80
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
81
|
+
select is((select count(*) from agent_board.messages where thread_id='667e0000-0000-4000-8000-000000000010'),0::bigint,
|
|
82
|
+
'XB native cast refused association inserts no message')
|
|
83
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
84
|
+
select is((select board_id from agent_board.threads where id='667e0000-0000-4000-8000-000000000010'),null::uuid,
|
|
85
|
+
'XB native cast private thread remains unstamped')
|
|
86
|
+
where to_regprocedure('realtime."cast"(text,regtype)') is not null;
|
|
87
|
+
select * from finish();
|
|
88
|
+
rollback;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
-- Native apply_rls own-row, role, prepared-target and history witnesses. These
|
|
2
|
+
-- are runtime observations, distinct from the effect-class disposition.
|
|
3
|
+
create extension if not exists pgtap with schema extensions;set search_path=extensions,public,agent_board;begin;
|
|
4
|
+
select to_regprocedure('realtime.apply_rls(jsonb,integer)') is not null as native_present \gset
|
|
5
|
+
\if :native_present
|
|
6
|
+
select plan(26);
|
|
7
|
+
create schema xb_ar_own;
|
|
8
|
+
create table xb_ar_own.notes(id integer primary key,owner text not null);
|
|
9
|
+
alter table xb_ar_own.notes enable row level security;
|
|
10
|
+
create policy xb_ar_own_claims on xb_ar_own.notes for select to authenticated
|
|
11
|
+
using (owner=(nullif(current_setting('request.jwt.claims',true),'')::jsonb->>'sub'));
|
|
12
|
+
create table xb_ar_own.plain(id integer primary key);
|
|
13
|
+
create table xb_ar_own.effect(n text);
|
|
14
|
+
grant usage on schema xb_ar_own to authenticated;
|
|
15
|
+
grant select on xb_ar_own.notes,xb_ar_own.plain to authenticated;
|
|
16
|
+
grant insert on xb_ar_own.effect to authenticated;
|
|
17
|
+
insert into xb_ar_own.notes values(1,'alice'),(2,'bob');
|
|
18
|
+
insert into realtime.subscription(subscription_id,entity,claims) values
|
|
19
|
+
('66700000-0000-4000-8000-0000000000a1','xb_ar_own.notes','{"role":"authenticated","sub":"alice"}'),
|
|
20
|
+
('66700000-0000-4000-8000-0000000000b2','xb_ar_own.notes','{"role":"authenticated","sub":"bob"}'),
|
|
21
|
+
('66700000-0000-4000-8000-0000000000c3','xb_ar_own.plain','{"role":"authenticated","sub":"alice"}');
|
|
22
|
+
create temp table ar_out(wal jsonb,is_rls_enabled boolean,subscription_ids uuid[],errors text[]) on commit drop;
|
|
23
|
+
create function pg_temp.ar_wal(p_table text,p_action text,p_id integer) returns jsonb language sql as $f$
|
|
24
|
+
select jsonb_build_object('action',p_action,'schema','xb_ar_own','table',p_table,'timestamp','2026-10-27 00:00:00+00',
|
|
25
|
+
'columns',jsonb_build_array(jsonb_build_object('name','id','type','int4','value',p_id)),
|
|
26
|
+
'identity',jsonb_build_array(jsonb_build_object('name','id','type','int4','value',p_id)),
|
|
27
|
+
'pk',jsonb_build_array(jsonb_build_object('name','id','type','int4')))
|
|
28
|
+
$f$;
|
|
29
|
+
create temp table ar_history on commit drop as
|
|
30
|
+
with direct as (select distinct conrelid from pg_constraint where contype='f' and confrelid='agent_board.threads'::regclass)
|
|
31
|
+
select conrelid as relid,0::bigint as n from direct
|
|
32
|
+
union select f.conrelid,0 from pg_constraint f join direct d on d.conrelid=f.confrelid where f.contype='f';
|
|
33
|
+
do $$ declare r record; begin
|
|
34
|
+
for r in select relid from pg_temp.ar_history loop
|
|
35
|
+
execute format('update pg_temp.ar_history set n=(select count(*) from %s) where relid=%s',r.relid::regclass,r.relid);
|
|
36
|
+
end loop; end $$;
|
|
37
|
+
|
|
38
|
+
-- Own-row visibility is decided by the subscriber's role and claims.
|
|
39
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(pg_temp.ar_wal('notes','I',1))$c$,'AR alice row native call lives');
|
|
40
|
+
select is((select subscription_ids from ar_out),array['66700000-0000-4000-8000-0000000000a1']::uuid[],'AR only the owning subscriber sees alice row');
|
|
41
|
+
select ok((select is_rls_enabled and errors='{}' from ar_out),'AR alice row took the row-security path without errors');
|
|
42
|
+
truncate ar_out;
|
|
43
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(pg_temp.ar_wal('notes','I',2))$c$,'AR bob row native call lives');
|
|
44
|
+
select is((select subscription_ids from ar_out),array['66700000-0000-4000-8000-0000000000b2']::uuid[],'AR only the owning subscriber sees bob row');
|
|
45
|
+
-- Exit state: the role is reset; the last subscriber's claims stay set for the
|
|
46
|
+
-- remainder of this transaction. This is native behavior, recorded not endorsed.
|
|
47
|
+
select is(current_user::text,'postgres','AR caller role is restored after the subscriber role switches');
|
|
48
|
+
select ok(current_setting('request.jwt.claims')::jsonb in('{"role":"authenticated","sub":"alice"}'::jsonb,'{"role":"authenticated","sub":"bob"}'::jsonb),
|
|
49
|
+
'AR subscriber claims remain set after return');
|
|
50
|
+
select is((select count(*) from pg_prepared_statements where name='walrus_rls_stmt'),1::bigint,'AR prepared target remains a session resource');
|
|
51
|
+
select ok((select statement from pg_prepared_statements where name='walrus_rls_stmt') ~ 'from\s+xb_ar_own\.notes\s+where\s+id=''2''',
|
|
52
|
+
'AR prepared target is schema-qualified when the relation is not on the search path');
|
|
53
|
+
|
|
54
|
+
-- PREPARE/EXECUTE is reached only for a row-security entity and a non-DELETE.
|
|
55
|
+
deallocate walrus_rls_stmt;
|
|
56
|
+
truncate ar_out;
|
|
57
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(pg_temp.ar_wal('notes','D',1))$c$,'AR delete native call lives');
|
|
58
|
+
select is((select count(*) from pg_prepared_statements where name='walrus_rls_stmt'),0::bigint,'AR delete does not prepare the target');
|
|
59
|
+
select is((select array_agg(x order by x) from ar_out cross join unnest(subscription_ids) x),
|
|
60
|
+
array['66700000-0000-4000-8000-0000000000a1','66700000-0000-4000-8000-0000000000b2']::uuid[],
|
|
61
|
+
'AR delete is delivered by filter without a row-security check');
|
|
62
|
+
truncate ar_out;
|
|
63
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(pg_temp.ar_wal('plain','I',1))$c$,'AR non-row-security native call lives');
|
|
64
|
+
select is((select count(*) from pg_prepared_statements where name='walrus_rls_stmt'),0::bigint,'AR non-row-security entity does not prepare the target');
|
|
65
|
+
select is((select subscription_ids from ar_out),array['66700000-0000-4000-8000-0000000000c3']::uuid[],'AR non-row-security subscriber is delivered');
|
|
66
|
+
|
|
67
|
+
-- The role switch cannot exceed the session user's SET membership.
|
|
68
|
+
create role xb_ar_unsettable nologin;
|
|
69
|
+
grant select on xb_ar_own.notes to xb_ar_unsettable;
|
|
70
|
+
select ok(not pg_has_role(session_user,'xb_ar_unsettable','SET'),'AR control role is not settable by the session user');
|
|
71
|
+
insert into realtime.subscription(subscription_id,entity,claims) values
|
|
72
|
+
('66700000-0000-4000-8000-0000000000d4','xb_ar_own.notes','{"role":"xb_ar_unsettable","sub":"alice"}');
|
|
73
|
+
select throws_ok($c$select * from realtime.apply_rls(pg_temp.ar_wal('notes','I',1))$c$,'42501',null,
|
|
74
|
+
'AR an unsettable subscriber role is refused, not assumed');
|
|
75
|
+
delete from realtime.subscription where subscription_id='66700000-0000-4000-8000-0000000000d4';
|
|
76
|
+
|
|
77
|
+
-- A board relation reaches its real policies and helpers, without history writes.
|
|
78
|
+
grant usage on schema agent_board to authenticated;
|
|
79
|
+
insert into realtime.subscription(subscription_id,entity,claims) values
|
|
80
|
+
('66700000-0000-4000-8000-0000000000e5','agent_board.threads','{"role":"authenticated","sub":"66700000-0000-4000-8000-0000000000ff"}');
|
|
81
|
+
truncate ar_out;
|
|
82
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(jsonb_build_object('action','I','schema','agent_board','table','threads',
|
|
83
|
+
'timestamp','2026-10-27 00:00:00+00','columns',jsonb_build_array(jsonb_build_object('name','id','type','uuid','value','66700000-0000-4000-8000-0000000000ff')),
|
|
84
|
+
'pk',jsonb_build_array(jsonb_build_object('name','id','type','uuid'))))$c$,'AR board thread native call lives');
|
|
85
|
+
select ok((select is_rls_enabled and errors='{}' and subscription_ids='{}' from ar_out),'AR board thread row-security check ran and refused visibility');
|
|
86
|
+
select ok((select statement from pg_prepared_statements where name='walrus_rls_stmt') ~ 'from\s+(agent_board\.)?threads\s',
|
|
87
|
+
'AR board thread was the prepared target');
|
|
88
|
+
create function pg_temp.ar_history_changed() returns bigint language plpgsql as $f$
|
|
89
|
+
declare r record; changed bigint:=0; now_n bigint; begin
|
|
90
|
+
for r in select relid,n from pg_temp.ar_history loop
|
|
91
|
+
execute format('select count(*) from %s',r.relid::regclass) into now_n;
|
|
92
|
+
if now_n<>r.n then changed:=changed+1; end if;
|
|
93
|
+
end loop; return changed; end $f$;
|
|
94
|
+
select is(pg_temp.ar_history_changed(),0::bigint,'AR no history relation changed during the native calls');
|
|
95
|
+
select ok((select count(*)>=8 from pg_temp.ar_history),'AR history snapshot covers the catalog-derived history relations');
|
|
96
|
+
|
|
97
|
+
-- Redirection witness. With the target on the search path its regclass text is
|
|
98
|
+
-- unqualified, and PostgreSQL re-parses the prepared statement under the
|
|
99
|
+
-- subscriber role's "$user" schema. The guard must therefore include every
|
|
100
|
+
-- relation that shares a target's relname; see the apply_rls controls.
|
|
101
|
+
create schema authenticated;
|
|
102
|
+
grant usage on schema authenticated to authenticated;
|
|
103
|
+
create function authenticated.xb_ar_redirect_probe() returns boolean language sql
|
|
104
|
+
as $f$insert into xb_ar_own.effect values('redirected') returning true$f$;
|
|
105
|
+
create view authenticated.notes as select 1 as id where authenticated.xb_ar_redirect_probe();
|
|
106
|
+
grant select on authenticated.notes to authenticated;
|
|
107
|
+
truncate ar_out;
|
|
108
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(pg_temp.ar_wal('notes','I',1))$c$,'AR qualified control native call lives');
|
|
109
|
+
select is((select count(*) from xb_ar_own.effect),0::bigint,'AR qualified target is not redirected');
|
|
110
|
+
set local search_path="$user",xb_ar_own,extensions,public,agent_board;
|
|
111
|
+
truncate ar_out;
|
|
112
|
+
select lives_ok($c$insert into ar_out select * from realtime.apply_rls(pg_temp.ar_wal('notes','I',1))$c$,'AR unqualified target native call lives');
|
|
113
|
+
select is((select count(*) from xb_ar_own.effect),2::bigint,'AR unqualified target is re-resolved under each subscriber role');
|
|
114
|
+
\else
|
|
115
|
+
select plan(1);select ok(to_regprocedure('realtime.apply_rls(jsonb,integer)') is null,'AR native apply_rls absent; no native behavior credit');
|
|
116
|
+
\endif
|
|
117
|
+
select * from finish();rollback;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
-- Each control installs one catalog edge of a closure class, proves the guard
|
|
2
|
+
-- names its exact identity and closes admission, then proves removal restores
|
|
3
|
+
-- the prior findings. Probes are never executed.
|
|
4
|
+
create extension if not exists pgtap with schema extensions;
|
|
5
|
+
create extension if not exists plpgsql_check with schema extensions;
|
|
6
|
+
set search_path=extensions,public,agent_board;
|
|
7
|
+
begin;
|
|
8
|
+
\ir fixtures/agent_board_667_conversion_guard.sql
|
|
9
|
+
\ir fixtures/agent_board_667_sender_guard.sql
|
|
10
|
+
\ir fixtures/agent_board_667_timestamp_guard.sql
|
|
11
|
+
\ir fixtures/agent_board_667_apply_rls_guard.sql
|
|
12
|
+
select to_regprocedure('realtime.apply_rls(jsonb,integer)') is not null as native_present \gset
|
|
13
|
+
\if :native_present
|
|
14
|
+
select plan(32);
|
|
15
|
+
create temp table ar_prior on commit drop as select * from pg_temp.xb_ar_problems();
|
|
16
|
+
create temp table ar_seen(identity text,problem text) on commit drop;
|
|
17
|
+
create function pg_temp.ar_capture() returns void language plpgsql as $f$
|
|
18
|
+
begin truncate pg_temp.ar_seen; insert into pg_temp.ar_seen select * from pg_temp.xb_ar_problems(); end $f$;
|
|
19
|
+
create function pg_temp.ar_restored() returns boolean language sql as $f$
|
|
20
|
+
select (select jsonb_agg(jsonb_build_array(identity,problem) order by identity,problem) from pg_temp.xb_ar_problems())
|
|
21
|
+
is not distinct from (select jsonb_agg(jsonb_build_array(identity,problem) order by identity,problem) from pg_temp.ar_prior)
|
|
22
|
+
$f$;
|
|
23
|
+
create schema xb_ar_ctl;
|
|
24
|
+
create schema xb_ar_ctl2;
|
|
25
|
+
create function xb_ar_ctl.probe() returns boolean language plpgsql as $f$begin return true;end$f$;
|
|
26
|
+
|
|
27
|
+
-- C1 a relation sharing a row-security target's relname is a possible prepared target.
|
|
28
|
+
create view xb_ar_ctl2.threads as select 1 as id where xb_ar_ctl.probe();
|
|
29
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
30
|
+
select ok(exists(select 1 from pg_temp.xb_ar_rel where rel='xb_ar_ctl2.threads'::regclass
|
|
31
|
+
and origin='row-security target or same-name resolution'),'AR C1 same-name view enters the closure by relname');
|
|
32
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.probe()' and problem='unreviewed apply_rls executable'),
|
|
33
|
+
'AR C1 same-name view names its unreviewed callee');
|
|
34
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C1 same-name view closes admission');
|
|
35
|
+
drop view xb_ar_ctl2.threads;
|
|
36
|
+
select ok(pg_temp.ar_restored(),'AR C1 removal restores the prior findings');
|
|
37
|
+
|
|
38
|
+
-- C2 a parsed policy helper must be SELECT-only; a DML body names itself.
|
|
39
|
+
create table xb_ar_ctl.sink(id integer);
|
|
40
|
+
create table xb_ar_ctl.target(id integer);
|
|
41
|
+
alter table xb_ar_ctl.target enable row level security;
|
|
42
|
+
create function xb_ar_ctl.writes() returns boolean language sql set search_path=pg_catalog
|
|
43
|
+
as $f$select 1;with w as (insert into xb_ar_ctl.sink values(1) returning 1) select exists(select 1 from w)$f$;
|
|
44
|
+
create policy xb_ar_ctl_writes on xb_ar_ctl.target for select using (xb_ar_ctl.writes());
|
|
45
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
46
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.writes()' and problem='apply_rls helper is not SELECT-only'),
|
|
47
|
+
'AR C2 a policy helper that writes names itself');
|
|
48
|
+
select ok(not exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.writes()' and problem='unreviewed apply_rls executable'),
|
|
49
|
+
'AR C2 the writer is refused by its parsed structure, not by an identity list');
|
|
50
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C2 writing helper closes admission');
|
|
51
|
+
drop policy xb_ar_ctl_writes on xb_ar_ctl.target;
|
|
52
|
+
select ok(pg_temp.ar_restored(),'AR C2 removal restores the prior findings');
|
|
53
|
+
|
|
54
|
+
-- C3 inheritance children of a target are scanned with it.
|
|
55
|
+
create table xb_ar_ctl.xb_ar_child_only() inherits (xb_ar_ctl.target);
|
|
56
|
+
create policy xb_ar_ctl_child on xb_ar_ctl.xb_ar_child_only for select using (xb_ar_ctl.probe());
|
|
57
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
58
|
+
select ok(exists(select 1 from pg_temp.xb_ar_rel where rel='xb_ar_ctl.xb_ar_child_only'::regclass and origin like 'inheritance child of %'),
|
|
59
|
+
'AR C3 inheritance child enters the closure');
|
|
60
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.probe()' and problem='unreviewed apply_rls executable'),
|
|
61
|
+
'AR C3 inheritance child names its unreviewed policy callee');
|
|
62
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C3 inheritance child closes admission');
|
|
63
|
+
drop table xb_ar_ctl.xb_ar_child_only;
|
|
64
|
+
select ok(pg_temp.ar_restored(),'AR C3 removal restores the prior findings');
|
|
65
|
+
|
|
66
|
+
-- C4 a pinned-path SQL helper is expanded through its own parsed body.
|
|
67
|
+
create function xb_ar_ctl.helper() returns boolean language sql stable set search_path=pg_catalog
|
|
68
|
+
as $f$select xb_ar_ctl.probe()$f$;
|
|
69
|
+
create policy xb_ar_ctl_helper on xb_ar_ctl.target for select using (xb_ar_ctl.helper());
|
|
70
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
71
|
+
select ok(exists(select 1 from pg_temp.xb_ar_fn where fn='xb_ar_ctl.probe()'::regprocedure and origin='body of xb_ar_ctl.helper()'),
|
|
72
|
+
'AR C4 helper body reaches its callee');
|
|
73
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.probe()' and problem='unreviewed apply_rls executable'),
|
|
74
|
+
'AR C4 helper body names its unreviewed callee');
|
|
75
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C4 helper callee closes admission');
|
|
76
|
+
drop policy xb_ar_ctl_helper on xb_ar_ctl.target;
|
|
77
|
+
select ok(pg_temp.ar_restored(),'AR C4 removal restores the prior findings');
|
|
78
|
+
|
|
79
|
+
-- C5 a body without a pinned search_path resolves names at run time, so
|
|
80
|
+
-- every same-named routine is a possible callee.
|
|
81
|
+
create function xb_ar_ctl.unpinned() returns boolean language sql stable as $f$select pg_catalog.lower('x')='x'$f$;
|
|
82
|
+
create function xb_ar_ctl.lower(text) returns text language plpgsql as $f$begin return $1;end$f$;
|
|
83
|
+
create policy xb_ar_ctl_unpinned on xb_ar_ctl.target for select using (xb_ar_ctl.unpinned());
|
|
84
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
85
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.lower(text)' and problem='unreviewed apply_rls executable'),
|
|
86
|
+
'AR C5 run-time shadow of a helper call names itself');
|
|
87
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C5 run-time shadow closes admission');
|
|
88
|
+
drop policy xb_ar_ctl_unpinned on xb_ar_ctl.target;
|
|
89
|
+
drop function xb_ar_ctl.lower(text);
|
|
90
|
+
select ok(pg_temp.ar_restored(),'AR C5 removal restores the prior findings');
|
|
91
|
+
|
|
92
|
+
-- C6 apply_rls itself has no pinned search_path: a static-call shadow names itself.
|
|
93
|
+
create function xb_ar_ctl.set_config(text,text,boolean) returns text language plpgsql as $f$begin return $2;end$f$;
|
|
94
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
95
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.set_config(text,text,boolean)' and problem='unreviewed apply_rls executable'),
|
|
96
|
+
'AR C6 static-call shadow names itself');
|
|
97
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C6 static-call shadow closes admission');
|
|
98
|
+
drop function xb_ar_ctl.set_config(text,text,boolean);
|
|
99
|
+
select ok(pg_temp.ar_restored(),'AR C6 removal restores the prior findings');
|
|
100
|
+
|
|
101
|
+
-- C7 a relation read inside a policy is itself scanned under row security.
|
|
102
|
+
create table xb_ar_ctl.xb_ar_side_only(id integer);
|
|
103
|
+
create policy xb_ar_ctl_side on xb_ar_ctl.xb_ar_side_only for select using (xb_ar_ctl.probe());
|
|
104
|
+
create policy xb_ar_ctl_reads on xb_ar_ctl.target for select using (exists(select 1 from xb_ar_ctl.xb_ar_side_only));
|
|
105
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
106
|
+
select ok(exists(select 1 from pg_temp.xb_ar_rel where rel='xb_ar_ctl.xb_ar_side_only'::regclass and origin like 'policy %'),
|
|
107
|
+
'AR C7 policy-read relation enters the closure');
|
|
108
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl.probe()' and problem='unreviewed apply_rls executable'),
|
|
109
|
+
'AR C7 policy-read relation names its unreviewed policy callee');
|
|
110
|
+
drop policy xb_ar_ctl_reads on xb_ar_ctl.target;
|
|
111
|
+
drop table xb_ar_ctl.xb_ar_side_only;
|
|
112
|
+
select ok(pg_temp.ar_restored(),'AR C7 removal restores the prior findings');
|
|
113
|
+
|
|
114
|
+
-- C8 an undispositioned relation kind among possible targets names itself.
|
|
115
|
+
create sequence xb_ar_ctl2.target;
|
|
116
|
+
do $$ begin perform pg_temp.ar_capture(); end $$;
|
|
117
|
+
select ok(exists(select 1 from pg_temp.ar_seen where identity='xb_ar_ctl2.target' and problem='unreviewed apply_rls relation kind S'),
|
|
118
|
+
'AR C8 same-name sequence names its relation kind');
|
|
119
|
+
drop sequence xb_ar_ctl2.target;
|
|
120
|
+
select ok(pg_temp.ar_restored(),'AR C8 removal restores the prior findings');
|
|
121
|
+
|
|
122
|
+
-- C9 the wrapper declaration is exact; drift closes admission by identity.
|
|
123
|
+
update pg_temp.xb_ar_reference set payload=payload||'{"owner":"drifted"}' where kind='wrapper';
|
|
124
|
+
select ok(exists(select 1 from pg_temp.xb_ar_problems() where identity='realtime.apply_rls(jsonb,integer)'
|
|
125
|
+
and problem='apply_rls declaration or security drift'),'AR C9 wrapper declaration drift names itself');
|
|
126
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C9 wrapper drift closes admission');
|
|
127
|
+
update pg_temp.xb_ar_reference set payload=payload-'owner'||jsonb_build_object('owner',pg_get_userbyid(p.proowner))
|
|
128
|
+
from pg_proc p where kind='wrapper' and p.oid=to_regprocedure(identity);
|
|
129
|
+
select ok(pg_temp.ar_restored(),'AR C9 restoring the declaration restores the prior findings');
|
|
130
|
+
|
|
131
|
+
-- C10 a reviewed built-in leaf is admitted only with its exact declaration.
|
|
132
|
+
update pg_temp.xb_ar_reference set payload=payload||'{"definition_md5":"drifted"}'
|
|
133
|
+
where kind='primitive' and identity='pg_catalog.set_config(text,text,boolean)';
|
|
134
|
+
select ok(exists(select 1 from pg_temp.xb_ar_problems() where identity='pg_catalog.set_config(text,text,boolean)'
|
|
135
|
+
and problem='unreviewed apply_rls executable'),'AR C10 built-in leaf drift names itself');
|
|
136
|
+
select is((select count(*) from pg_temp.xb_ar_admitted()),0::bigint,'AR C10 built-in leaf drift closes admission');
|
|
137
|
+
\else
|
|
138
|
+
select plan(1);
|
|
139
|
+
select ok(to_regprocedure('realtime.apply_rls(jsonb,integer)') is null
|
|
140
|
+
and not exists(select 1 from pg_temp.xb_ar_admitted()),'AR absent native apply_rls has no control admission');
|
|
141
|
+
\endif
|
|
142
|
+
select * from finish();
|
|
143
|
+
rollback;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
create extension if not exists pgtap with schema extensions;
|
|
2
|
+
create extension if not exists plpgsql_check with schema extensions;
|
|
3
|
+
set search_path=extensions,public,agent_board;
|
|
4
|
+
begin;
|
|
5
|
+
\ir fixtures/agent_board_667_conversion_guard.sql
|
|
6
|
+
\ir fixtures/agent_board_667_sender_guard.sql
|
|
7
|
+
\ir fixtures/agent_board_667_timestamp_guard.sql
|
|
8
|
+
\ir fixtures/agent_board_667_apply_rls_guard.sql
|
|
9
|
+
select to_regprocedure('realtime.apply_rls(jsonb,integer)') is not null as native_present \gset
|
|
10
|
+
\if :native_present
|
|
11
|
+
select plan(14);
|
|
12
|
+
select is((select string_agg(identity||': '||problem,', ' order by identity,problem) from pg_temp.xb_ar_problems()),null::text,
|
|
13
|
+
'AR complete target, policy, helper and built-in closure matches');
|
|
14
|
+
select is((select array_agg(fn order by fn) from pg_temp.xb_ar_admitted()),
|
|
15
|
+
array['realtime.apply_rls(jsonb,integer)'::regprocedure::oid],'AR exactly the native apply_rls OID is admitted');
|
|
16
|
+
do $$ begin perform pg_temp.xb_ar_compute(); end $$;
|
|
17
|
+
select is((select string_agg(c.oid::regclass::text,', ' order by c.oid::regclass::text) from pg_class c
|
|
18
|
+
where c.relrowsecurity and c.relkind in('r','p') and not exists(select 1 from pg_temp.xb_ar_rel r where r.rel=c.oid)),
|
|
19
|
+
null::text,'AR every row-security target is in the closure');
|
|
20
|
+
select is((select string_agg(o.oid::regclass::text,', ' order by o.oid::regclass::text) from pg_class t join pg_class o on o.relname=t.relname
|
|
21
|
+
where t.relrowsecurity and t.relkind in('r','p') and not exists(select 1 from pg_temp.xb_ar_rel r where r.rel=o.oid)),
|
|
22
|
+
null::text,'AR every relation sharing a target relname is in the closure');
|
|
23
|
+
select ok(exists(select 1 from pg_temp.xb_ar_rel where rel='realtime.subscription'::regclass)
|
|
24
|
+
and exists(select 1 from pg_temp.xb_ar_rel where rel='pg_catalog.pg_prepared_statements'::regclass),
|
|
25
|
+
'AR static subscription and prepared-statement reads are in the closure');
|
|
26
|
+
select ok(exists(select 1 from pg_temp.xb_ar_fn where fn='pg_catalog.set_config(text,text,boolean)'::regprocedure),
|
|
27
|
+
'AR the role and claims switch is a reviewed reached primitive');
|
|
28
|
+
select ok(exists(select 1 from pg_temp.xb_ar_fn where fn='agent_board.current_agent_id()'::regprocedure and origin like 'policy %'),
|
|
29
|
+
'AR row-security policies reach their helper functions');
|
|
30
|
+
select ok(exists(select 1 from pg_temp.xb_ar_fn where fn='auth.uid()'::regprocedure and origin like 'body of %'),
|
|
31
|
+
'AR parsed helper bodies reach their own callees');
|
|
32
|
+
select ok(exists(select 1 from pg_temp.xb_ar_fn where fn='realtime.check_equality_op(realtime.equality_op,regtype,text,text,boolean)'::regprocedure),
|
|
33
|
+
'AR the filter constructor reaches the admitted comparison dispatch');
|
|
34
|
+
select ok((select count(*)>=13 and bool_and(tree is not null and problem is null) from pg_temp.xb_ar_parse),
|
|
35
|
+
'AR every reached SQL body parsed into a stored tree');
|
|
36
|
+
-- The reference is exact in both directions: no reached built-in is missing
|
|
37
|
+
-- and no listed leaf is stale.
|
|
38
|
+
select is((with reached as (select pg_temp.xb_cf_fn(a.fn) identity from pg_temp.xb_ar_fn a
|
|
39
|
+
where not exists(select 1 from pg_temp.xb_cf_primitives c where c.fn=a.fn)
|
|
40
|
+
and not exists(select 1 from pg_temp.xb_cf_wrappers w where to_regprocedure(w.identity)=a.fn)
|
|
41
|
+
and not exists(select 1 from pg_temp.xb_ar_reference r where r.kind='constructor' and to_regprocedure(r.identity)=a.fn)
|
|
42
|
+
and not exists(select 1 from pg_temp.xb_ar_parse p where p.fn=a.fn)),
|
|
43
|
+
listed as (select identity from pg_temp.xb_ar_reference where kind in('primitive','aggregate'))
|
|
44
|
+
select string_agg(coalesce(r.identity,l.identity),', ' order by coalesce(r.identity,l.identity))
|
|
45
|
+
from reached r full join listed l on l.identity=r.identity where r.identity is null or l.identity is null),
|
|
46
|
+
null::text,'AR reviewed built-in leaves equal the reached built-ins exactly');
|
|
47
|
+
select is((select payload->>'prosrc_md5' from pg_temp.xb_ar_reference where kind='coverage'),
|
|
48
|
+
(select md5(prosrc) from pg_proc where oid='realtime.apply_rls(jsonb,integer)'::regprocedure),
|
|
49
|
+
'AR source coverage is bound to the actual native body');
|
|
50
|
+
select ok((select bool_and(position(payload->>'syntax' in lower(agent_board_test.stripped_body(p.oid)))>0) from pg_temp.xb_ar_reference r
|
|
51
|
+
cross join pg_proc p where r.kind='syntax' and p.oid='realtime.apply_rls(jsonb,integer)'::regprocedure),
|
|
52
|
+
'AR every grammar-form call is present in the native body');
|
|
53
|
+
select is((select count(*) from pg_temp.xb_ar_reference where kind='constructor'),2::bigint,
|
|
54
|
+
'AR both SQL constructors are pinned declarations');
|
|
55
|
+
\else
|
|
56
|
+
select plan(1);
|
|
57
|
+
select ok(to_regprocedure('realtime.apply_rls(jsonb,integer)') is null
|
|
58
|
+
and not exists(select 1 from pg_temp.xb_ar_admitted()),'AR absent native apply_rls has no admission or native credit');
|
|
59
|
+
\endif
|
|
60
|
+
select * from finish();
|
|
61
|
+
rollback;
|